OpenSRE 测试体系指南:目录规范、快速命令与端到端命名约定
【免费下载链接】opensreBuild your own AI SRE agents. The open source toolkit for the AI era.项目地址: https://gitcode.com/GitHub_Trending/op/opensre
本文以仓库 tests/README.md 为核心骨架,结合 Makefile、pytest 配置与测试源码,系统讲解 OpenSRE 开源项目(Build your own AI SRE agents)的测试组织方式。你将掌握三套开箱即用的测试命令(覆盖、集成校验、全量回归)、
tests/目录的分层约定、tests/e2e/与遥测的命名规则,以及如何快速定位某个领域(cli、tools、integrations、core等)对应的测试代码。
快速上手:三条核心命令
原文档给出了三组最常用的命令,它们分别对应「本地首跑」「集成改动后」「CI 回归」三种场景。
| 目标 | 命令 | 何时使用 |
|---|---|---|
| 运行默认单元测试套件并带覆盖率 | make test-cov | 本地第一件事;无需任何真实基础设施 |
| 校验所有集成配置与客户端 | make verify-integrations | 新增或修改集成之后 |
运行默认 pytest 全量收集(tests/e2e被 pytest 配置排除) | make test-full | 本地或 CI 的宽泛回归 |
make test-cov:并行覆盖率跑分
在 Makefile 中,test-cov的实现是:
test-cov: $(PYTHON) -m pytest -n auto -v $(addprefix --cov=,$(PYTHON_SOURCE_PATHS)) --cov-report=term-missing其中PYTHON_SOURCE_PATHS := bootstrap config core gateway integrations infrastructure surfaces tools(Makefile),即覆盖统计只针对这些产品源码目录,不把测试自身算进分母。-n auto借助 pytest-xdist 按 CPU 核数并行,--cov-report=term-missing会在终端列出未覆盖行号,方便逐行补测。
PYTHON变量的解析顺序(Makefile)值得注意:优先使用.venv/bin/python,其次.venv/Scripts/python.exe(Windows),最后回退到python3/python,保证在没有虚拟环境时命令依然可用。
make verify-integrations:集成配置与连通性校验
verify-integrations: uv run opensre integrations verify $(if $(SERVICE),$(SERVICE),) $(if $(SLACK_TEST),--send-slack-test,)该命令实际调用 CLI 的opensre integrations verify(可传SERVICE限定单个集成,传SLACK_TEST=1触发 Slack 测试消息)。它对应 integrations/verify.py 等实现,会读取本地 store 与.env中的凭据逐项验证连通性。仓库还提供了更轻量的冒烟变体:
verify-integrations-smoke: $(PYTHON) -m pytest -q \ tests/integrations/test_verification_registry.py \ tests/integrations/test_registry.py它只跑注册表/目录的契约测试,作为 CI 冒烟闸门,不触碰真实服务。
make test-full:全量回归
test-full: $(PYTHON) -m pytest -vpytest 的testpaths(pytest.ini)为tests、gateway/tests和core/agent_harness/prompts/skills三处;其中norecursedirs = tests/e2e .git ...(pytest.ini)明确把tests/e2e排除出默认收集,这正是原文档标注「tests/e2eexcluded by pytest configuration」的出处——端到端用例需要显式 opt-in,避免本地/CI 因缺少真实服务凭据而失败。
pytest.ini中还有几项对理解全量回归至关重要的全局配置:
- import 模式:
--import-mode=importlib,解决两个测试文件同名(如test_enums)导致的 "import file mismatch"; - 插件加载:
-p tests.harness_providers_plugin -p tests.colocated_skill_tests_plugin,前者为每个测试树装配工具/集成端口,后者保证位于core/agent_harness/prompts/skills下的技能测试不被重复执行; - 超时兜底:
timeout = 600(pytest.ini),把可能挂死的测试从「烧光整个 30 分钟 CI 任务」降级为「快速失败并输出全线程栈」,便于诊断死锁; - 标记定义:
integration(可能发 API 调用)、live_llm(需要真实 LLM 凭据与网络)、e2e(需要真实基础设施或外部凭据,离线 CI 中跳过)、live_install(命中真实安装源,opt-in 或 e2e 路径使用),见 pytest.ini。
目录布局:测试必须按领域归置
原文档的核心约定是:测试要放在领域目录下,而不是散落在tests/根目录。
| 路径 | 覆盖内容 |
|---|---|
tests/<domain>/ | 产品模块的单元与集成测试(cli/、tools/、integrations/、core/、infrastructure/等) |
tests/e2e/ | 针对真实服务与基础设施的真实端到端场景,设计原则见 e2e/AGENTS.md |
tests/github_ci/ | 仓库卫生守卫(命名、导入边界、架构引用) |
tests/conftest.py | 整棵测试树共享的 pytest fixtures |
实际目录(tests/)与之一一对应:除conftest.py、两个插件文件和ci_sharding.py外,analytics/、benchmarks/、bootstrap/、config/、core/、filestorage/、infrastructure/、integrations/、interactive_shell/、scheduler/、tools/等均为领域目录,与源码顶层结构bootstrap/、config/、core/、integrations/、infrastructure/、surfaces/一一镜像,方便「源码改动 → 就近找到测试」。
tests/github_ci/:仓库卫生守卫
这组测试守卫的是「仓库本身的健康」而非业务功能。以 tests/github_ci/test_naming_conventions.py 为例,它扫描README.md、pyproject.toml、Makefile、tests/README.md、.github/workflows/*.yml以及tests/e2e/下的所有.py文件,断言其中不再出现tests/test_case_、test_case=test_case_、test_orchestrator三个遗留 token——这是原文档「Legacy names」一节的落地守卫。同目录还包含 test_ci_sharding.py、test_external_code_boundaries.py、test_pr_pipeline_slo.py、test_pre_push_gate.py 等,分别守护分片、外部代码边界、PR 流水线 SLO 与 pre-push 闸门。
tests/conftest.py:整棵树共享的安全网
tests/conftest.py 的价值远超「加载 .env」:它通过若干 autouse fixture 把每个测试与开发者真实环境隔离开来:
_load_env读取项目根.env(override=True),并统一关闭 Sentry(OPENSRE_SENTRY_DISABLED=1)与遥测(OPENSRE_NO_TELEMETRY=1),标记OPENSRE_INVESTIGATION_SOURCE=test;_restore_os_environ在每个测试后整体快照恢复os.environ——因为sync_provider_env等代码会os.environ.pop/update其他 provider 的 API key,泄漏会污染同 worker 上后续的live_llm测试;_isolate_opensre_home_files把 wizard store(opensre.json)、LLM 认证元数据(llm-auth.json)、本地凭据与 memory 目录全部重定向到tmp_path,防止测试悄悄写坏开发者真实的~/.opensre(注释中记录了 #3721 回归案例);_isolate_session_trace_store恢复进程级 session trace store,避免 xdist 下trace_spansidecar 泄漏进被断言的会话文件;pytest_sessionfinish在「什么都没收集到」时强制返回NO_TESTS_COLLECTED,堵住 xdist 在-m把所有用例过滤掉时仍以 0 退出的漏洞。
E2E 目录与文件命名规则
原文档对端到端测试的命名有两条硬性规则:
- 目录格式:
tests/e2e/<scenario_name>/,其中<scenario_name>描述「系统 + 工作负载」,例如install、quickstart。 - 环境特定文件用显式文件名:
test_local.py:本地环境;test_<cloud>.py:云环境。
当前仓库的 tests/e2e/ 完全遵循这一约定,场景覆盖:deploy/(Docker 镜像构建与健康端点)、grafana_validation/(Grafana Cloud 查询)、incident_io/、install/(真实安装器)、posthog/、quickstart/、tempo/、trello/。环境维度的例子如 install/test_live_installers.py 与 install/test_live_installers_windows.py——前者用sys.platform == "win32"条件跳过(POSIX 安装器走install.sh,Windows 走install.ps1),后者单独覆盖 Windows 宿主。
e2e 场景的三个设计原则
e2e/AGENTS.md 明确了tests/e2e/的指导原则,可视为对命名规则的语义补充:
- 真实端到端,零 mock:必须打真实服务与真实基础设施(live installers、Grafana Cloud、PostHog、incident.io、Docker 构建),因为 mock 验证的是「人工载荷下的 agent」而非生产实际产生的东西;
- 关注点分离,业务逻辑纯净:测试驱动的工作负载代码必须与测试编排/可观测代码隔离,看起来像真实客户代码;
- 前置声明环境,缺凭据就响亮跳过:真实套件在开头声明所需凭据(参见 grafana_validation/env_requirements.py),缺失时带明确原因
pytest.skip,让无密钥的 CI 保持绿色又不掩盖有密钥运行中的失败。
env_requirements.py展示了「门控 + 响亮跳过」的落地方式:require_grafana_cloud_env()收集GCLOUD_OTLP_ENDPOINT、GCLOUD_OTLP_AUTH_HEADER、GCLOUD_HOSTED_METRICS_ID/URL、GCLOUD_HOSTED_LOGS_ID/URL、GCLOUD_RW_API_KEY等 7 项,缺任一即以pytest.skip("Grafana Cloud telemetry not configured; missing env vars: ...")跳过;require_grafana_query_env()则按账号 id 归一化出GRAFANA_READ_TOKEN/GRAFANA_INSTANCE_URL(默认账号tracerbio)并逐项校验。
deploy/conftest.py是「环境门控」的另一个典型:RUN_DEPLOY_DOCKER_TESTS=1未设置或 Docker 不可用时直接 skip,启用后构建一个带随机 tag 的镜像,并在会话结束用docker image rm -f清理。
遥测命名规则:语义化 resource attributes
原文档规定:OTEL_RESOURCE_ATTRIBUTES的值必须使用语义目录名,禁止继续使用遗留的test_case_*值;e2e 场景统一使用test_case=e2e_<scenario_name>。
这条规则与命名守卫互相印证:tests/github_ci/test_naming_conventions.py 中的LEGACY_TOKENS = ("tests/test_case_", "test_case=test_case_", "test_orchestrator"),一旦在 README、pyproject、Makefile、工作流或 e2e 测试源码中出现即判定违规。也就是说,遥测命名不是「建议」,而是有 CI 测试强制的契约——新写的 e2e 场景必须形如test_case=e2e_install、test_case=e2e_quickstart,确保遥测面板上能按场景聚合出稳定的维度。
遗留命名与迁移
原文档明确指出:tests/下遗留的test_case_*路径命名已废弃,只使用tests/e2e/*。迁移路径即上文所述规则:任何历史遗留的场景(例如以test_orchestrator为文件名的编排测试)都应重命名为tests/e2e/<scenario_name>/下的环境特定文件,并把遥测标签切换为test_case=e2e_<scenario_name>。守卫测试的存在意味着迁移必须一次性完成,否则make test-full或 CI 会直接报红。
进阶:CI 分片与定时快照
虽然不在原文档正文,但 tests/ci_sharding.py 是理解tests/全量回归在 CI 中如何扩展的关键补充。它提供三个子命令:
select:按耗时快照(默认.github/ci/pytest-file-durations.json)把测试文件贪心分配到 N 个 shard 中「累计耗时最小」的一组,输出该 shard 的文件清单;report:报告快照「新鲜度」(--max-age-days默认 14 天)与覆盖率(缺失文件占比--max-missing-percent默认 5%),超限时输出::warning供 CI 可视化;merge:把各 worker 产出的定时片段(--ci-durations-output,见pytest_addoption)合并回总快照。
其核心算法assign_file_groups(tests/ci_sharding.py)对按耗时降序排列的文件做「放入当前最轻的组」的贪心分配,让每个 CI shard 的预估时长尽量均衡——这正是make test-full这类全量回归能保持稳定时长的底层机制。
小结
OpenSRE 的测试体系可以用「三条命令 + 一套约定 + 两类守卫」概括:make test-cov负责本地并行覆盖、make verify-integrations负责集成改动后的连通性校验、make test-full负责 CI 全量回归;测试必须按领域归置于 tests/ 下与源码镜像的目录;tests/github_ci/用真实测试强制命名与架构契约(包括test_case_*遗留命名的清除),tests/conftest.py则以 autouse fixtures 保证每个用例与开发者本机环境彻底隔离。掌握这些规则后,无论是为新增模块补测试、为集成改动跑校验,还是排查全量回归中的偶发失败,你都能快速定位对应的测试文件与运行入口。
【免费下载链接】opensreBuild your own AI SRE agents. The open source toolkit for the AI era.项目地址: https://gitcode.com/GitHub_Trending/op/opensre
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考