MongoDB 冒烟测试套件(Smoke Test Suites)实战指南:面向迭代开发的本地快速回归方案
【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo
在 MongoDB 服务端这类大型 C++ 代码库中,改动某个组件后最担心的问题往往是"没有破坏该组件的核心功能"。本文基于 MongoDB 仓库中的冒烟测试套件文档(buildscripts/smoke_tests/README.md)编写,系统讲解 MongoDB 各团队冒烟测试套件的定位、bazel test标签体系与运行命令、Storage Execution 组件拆分方式,以及一键式 Python 脚本smoke_tests.py的完整工作流。读完本文,你将掌握如何在本地迭代开发中快速运行某个组件的核心回归测试,并在合入前用更轻量的方式替代部分补丁构建(patch build)的等待时间。
什么是冒烟测试套件
冒烟测试套件(Smoke Test Suites)是一类专为本地迭代开发设计的测试集合。按文档的定义,它们的目的是在开发过程中给开发者一个"合理的把握"——判断对某个组件的改动是否破坏了该组件的核心功能。
关键定位有三点:
- 本地运行:所有命令都在开发者自己的机器上通过 Bazel 执行,不依赖 Evergreen 等远程 CI。
- 快速反馈:相比提交合并前必须运行的完整补丁构建(patch build),冒烟测试能在本地较快给出结果。
- 不能替代补丁构建:文档明确强调,"They are not meant to replace running a patch build before merging in a change"——冒烟测试通过后,合入前仍应跑正式的补丁构建。
从仓库结构看,冒烟测试套件相关的代码集中在 buildscripts/smoke_tests/ 目录,其中包括每个团队的子目录(如replication/、server_ttl/、catalog_and_routing/)、统一的BUILD.bazel定义,以及核心入口脚本 smoke_tests.py。
测试套件的底层形态:resmoke_suite_test
每个团队子目录下的BUILD.bazel并不是手写的测试用例清单,而是通过resmoke_suite_test宏(定义于 bazel/resmoke/resmoke.bzl)声明的一个个测试目标。例如 buildscripts/smoke_tests/server_ttl/BUILD.bazel 中的no_passthrough目标:
resmoke_suite_test( name = "no_passthrough", srcs = [ "//jstests/noPassthrough/ttl:ttlMonitorSleepSecs_parameter.js", "//jstests/noPassthrough/ttl:ttl_batch_deletes.js", ... ], config = "//buildscripts/resmokeconfig:suites/no_passthrough.yml", data = [...], resmoke_args = ["--runAllFeatureFlagTests"], tags = [ "ci-development-critical-single-variant", "server-ttl", ], deps = [ "//src/mongo/db:mongod", "//src/mongo/s:mongos", "//src/mongo/shell:mongo", ], )从这些 BUILD 文件中可以看到冒烟测试的典型构成:
- srcs:选入套件的 JavaScript 测试用例(来自 jstests/ 目录),很多套件会注明这些用例的历史失败次数与 p90 运行时长(如
failed 53.0:13023 times, success p90 => 1.660s),可以推断套件倾向于挑选历史上最能暴露回归的高风险用例。 - config:对应的 resmoke 套件配置文件,位于 buildscripts/resmokeconfig/suites/。
- tags:这是冒烟测试命令的核心——每个套件都会打上一个组件专属标签(如
server-ttl、catalog-and-routing),同时通常还会打上ci-development-critical-single-variant。 - deps:测试运行所需的
mongod、mongos、mongo(shell)等可执行文件目标。
resmoke_suite_test宏在生成测试规则时还会自动追加no-cache、resources:port_block:1、resmoke_suite_test等标签,确保测试不会被错误缓存复用。
冒烟测试与 Bazel 标签:命令的通用结构
所有冒烟测试命令都基于 Bazel 的--test_tag_filters标签过滤机制,通用形态为:
bazel test --test_output=summary --test_tag_filters=<过滤器>,<组件标签> //...几个关键参数的含义:
--test_tag_filters=-intermediate_debug,<tag>:只运行打了<tag>标签且没有intermediate_debug标签的测试。-intermediate_debug用于排除中间调试构建产物相关的测试,几乎所有套件命令都带有这个过滤条件。--test_output=summary:只输出测试结果摘要,避免大量日志刷屏。//...:表示对仓库全部目标做过滤;而 Replication 套件则把范围收窄到//src/mongo/db/repl/...与//buildscripts/smoke_tests/...。
各团队的冒烟测试套件
Catalog And Routing(目录与路由)
该团队的测试标签为catalog-and-routing。运行命令:
bazel test --test_output=summary --test_tag_filters=-intermediate_debug,catalog-and-routing //...从 buildscripts/smoke_tests/catalog_and_routing/BUILD.bazel 可以看到,该套件由sharding_jscore_passthrough、sharded_collections_jscore_passthrough、replica_sets_jscore_passthrough、no_passthrough四个resmoke_suite_test目标组成,覆盖了list_collections、list_databases、list_indexes、rename_collection、move_primary、enable_sharding、shard_collection_basic等目录(catalog)与分片路由(routing)核心能力,并依赖mongod、mongos与mongoshell 构建目标。
Server Integration(服务端集成)
该团队的测试标签为server-integration-smoke。运行命令:
bazel test --test_output=summary --test_tag_filters=-intermediate_debug,server-integration-smoke //...在 buildscripts/smoke_tests/server_integration/BUILD.bazel 中有多个目标被打上server-integration-smoke标签,用于验证服务端各组件的集成行为。
Replication(复制)
Replication 的冒烟测试分为两部分:
- 集成测试,标签为
replication-smoke:
bazel test --test_tag_filters=replication-smoke //...- 单元测试,运行复制相关目录下的全部单元测试:
bazel test --test_output=summary --test_tag_filters=-intermediate_debug //src/mongo/db/repl/...- 两者合并运行(这也是推荐做法):
bazel test --test_output=summary --test_tag_filters=mongo_unittest,replication-smoke,-intermediate_debug //src/mongo/db/repl/... //buildscripts/smoke_tests/...注意合并命令中的标签过滤器是mongo_unittest,replication-smoke,-intermediate_debug——同时命中单元测试标签与冒烟测试标签。这与 smoke_tests.py 中component_name_to_test_tag映射表的定义一致("replication": "mongo_unittest,replication-smoke"),并且脚本在运行 Replication 套件时会把测试目标限定为//src/mongo/db/repl/...与//buildscripts/smoke_tests/...两个路径。
从 buildscripts/smoke_tests/replication/BUILD.bazel 看,Replication 冒烟套件基于replica_sets_initsync_static_jscore_passthrough配置(对应 buildscripts/resmokeconfig/suites/replica_sets_initsync_static_jscore_passthrough.yml),选入的用例集中在事务(txns)、时间序列(timeseries)、复制记录 ID(replicate_record_ids)、全文索引(fts)等与复制行为强相关的领域。
Server Programmability(服务端可编程性)
该团队的测试标签为server-programmability。运行命令:
bazel test --test_output=summary --test_tag_filters=-intermediate_debug,server-programmability //...在 buildscripts/smoke_tests/server_programmability/BUILD.bazel 中,core、failpoints、no_passthrough三个目标共享该标签,覆盖 failpoint(故障注入点)、服务器参数、启动/关闭路径、BSON 处理、中断(interruption)等可编程性核心区域。其中还留有一条注释说明:pin_code_segments_on_startup.js因依赖宿主机 ulimit 配置、结果不稳定而未包含在套件中,体现了冒烟套件"稳定优先"的选择原则。
Storage Execution(存储执行)
Storage Execution 团队将冒烟测试按组件拆分,每个组件拥有独立的测试标签。运行全部组件:
bazel test --test_output=summary --test_tag_filters=-intermediate_debug,server-bsoncolumn,server-collection-write-path,server-external-sorter,server-index-builds,server-key-string,server-storage-engine-integration,server-timeseries-bucket-catalog,server-tracking-allocators,server-ttl //...各组件及其运行方式如下(均使用bazel test --test_output=summary --test_tag_filters=-intermediate_debug,<组件标签> //...):
| 组件 | 测试标签 | 是否含集成测试 |
|---|---|---|
| Server-BSONColumn | server-bsoncolumn | 否(目前仅单元测试) |
| Server-Collection-Write-Path | server-collection-write-path | 是 |
| Server-External-Sorter | server-external-sorter | 否(目前仅单元测试) |
| Server-Index-Builds | server-index-builds | 是 |
| Server-Key-String | server-key-string | 否(目前仅单元测试) |
| Server-Storage-Engine-Integration | server-storage-engine-integration | 是 |
| Server-Timeseries-Bucket-Catalog | server-timeseries-bucket-catalog | 否(目前仅单元测试) |
| Server-Tracking-Allocators | server-tracking-allocators | 否(目前仅单元测试) |
| Server-TTL | server-ttl | 是 |
其中server-ttl组件在 buildscripts/smoke_tests/server_ttl/BUILD.bazel 中对应no_passthrough目标,选入了ttlMonitorSleepSecs_parameter.js、ttl_batch_deletes.js、ttl_with_restart.js、user_write_blocking_ttl_index.js等 TTL 索引行为用例。在 smoke_tests.py 中,Storage Execution 全套组件的标签被汇总为一行test_tag,与 README 中"全部组件一起跑"的命令完全一致。
Streams(Atlas Stream Processing)
Streams 组件比较特殊:它要求启用 streams release 构建配置。运行命令:
bazel test --test_output=summary --test_tag_filters=-intermediate_debug,streams-smoke --streams_release_build=True //...其中的--streams_release_build=True是 Bazel 构建标志。在 bazel/config/BUILD.bazel 中定义了streams_release_build构建设置及其 enabled/disabled 两个取值(对应 bazel/config/configs.bzl 中的streams_release_build规则),Streams 冒烟测试目标还通过target_compatible_with = select(...)在禁用该配置的平台声明为不兼容,确保测试只在正确的构建模式下运行。
buildscripts/smoke_tests/streams/BUILD.bazel 中的streams目标是一个shard_count = 3的大型套件,选入了几十个来自//src/mongo/db/modules/enterprise/jstests/streams/的用例(如infinite_loop.js、parse_only.js、documents.js、dlq.js、checkpoint_backwards_compat.js等),覆盖流处理管道的合并、窗口、死信队列与检查点等核心能力。
一键式入口:smoke_tests.py 脚本
除了直接使用bazel test命令,仓库还提供了更完整的入口脚本 buildscripts/smoke_tests/smoke_tests.py。它的文档注释明确了设计目的:在提交 Evergreen 补丁之前本地运行,依次保证以下内容通过:
- clang format(代码格式化)
- clang tidy(静态检查)
- 构建
install-dist-test(安装/发行版测试目标) - 对应组件/团队的单元测试
- 对应组件/团队的冒烟测试
运行方式与组件名映射
python buildscripts/smoke_tests/smoke_tests.py <component>component的可用值由脚本中的component_name_to_formal_name/component_name_to_test_tag映射表给出,包括:catalog-and-routing、server-integration、replication、server-bsoncolumn、server-collection-write-path、server-external-sorter、server-index-builds、server-storage-engine-integration、server-timeseries-bucket-catalog、server-tracking-allocator、server-ttl等,此外还可能包含所检出模块(modules)在buildscripts/modules/*/smoke_tests/smoke_tests_metadata.json中声明的额外组件。
脚本开头的ensure_python3_venv()会强制切换到仓库自带的 Python 虚拟环境(python3-venv),随后才导入buildscripts.resmokelib.utils.evergreen_conn等模块,保证运行环境一致。
命令行参数
| 参数 | 默认值 | 说明 |
|---|---|---|
component(位置参数) | 无 | 要运行冒烟测试的组件名 |
--log-path | ~/.logs/smoke_tests | 各阶段日志存放目录,脚本会按仓库路径哈希追加唯一子目录 |
--run-clang-tidy | False | 是否运行 clang tidy;耗时较长,且会把构建配置切换为config=clang-tidy |
--send-slack-notification | 1 | 结束后是否向本地 Evergreen 配置中登录的用户发送 Slack 通知 |
--schedule-patch | None | 成功后自动提交 Evergreen 补丁(使用requiredalias);不带值时使用mongodb-mongo-master,也可指定如--schedule-patch=mongodb-mongo-v8.0 |
位置参数之后的所有参数会被parse_known_args捕获并作为bazel_args原样透传给后续的 bazel 构建/测试命令——这就是 README 中 Streams 示例的写法:
python buildscripts/smoke_tests/smoke_tests.py streams --//bazel/config:streams_release_build=True这里--//bazel/config:streams_release_build=True是 Bazel 风格的构建标志透传(即bazel test --//bazel/config:streams_release_build=True),作用与前面--streams_release_build=True等价。
内部执行流水线
脚本内部用一个依赖图(CommandRunner+Node)把各阶段组织成有依赖关系的并行任务,并可用parallelism(默认取os.cpu_count())控制并发。默认流水线如下:
- 质量检查(quality checks):
bazel run checks -- --fix --group format --group lint,执行 clang format 与 lint 修复。 - 构建可执行文件:
bazel build <透传参数> //:install-dist-test,依赖第 1 步完成。 - 组件测试:
bazel test <透传参数> --test_tag_filters=<组件标签>,-intermediate_debug --test_output=summary --dev_stacktrace=False <目标路径>,依赖第 2 步(注释说明这并非真正的依赖关系,而是为了串行化 bazel 访问,避免并发冲突)。 - clang tidy(仅当
--run-clang-tidy=True):bazel build --config=clang-tidy --verbose_failures --keep_going //src/mongo/...,同样用于串行化 bazel 访问,并防止 clang-tidy 在测试结束前改掉构建配置。
任一步骤失败(返回码非 0)会立即中止并抛出异常。全部通过后,如果指定了--schedule-patch,脚本会临时git add -A暂存所有改动(含未跟踪文件),以--uncommitted方式提交 Evergreen 补丁,随后恢复原来的 git 暂存状态;如果--send-slack-notification开启,则通过 Evergreen API 向本地配置的用户发送结果摘要(含各阶段耗时、失败命令与日志路径)。
结语
MongoDB 的冒烟测试体系是一个典型的"标签驱动 + 宏生成 + 脚本编排"三层结构:resmoke_suite_test宏负责把精选的高风险 jstest 用例编译成可被标签过滤的 Bazel 测试目标;开发者用一行bazel test --test_tag_filters=...命令按组件快速回归;需要完整流程时再交给smoke_tests.py自动完成格式化、构建、测试与可选补丁提交。对于日常迭代,建议记住两条核心命令模式:通用组件用bazel test --test_output=summary --test_tag_filters=-intermediate_debug,<组件标签> //...,Replication 用合并命令同时覆盖单元测试与冒烟测试;无论哪种方式,合入前都别忘了仍要跑正式的 Evergreen 补丁构建来兜底。
【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考