尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MongoDB 测试指南:使用 resmoke 测试编排器运行与配置集成测试

MongoDB 测试指南:使用 resmoke 测试编排器运行与配置集成测试 MongoDB 测试指南使用 resmoke 测试编排器运行与配置集成测试【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongoresmoke 是 MongoDB 仓库内置的测试运行器与编排工具几乎所有 MongoDB 测试尤其是jstests/下的 JavaScript 集成测试都经由它调度执行。本文以 docs/testing/README.md 为主线结合仓库内的 suites、fixtures、hooks、testcases 等配套文档与源码实现系统讲解 resmoke 的四大核心概念suites、fixtures、hooks、testcases、从零跑通一个测试的完整流程以及如何读懂并编写自定义测试套件配置。读完本文你将能够独立使用 resmoke 运行指定测试文件、解释 suite YAML 的每个字段含义并知道如何按需组合拓扑fixture与测试前后逻辑hook。1. resmoke 是什么resmoke 是 MongoDB 的集成测试运行器integration test runner其入口文件位于仓库根目录下的 buildscripts/resmoke.py。该脚本本身只是一个薄壳主要作用是修正PYTHONPATH后调用buildscripts.resmokelib.cli模块对应 buildscripts/resmokelib/cli.py的main()函数再由parser.parse_command_line()解析子命令并执行。resmoke 负责的工作远不止“执行一条命令”这么简单它实际上是一个测试编排器orchestrator需要协调按 suite 配置挑选select要运行的测试文件按 fixture 配置拉起对应的服务器拓扑如独立 mongod、副本集、分片集群按 hooks 配置在测试前后执行数据校验、清理等附加逻辑汇总测试结果、在失败时归档数据文件archive供事后分析。值得注意的是尽管 MongoDB 源码本身使用 Bazel 构建但 resmoke尚未与 Bazel 集成因此运行测试前需要先用bazel build产出可执行二进制详见 buildscripts/resmokelib/README.md 的 Build 一节。2. 四大核心概念原文档明确将 resmoke 的知识体系拆成四个独立概念每个都有自己专门的文档。它们是理解 resmoke 的钥匙suites套件决定“跑哪些测试、怎么跑”本质是 YAML 配置文件。详见 buildscripts/resmokeconfig/suites/README.mdfixtures夹具指定测试所针对的服务器拓扑独立节点、副本集、分片集群等。详见 buildscripts/resmokelib/testing/fixtures/README.mdhooks钩子在单个测试之前、之后以及整个 suite 前后运行的逻辑如校验数据一致性、周期性清理。详见 buildscripts/resmokelib/testing/hooks/README.mdtestcases测试用例类型resmoke 可以运行的不同“种类”的测试本质是 Pythonunittest.TestCase的扩展。详见 buildscripts/resmokelib/testing/testcases/README.md。下面分别展开。2.1 Suites测试如何被分组与配置Suite 是一份 YAML 文件文件名即 suite 名其作用是把“要跑的测试文件、fixture 及其参数、shell 选项、hooks、归档策略”打包成一个可复用的配置单元。所有 suite 配置位于 buildscripts/resmokeconfig/suites/ 目录约 940 个 YAML 文件。一个最精简的 suite 只需要三部分test_kind: js_test selector: roots: - jstests/mytests/**/*.js executor: config: shell_options: nodb: 含义是suite 名即文件名my_suite包含jstests/mytests目录下所有 JS 文件这些测试在一个传入nodb: 选项的 shell 中运行。下面用一个带占位符的完整结构示例展示 suite 的整体骨架摘自 buildscripts/resmokeconfig/suites/README.mdtest_kind: js_test selector: roots: - jstests/mytests/**/*.js executor: config: shell_options: nodb: global_vars: TestData: defaultReadConcernLevel: null hooks: - class: ValidateCollections - class: CleanEveryN n: 20 fixture: class: ShardedClusterFixture num_shards: 2 archive: tests: true hooks: - ValidateCollections2.1.1test_kind声明该 suite 中测试的种类常见值如js_test、cpp_unit_test、py_test、fsm_workload_test等。全部受支持的类型见 buildscripts/resmokelib/testing/testcases/README.md。其中js_test覆盖了大约75% 的 suite是绝对主力。2.1.2selector选择测试文件selector 决定 suite 包含/排除哪些测试文件主要字段roots要包含的测试文件路径列表支持 glob。如果提供的是不带 glob 的路径则该文件必须真实存在root一个文件通常为build/unittests.txt内部每行一个 glob 模式常用于cpp_unit_test类型指定候选测试include_filesglob 列表只保留这部分测试即使这些文件被 tag 排除了也会被强制包含若指定了 roots 中不存在的测试会报错exclude_filesglob 列表排除这些测试即使 tag 允许也会被排除若指定的测试不在 roots 中会报错include_with_any_tags只保留定义了任一这些 tag 的 jstestexclude_with_any_tags排除定义了任一这些 tag 的 jstest除非文件名层面被强制包含。示例如下selector: roots: - jstests/aggregation/**/*.js exclude_files: - jstests/aggregation/extras/*.js - jstests/aggregation/data/*.js exclude_with_any_tags: - requires_pipeline_optimization想查看仓库中所有被引用的 tag 及其说明可运行./buildscripts/resmoke.py list-tags。2.1.3executor定义如何执行executor下分四块config、hooks、fixture、archive。executor.config提供每个测试的附加配置结构随test_kind变化具体以 buildscripts/resmokelib/testing/testcases/ 下对应实现为准。对最常见的js_test而言核心是shell_optionsconfig: shell_options: global_vars: TestData: defaultReadConcernLevel: null nodb: gssapiServiceName: mockservice eval: - var testingReplication true; load(jstests/libs/override_methods/set_read_and_write_concerns.js); load(jstests/libs/override_methods/enable_causal_consistency_without_read_pref.js);shell_options中除global_vars外的参数会原样传给 mongo shell 可执行文件标志型参数需要写成空值如nodb: global_vars作为传给--eval的字符串基础会做对象格式化eval字段指定的 JS 会追加在其后TestData是一个特殊的全局变量用于承载测试数据。它的取值合并优先级为resmoke 命令行 suite.yml 运行时/默认值eval可以直接写 JS 代码也可以把 JS 放进独立脚本后用load(...)加载。executor.hooks声明要在测试前后运行的钩子。yml 中的class必须与 hook 的 Python 类名一致其余字段作为参数传入构造函数hook_logger与fixture由 resmoke 自动注入不要写在 yml 里。示例hooks: - class: CheckReplOplogs - class: CheckReplDBHash - class: ValidateCollections - class: CleanEveryN n: 20 - class: MyHook param1: something param2: somethingelseexecutor.fixture指定测试所运行的拓扑。class对应 fixture 的 Python 类名其余字段传给构造函数fixture: class: ShardedClusterFixture num_shards: 2 mongos_options: bind_ip_all: set_parameters: enableTestCommands: 1 mongod_options: bind_ip_all: set_parameters: enableTestCommands: 1 periodicNoopIntervalSecs: 1 writePeriodicNoops: trueexecutor.archive配置失败时的数据归档上传到 S3。当某个 hook 或 test 抛异常即视为失败触发归档的时机有二归档列表中的任意 hook 抛异常或tests: true时 suite 中任意 test 抛异常。示例archive: hooks: - Hook1 - Hook2 tests: truearchive.hooks是 hook 类名列表设为true表示归档所有 hookarchive.tests是测试文件列表支持通配true表示归档所有测试。关于失败归档的更多机制可阅读 buildscripts/resmokeconfig/suites/README.md 与 buildscripts/resmokelib/testing/testcases/README.md 中对FixtureAbortTestCase的说明。2.2 Fixtures测试针对的服务器拓扑Fixture 定义测试所针对的具体拓扑在 suite 的fixture字段中声明。仓库支持的 fixture 包括均位于 buildscripts/resmokelib/testing/fixtures/MongoDFixturestandalone.py提供独立 mongodReplicaSetFixturereplicaset.py副本集ShardedClusterFixtureshardedcluster.py分片集群同时承担“由 JS 测试自身通过MongoRunner、ReplSetTest、ShardingTest启动部署”的场景MultiReplicaSetFixturemulti_replica_set.py、MultiShardedClusterFixturemulti_sharded_cluster.py多组副本集/分片集群BulkWriteFixturebulk_write.py向 JSTest 提供一组集群ExternalFixtureexternal.py与ExternalShardedClusterFixture连接外部非 resmoke 管理的集群MongoTFixturemongot.pymongod 旁边再拉起一个 mongotYesFixtureyesfixture.py生成大量日志消息的辅助 fixture。fixture 侧还有一组接口类interface.pyFixture是所有 fixture 的基类MultiClusterFixture是可由多个独立集群组成的基类参与者集群平时独立运行仅在参与迁移等过程时被绑定NoOpFixture不启动任何服务器ReplFixture是所有支持复制的 fixture 的基类。2.3 Hooks测试边界上的运行逻辑Hook 是在测试内容边界before/after test、before/after suite上运行的例程。suite 的hooks字段中可声明任意组合。仓库支持的 hooks 数量很多按用途可粗略分为几类详见 buildscripts/resmokelib/testing/hooks/README.md数据一致性校验如CheckReplDBHashdbhash.py对比主从 dbhashCheckReplOplogsoplog.py检查local.oplog.rs在主备上一致CheckReplPreImagesConsistency检查config.system.preimagesValidateCollectionsvalidate.py做完整校验CheckOrphansDeletedorphans.py检查孤儿文档是否删除干净后台扰动/故障注入ContinuousStepdownstepdown.py周期性发送replSetStepDownPeriodicKillSecondariesperiodic_kill_secondaries.py周期性杀掉副本集 secondaryLagOplogApplicationInBackgroundsecondary_lag.py制造 secondary 回放延迟FuzzRuntimeParametersfuzz_runtime_parameters.py周期性下发随机setParameterHelloDelayshello_failures.py注入 Hello 故障初始同步相关BackgroundInitialSync/IntermediateInitialSyncinitialsync.py使用前提是 ReplicaSetFixture 以start_initial_sync_nodeTrue启动且与CleanEveryN共用时n要一致清理与重启CleanEveryNcleanup.py每跑n个测试重启 fixtureDropUserCollections、CleanupConcurrencyWorkloadscleanup_concurrency_workloads.py变更流/后台任务RunChangeStreamsInBackgroundchange_streams.py在后台跑全集群 change streamRunDBCheckInBackgrounddbcheck_background.py后台跑dbCheckRunQueryStatsrun_query_stats.py每个测试后运行$queryStats崩溃模拟与归档SimulateCrashsimulate_crash.pyMagicRestoreEveryNmagic_restore.py依赖MagicRestoreFixture。所有 hooks 都继承自buildscripts.resmokelib.testing.hooks.interface.Hookinterface.py并可覆写以下空方法中的任意子集before_suitebefore_testafter_testafter_suite至少要覆写其中一个方法否则 hook 什么都不做。常见的自定义工作包括校验数据、删除数据、执行清理等。此外还有三个接口层JSHookjsfile.py是携带静态 JS 文件的 hook 接口DataConsistencyHook是其上用于数据一致性检查的封装shell 以非零码退出时抛errors.ServerFailure终止测试BGHookbghook.py会在后台线程中反复调用run_action()贯穿整个 suite 生命周期PerClusterDataConsistencyHook则在 fixture 的每个独立集群上运行。2.4 Testcases测试的“种类”TestCases 是 Pythonunittest.TestCase的扩展resmoke 以不同“种类”test_kind运行它们。完整清单见 buildscripts/resmokelib/testing/testcases/README.md此处列举代表性类型js_testjstest.pyJS 集成测试约 75% 的 suite 使用具体编写规范见 jstests/README.mdall_versions_js_testjs_test的别名用于多版本multiversion透传 suite会以副本集/分片集群的所有版本组合运行cpp_unit_testcpp_unittest.pyC 单元测试cpp_integration_test、cpp_libfuzzer_test对应 C 集成与 libfuzzer 测试fsm_workload_test/parallel_fsm_workload_testfsm_workload_test.py并发FSM工作负载测试py_testpytest.pyPython 测试benchmark_test、json_schema_test、sdam_json_test、server_selection_json_test、sleep_test、tla_plus_test等各司其职。接口层面顶层有TestCase必须实现run_test与ProcessTestCase执行外部进程必须实现_make_process均在 interface.py子类包括JSRunnerFileTestCasejsrunnerfile.py与MultiClientsTestCase多个单用例副本的封装以及TestCaseFactory工厂。一个值得注意的机制是Fixture TestCasesresmoke 内部通过FixtureTestCaseManager用测试用例来协调 fixture 生命周期——suite 会先跑一个FixtureSetupTestCase建好拓扑再跑你的 N 个测试最后跑FixtureTeardownTestCase拆除。因此一次运行中你会看到N2个“测试”通过多出的两个正是 fixture 的 setup 与 teardown。另外当测试失败且配置了归档时resmoke 会动态生成一个FixtureAbortTestCase立即执行向每个 mongod 发送SIGABRT以便在归档前捕获崩溃现场。3. 动手实践从零跑通一个测试3.1 准备 Python 虚拟环境先确保 venv 已激活且依赖最新python3 -m venv python3-venv source python3-venv/bin/activate buildscripts/uv_sync.shuv_sync.sh是仓库提供的依赖同步脚本位于 buildscripts/uv_sync.sh它会按仓库锁定的版本安装 Python 依赖。如果直接运行buildscripts/resmoke.py而 venv 未激活且不在 Bazel workspace 环境下buildscripts/resmoke.py 会提示 You need to activate your virtual environment。3.2 构建被测二进制由于 resmoke 尚未与 Bazel 集成需要先用 Bazel 构建可测试的安装产物bazel build install-dist-test3.3 运行单个测试文件以原文档中的示例为例从单个测试文件运行测试内容buildscripts/resmoke.py run --suitesno_passthrough jstests/noPassthrough/shell/js/string.js这条命令做了这些事通过run子命令resmoke 最常用的功能执行测试--suitesno_passthrough指定使用 buildscripts/resmokeconfig/suites/no_passthrough.yml 中的 suite 配置命令行给出的 JS 文件 jstests/noPassthrough/shell/js/string.js 必须落在该 suite 的roots通配范围内。no_passthroughsuite 的特点是“passthrough”指用不同的运行时集群配置拓扑、运行时参数、故障注入等来跑同一测试大多数测试都能在 passthrough suite 中运行而 noPassthrough 是例外——这些测试只在测试自身预定义的精确配置下运行见 buildscripts/resmokeconfig/suites/no_passthrough.yml 的description。它的selector.roots通过 glob 覆盖了jstests/noPassthrough/**/*.js、jstests/concurrency/*.js等目录exclude_files排除了jstests/noPassthrough/libs/**/*.js这类库文件并通过exclude_with_any_tags排除requires_kernel_619、requires_kernel_7014等需要特定内核的测试。它的 executor 配置非常精简——原文档明确指出不指定 fixture、不指定 hooksexecutor 只带一份最小配置nodb: 让 shell 以不连接数据库的模式启动并关闭测试扩展签名校验的 server parameter。这正说明这些 noPassthrough 测试由 JS 代码自己启动 mongodMongoRunner等suite 层无需再管理拓扑。被执行的 jstests/noPassthrough/shell/js/string.js 是一个用 mochalite 编写的 String shim/polyfill 测试包含trim、trimLeft、trimRight、ltrim、rtrim、startsWith、endsWith、includes、pad等用例——非常适合作为入门跑通流程的最小样例。3.4 run 子命令与常用参数run子命令有100 个 flag。resmoke 刻意不在文档中重复罗列全部参数以免多源信息漂移过期统一以buildscripts/resmoke.py run --help为准。以下是高使用频率参数的说明源自 buildscripts/resmokelib/README.md--suites/--suiterun既可以运行 suite一组测试 对应的拓扑与配置也可以运行显式指定的测试文件。单套件用--suite多套件用逗号分隔传给--suites。--installDirresmoke 可以针对任意“可测试安装”ASAN、Debug、Release 等运行测试。当本地构建被安装到 git 仓库根目录的子目录、且仓库内恰好只有一份构建时resmoke 能自动定位并使用本地构建其他情况则用--installDir显式指定 mongod/mongos 二进制所在目录。替代方案是直接使用与 mongod 二进制同目录下的resmoke.py包装脚本它会自动替你设置installDir。注意该包装脚本在打包安装如 Homebrew 等包管理器提供的发行版中不存在此时必须显式传--installDir。其他子命令摘录自resmoke --helplist-suites列出可执行的 suite 名find-suites列出会执行指定测试的 suitegenerate-matrix-suites从映射文件生成 matrix suite 配置list-tags列出 suites 中可用的 tag 及说明generate-multiversion-exclude-tags基于当前分支与 last-lts/last-continuous 分支上BACKPORTS_REQUIRED_FILE的对比生成多版本测试的排除 tag 文件test-discovery发现 suite 会运行哪些测试suiteconfig显示 suite 的配置core-analyzer分析指定输入文件的 core dumphang-analyzerEvergreen 集成的原型挂起分析器支持抓取 dump 与进程信息摘要powercycle断电循环测试脚本generate-fuzz-config用配置模糊器生成 mongod.conf 与 mongos.confgenerate-fcv-constants等其他内部命令。另外注意bisect、setup-multiversion、symbolize三个子命令已迁移到db-contrib-tool工具不再由 resmoke 提供。4. 深入原理resmoke 的命令行入口与参数校验从源码看resmoke 的入口链路是buildscripts/resmoke.py 修正PYTHONPATH后调用cli.main(sys.argv)buildscripts/resmokelib/cli.py 的main()记录进程号到环境变量RESMOKE_PARENT_PROCESS、RESMOKE_PARENT_CTIME供子进程识别父进程若由bazel run调用则切到 workspace 根目录随后交给parser.parse_command_line()解析并执行对应子命令参数解析与校验位于buildscripts/resmokelib/parser模块与 buildscripts/resmokelib/configure_resmoke.py 的_validate_options()中。其中可以看到若干对用户友好的校验逻辑例如--executor已被--suites取代若使用会直接报错并提示改用--suites{} {}命令行测试文件列表与--replayFile不能同时使用--shellSeed必须配合且仅配合一个测试文件使用指定的测试文件若不存在且不以开头表示 replay 文件会报 Test file ... does not exist。5. 遥测resmoke 的 OpenTelemetry 埋点resmoke 使用 OpenTelemetryOTel采集自身运行的指标用于 Evergreen CI 场景下的性能优化。每次 resmoke 调用都会采集但只有运行在 Evergreen 时数据才会上报到 Honeycomb详见 docs/testing/otel_resmoke.md。采集内容包括一个 resmoke suite一组 JS 测试的运行时长suite 内每个测试单个 JS 测试的运行时长测试/suite 前后 hooks 的耗时resmoke 归档器失败时归档 core dump的相关数据。实现上大部分配置集中在_set_up_tracing(...)方法buildscripts/resmokelib/configure_resmoke.py并配套了BatchedBaggageSpanProcessorbuildscripts/resmokelib/utils/batched_baggage_span_processor.py与FileSpanExporterbuildscripts/resmokelib/utils/file_span_exporter.py两个自定义组件。数据采集以装饰器为主例如取自 buildscripts/resmokelib/testing/job.pyTRACER trace.get_tracer(resmoke) TRACER.start_as_current_span(func_name) def func_name(...): span trace.get_current_span() span.set_attribute(attr1, True)装饰器方式可以自动捕获异常、保证 span 一定被关闭个别场景也会用with块手动开 span但装饰器是首选方案。6. 相关文档导航测试运行器总览buildscripts/resmokelib/README.mdSuite 配置详解buildscripts/resmokeconfig/suites/README.mdFixture 与拓扑buildscripts/resmokelib/testing/fixtures/README.mdHook 机制buildscripts/resmokelib/testing/hooks/README.mdTestCase 种类buildscripts/resmokelib/testing/testcases/README.mdJS 测试编写规范jstests/README.mdresmoke 遥测docs/testing/otel_resmoke.md并发测试框架docs/testing/fsm_concurrency_testing_framework.md挂起分析docs/testing/hang_analyzer.md【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表