From 68cdff88934bd6cb4da3ed395f91b05b0daae1b7 Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Tue, 2 Jun 2026 23:55:07 +0800 Subject: [PATCH 1/8] fix: enforce AI framework gate + standalone CLI path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CLAUDE.md: add hard AI agent STOP gate with 3 Do-NOT rules - CLAUDE.md: document standalone CLI (tagent) as first-class path - install.py: add copy_runtime to deploy MCP/CLI modules - install.py: restructure workspace dirs — remove 执行日志/charters, flatten into 测试报告/ + 截图/ - install.py: finish() shows both CLI and AI collaboration paths --- CLAUDE.md | 90 ++++++++++++++++++++++++++++++++++++++++-------------- install.py | 57 ++++++++++++++++++++++++---------- 2 files changed, 108 insertions(+), 39 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e524e1a..f06cb14 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,10 +1,68 @@ # CLAUDE.md -## Entry Point +## AI AGENT — STOP. READ THIS FIRST. -This project uses **Skill workflow documents → manual Agent calls** pattern. Slash commands like `/smoke-test` are **not registered** as Claude Code commands — they are workflow documents in `skills/` that describe step-by-step processes. The main thread reads the Skill doc, then calls `Agent(subagent_type="xxx")` sequentially. +**This is a Test-Agent project. It has a defined execution framework. You MUST follow it.** -There is **no auto-orchestration engine**. The main thread reads Skill docs and calls Agents sequentially. Agents may invoke utils but often implement equivalent logic themselves. +- Do NOT call `Agent()` directly. +- Do NOT spawn sub-agents without reading the relevant Skill doc first. +- Do NOT skip the Skill workflow layer. + +**Correct flow:** +1. Read `skills/.md` to understand the workflow +2. Follow the Skill doc's step-by-step agent call sequence +3. Call `Agent(subagent_type="xxx")` ONLY when and how the Skill doc says + +**If no Skill doc matches the task:** fall back to `skills/test-coordinator.md` (通用编排). + +--- + +## Two Ways to Use Test-Agent + +### Way 1: Standalone CLI (no AI required) + +```bash +cd project-dir +pip install -e runtime/ # first time only +tagent run "path/to/prd.md" # router + orchestrator end-to-end +tagent catalog # list 16 experts + 32 skills +tagent status # check run status +tagent report # full execution report +tagent doctor # health check +``` + +The CLI uses the same runtime (router + orchestrator + utils) without needing Claude Code. + +### Way 2: Claude Code Agent Collaboration (AI-assisted) + +```bash +cd project-dir && claude +# Inside Claude Code: +# 1. Read skills/smoke-test.md +# 2. Follow the workflow: call Agent(subagent_type="requirements-analyst"), then test-lead, etc. +# 3. Outputs in workspace/ +``` + +**⚠️ Critical:** Claude Code agents WILL try to bypass the Skill layer and call Agent() directly. The main thread MUST enforce reading Skill docs first. + +--- + +## Architecture + +``` +Standalone CLI (tagent) AI Agent Mode (Claude Code) + │ │ + ▼ ▼ + runtime/router Skill docs (skills/*.md) + │ │ + ▼ ▼ + runtime/orchestrator Agent defs (agents/*.md) + │ │ + ▼ ▼ + utils/*.py (78 modules) utils/*.py (78 modules) +``` + +Both paths converge at the utils execution layer. ## Directory Map @@ -13,31 +71,17 @@ There is **no auto-orchestration engine**. The main thread reads Skill docs and | Agent definitions | `agents/` (16 agents) | | Skill workflow docs | `skills/` (35 skills) | | Python utils | `utils/` (78 modules) | +| Runtime (CLI + orchestrator + MCP) | `runtime/` | | Config templates | `config/` (incl. `.env.example`) | | Test outputs | `workspace/` | -| Runtime / MCP | `runtime/` | | CI pipelines | `ci/` | | Docs | `docs/` | | Marketplace | `marketplace/` | -## How to Run - -1. Copy `config/.env.example` to `.env` and fill in required values -2. Read the relevant Skill doc in `skills/` to understand the workflow -3. Call agents manually via `Agent(subagent_type="xxx")` following the Skill flow -4. Outputs land in `workspace/` - -## Architecture - -``` -Skill docs (skills/*.md) → define workflows -Agent defs (agents/*.md) → define roles + tool access -Utils (utils/*.py) → executable implementations -``` - -## Design Limitations +## Design Notes -- `/smoke-test` etc. are **not** registered slash commands. They are workflow documents. -- Agent definitions contain Python import hints (e.g. `from utils.prd_loader import load_prd`) as prompts for AI agents, not actual executable code. -- `test-lead` cannot recursively spawn sub-agents (Claude Code architecture limitation). +- Slash commands like `/smoke-test` are **not** registered. They are Skill workflow documents. +- Agent definitions contain Python import hints as prompts for AI agents — not actual executable code. +- `test-lead` cannot recursively spawn sub-agents (Claude Code limitation). Main thread orchestrates. - Pentest workflows require `tagent.yml` with `pentest.authorized: true` — see `tagent.yml.example`. +- MCP server (`python -m runtime.mcp.test_orchestrator.server`) provides catalog/plan/run/status/report tools. diff --git a/install.py b/install.py index d4c6d66..d17d857 100644 --- a/install.py +++ b/install.py @@ -70,7 +70,7 @@ def _parse_args(): PRESERVE_FILES = [ ".env", os.path.join("workspace", "测试数据", "test_data.json"), - os.path.join("workspace", "执行日志", "baselines", "perf_baseline.json"), + os.path.join("workspace", "测试报告", "baselines", "perf_baseline.json"), "workspace/regression_modules.yaml", ] @@ -286,19 +286,18 @@ def create_dirs(project_root): os.path.join("workspace", "测试用例"), os.path.join("workspace", "测试数据"), os.path.join("workspace", "测试报告"), - os.path.join("workspace", "测试用例", "charters"), + os.path.join("workspace", "测试报告", "allure-results"), + os.path.join("workspace", "测试报告", "jmeter-results"), + os.path.join("workspace", "测试报告", "jmeter-report"), + os.path.join("workspace", "测试报告", "coverage-report"), + os.path.join("workspace", "测试报告", "baselines"), + os.path.join("workspace", "测试报告", "history"), + os.path.join("workspace", "截图"), os.path.join("workspace", "自动化脚本", "python", "pages"), os.path.join("workspace", "自动化脚本", "python", "api"), os.path.join("workspace", "自动化脚本", "python", "tests"), os.path.join("workspace", "自动化脚本", "python", "scripts"), os.path.join("workspace", "自动化脚本", "jmeter"), - os.path.join("workspace", "执行日志", "allure-results"), - os.path.join("workspace", "执行日志", "jmeter-results"), - os.path.join("workspace", "执行日志", "jmeter-report"), - os.path.join("workspace", "执行日志", "coverage-report"), - os.path.join("workspace", "执行日志", "baselines"), - os.path.join("workspace", "执行日志", "history"), - os.path.join("workspace", "执行日志", "截图"), "memory", ] for d in dirs: @@ -390,6 +389,26 @@ def copy_utils(template_dir, project_root): print(f" ✓ {count} 个 .py 文件已拷贝") +def copy_runtime(template_dir, project_root): + """拷贝 runtime 目录下所有 .py 文件(MCP servers / orchestrator / router 等)。""" + print("→ 拷贝 runtime...") + runtime_src = os.path.join(template_dir, "runtime") + runtime_dst = os.path.join(project_root, "runtime") + count = 0 + skip = {".pyc", "__pycache__", ".ruff_cache", ".pytest_cache", ".egg-info"} + for root, dirs, files in os.walk(runtime_src): + dirs[:] = [d for d in dirs if d not in skip] + for f in files: + if f.endswith(".py") or f.endswith(".md"): + src = os.path.join(root, f) + rel = os.path.relpath(src, runtime_src) + dst = os.path.join(runtime_dst, rel) + os.makedirs(os.path.dirname(dst), exist_ok=True) + shutil.copy2(src, dst) + count += 1 + print(f" ✓ {count} 个文件已拷贝") + + def copy_ci(template_dir, project_root): """拷贝 CI/CD 文件。""" print("→ 拷贝 CI/CD...") @@ -499,13 +518,17 @@ def finish(project_root): 项目目录: {project_root} - 下一步: - 1. 编辑 {project_root}/.env(最少 8 必填字段,详见 配置清单.md) - 2. 安装 Java JRE 17 + JMeter 5.6.3 + Allure CLI(详见 部署说明.md) - 3. claude /login # 首次登录 Claude Code - 4. cd {project_root} && claude # 启动 - 5. cd {project_root} && claude # 进入项目 - 6. 阅读 skills/smoke-test.md 工作流 # 第一次冒烟验证 + === 独立使用(不需 AI)=== + pip install -e {project_root}/runtime/ + tagent run "path/to/prd.md" # 一键执行 + tagent doctor # 健康检查 + tagent catalog # 查看所有专家和技能 + + === AI 协作模式 === + 1. 编辑 {project_root}/.env + 2. claude /login + 3. cd {project_root} && claude + 4. AI 会自动读取 CLAUDE.md,请确保它遵循 skills/ 流程文档 {'=' * 50} """ @@ -625,6 +648,7 @@ def do_update(): copy_skills(template_dir, PROJECT_ROOT) copy_config(template_dir, PROJECT_ROOT) copy_utils(template_dir, PROJECT_ROOT) + copy_runtime(template_dir, PROJECT_ROOT) copy_ci(template_dir, PROJECT_ROOT) copy_top_level_docs(template_dir, PROJECT_ROOT) @@ -692,6 +716,7 @@ def main(): copy_skills(template_dir, PROJECT_ROOT) copy_config(template_dir, PROJECT_ROOT) copy_utils(template_dir, PROJECT_ROOT) + copy_runtime(template_dir, PROJECT_ROOT) copy_ci(template_dir, PROJECT_ROOT) copy_top_level_docs(template_dir, PROJECT_ROOT) From c0deb6362c958f56f0e5c1df4cc9dad68feb6bb0 Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 00:32:04 +0800 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20consolidate=20output=20paths=20?= =?UTF-8?q?=E2=80=94=20=E6=89=A7=E8=A1=8C=E6=97=A5=E5=BF=97/=20=E2=86=92?= =?UTF-8?q?=20=E6=B5=8B=E8=AF=95=E6=8A=A5=E5=91=8A/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Systematic path normalization across entire codebase (86 files): - Eliminate legacy workspace/执行日志/ directory; all outputs under workspace/测试报告/ - install.py: 截图/ → screenshots/ under 测试报告/ - .gitignore: update ignore/whitelist rules for new paths - Add AGENTS.md (Cursor/Windsurf) and .github/copilot-instructions.md for multi-AI-tool compatibility - Update all agent docs, skill docs, config files, runtime orchestrator, and utils --- .github/copilot-instructions.md | 31 +++++++ .gitignore | 5 +- AGENTS.md | 78 ++++++++++++++++++ ...13\350\257\225\344\270\273\347\256\241.md" | 8 +- ...50\344\276\213\350\256\276\350\256\241.md" | 4 +- ...57\345\242\203\347\256\241\347\220\206.md" | 8 +- ...60\346\215\256\345\207\206\345\244\207.md" | 2 +- ...50\345\214\226\350\204\232\346\234\254.md" | 6 +- ...13\350\257\225\346\211\247\350\241\214.md" | 32 ++++---- "agents/08-Bug\347\256\241\347\220\206.md" | 2 +- ...45\345\221\212\347\224\237\346\210\220.md" | 6 +- ...73\345\212\250\346\265\213\350\257\225.md" | 16 ++-- ...14\351\235\242\346\265\213\350\257\225.md" | 8 +- ...70\346\210\217\346\265\213\350\257\225.md" | 6 +- ...06\346\210\220\346\265\213\350\257\225.md" | 8 +- ...41\345\236\213\346\265\213\350\257\225.md" | 10 +-- ...06\346\210\220\350\257\264\346\230\216.md" | 4 +- ci/github-actions-test.yml | 50 ++++++------ ci/jenkins-pipeline.groovy | 64 +++++++-------- config/.env.example | 4 +- config/conftest.py | 81 +++++++++---------- config/mcp-server-impl.md | 2 +- config/pytest.ini | 4 +- docs/charter/01-vision-dimensions.md | 4 +- docs/charter/02-coverage-matrix.md | 2 +- docs/charter/03-agentchat-protocol.md | 2 +- docs/charter/04-skills-bugtracker.md | 2 +- docs/charter/05-install-deploy.md | 6 +- ...30\347\211\251\346\270\205\345\215\225.md" | 48 +++++------ ...77\347\224\250\346\211\213\345\206\214.md" | 24 +++--- ...50\347\275\262\350\257\264\346\230\216.md" | 20 ++--- ...15\347\275\256\346\270\205\345\215\225.md" | 8 +- docs/tutorial/TUTORIAL.md | 2 +- install.py | 2 +- runtime/api/main.py | 4 +- runtime/cli/commands/demo.py | 2 +- runtime/learning_loop/INDEX.md | 2 +- runtime/marketplace/installer.py | 2 +- runtime/mcp/base.py | 2 +- runtime/observability/audit.py | 2 +- runtime/observability/dashboard.py | 2 +- .../agents/automation_engineer.py | 2 +- .../orchestrator/agents/automotive_tester.py | 2 +- runtime/orchestrator/agents/bug_manager.py | 2 +- runtime/orchestrator/agents/env_manager.py | 2 +- runtime/orchestrator/agents/mobile_tester.py | 2 +- runtime/orchestrator/agents/pentest_tester.py | 2 +- .../agents/requirements_analyst.py | 2 +- runtime/orchestrator/agents/system_tester.py | 2 +- runtime/orchestrator/agents/test_executor.py | 2 +- runtime/orchestrator/agents/test_lead.py | 2 +- runtime/orchestrator/agents/visual_tester.py | 2 +- runtime/orchestrator/skills/eval_harness.py | 26 +++--- runtime/orchestrator/skills/mobile_test.py | 28 +++---- .../skills/pentest_coordinator.py | 6 +- runtime/orchestrator/skills/system_test.py | 26 +++--- runtime/orchestrator/skills/visual_test.py | 18 ++--- runtime/tests/test_router_real.py | 2 +- scripts/_demo-commands.sh | 6 +- skills/ai-test.md | 2 +- skills/data-preparation.md | 2 +- skills/desktop-test.md | 4 +- skills/jmeter-script-gen.md | 28 +++---- skills/mobile-test.md | 10 +-- skills/pentest-coordinator.md | 2 +- skills/regression-test.md | 28 +++---- skills/smoke-test.md | 8 +- skills/system-test.md | 2 +- skills/test-coordinator.md | 16 ++-- skills/visual-test.md | 14 ++-- skills/zentao-bug-submission.md | 2 +- utils/a11y_i18n/a11y_scanner.py | 2 +- utils/a11y_i18n/a11y_scanner_v2.py | 2 +- utils/a11y_i18n/fairness_auditor.py | 2 +- utils/a11y_i18n/ux_metrics.py | 2 +- utils/performance/jmeter_result_parser.py | 2 +- utils/performance/slo_validator.py | 2 +- utils/performance/web_vitals_collector.py | 2 +- utils/platforms/desktop_driver.py | 6 +- utils/platforms/media_validator.py | 2 +- utils/platforms/mobile_driver.py | 8 +- utils/quality/flaky_detector.py | 12 +-- utils/reporting/evidence_chain.py | 12 +-- utils/security/absentee_scenario_injector.py | 4 +- utils/security/ai_validator.py | 8 +- utils/security/security_scanner.py | 2 +- utils/security/silent_failure_detector.py | 2 +- utils/testing/soak_runner.py | 2 +- 88 files changed, 503 insertions(+), 396 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 AGENTS.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..bc8ac2c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,31 @@ +# Copilot Instructions + +This is a Test-Agent project with a defined Skill → Agent → Utils execution framework. + +## When generating code or answering questions: + +1. **Read Skill docs first** — Check `skills/.md` to understand the workflow before generating any test code or calling agents. +2. **Follow the framework** — Do not skip the Skill workflow layer. Agent definitions are in `agents/`, utils in `utils/`. +3. **Use existing utils** — The project has 78 utility modules in `utils/`. Prefer using them over generating new code. +4. **Match the project structure** — Test outputs go to `workspace/`, config in `config/`, source code in `src/`. +5. **Config first** — Check `.env.example` for required environment variables before generating code that depends on them. + +## Standalone CLI + +The project has a CLI at `runtime/cli/main.py` (entry point: `tagent`): +```bash +tagent run "path/to/prd.md" +tagent catalog +tagent doctor +``` + +## Key directories + +| What | Where | +|------|-------| +| Agent definitions | `agents/` | +| Skill workflow docs | `skills/` | +| Python utils | `utils/` | +| Runtime (CLI + MCP) | `runtime/` | +| Config templates | `config/` | +| Test outputs | `workspace/` | diff --git a/.gitignore b/.gitignore index 903351f..53528ad 100644 --- a/.gitignore +++ b/.gitignore @@ -17,14 +17,13 @@ htmlcov/ # workspace 测试产出(敏感 + 体积大) workspace/测试数据/ -workspace/执行日志/ workspace/测试报告/ workspace/_outputs/ workspace/feedback/ workspace/自动化脚本/ -# 但保留 workspace/执行日志/baselines/(性能基线需提交) -!workspace/执行日志/baselines/ +# 但保留 workspace/测试报告/baselines/(性能基线需提交) +!workspace/测试报告/baselines/ # ===== 敏感配置 ===== .env diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e1364de --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,78 @@ +# AGENTS.md + +## AI AGENT — STOP. READ THIS FIRST. + +**This is a Test-Agent project. It has a defined execution framework. You MUST follow it.** + +- Do NOT call or spawn sub-agents without reading the relevant Skill doc first. +- Do NOT skip the Skill workflow layer. +- Do NOT execute test workflows directly — read the Skill doc and follow its agent call sequence. + +**Correct flow:** +1. Read `skills/.md` to understand the workflow +2. Follow the Skill doc's step-by-step agent call sequence +3. Use Agent tools ONLY when and how the Skill doc says + +**If no Skill doc matches the task:** fall back to `skills/test-coordinator.md`. + +--- + +## Two Ways to Use Test-Agent + +### Way 1: Standalone CLI (no AI required) + +```bash +cd project-dir +pip install -e runtime/ # first time only +tagent run "path/to/prd.md" # router + orchestrator end-to-end +tagent catalog # list 16 experts + 32 skills +tagent doctor # health check +``` + +### Way 2: AI Agent Collaboration + +```bash +cd project-dir +# Read skills/smoke-test.md first, then follow workflow +# Call sub-agents per Skill doc sequence (requirements-analyst → testcase-designer → ...) +# Outputs in workspace/ +``` + +--- + +## Architecture + +``` +Standalone CLI (tagent) AI Agent Mode + │ │ + ▼ ▼ + runtime/router Skill docs (skills/*.md) + │ │ + ▼ ▼ + runtime/orchestrator Agent defs (agents/*.md) + │ │ + ▼ ▼ + utils/*.py (78 modules) utils/*.py (78 modules) +``` + +Both paths converge at the utils execution layer. + +## Directory Map + +| What | Where | +|------|-------| +| Agent definitions | `agents/` (16 agents) | +| Skill workflow docs | `skills/` (35 skills) | +| Python utils | `utils/` (78 modules) | +| Runtime (CLI + orchestrator + MCP) | `runtime/` | +| Config templates | `config/` (incl. `.env.example`) | +| Test outputs | `workspace/` | +| CI pipelines | `ci/` | +| Docs | `docs/` | + +## Design Notes + +- Slash commands like `/smoke-test` are Skill workflow documents, not registered commands. +- Agent definitions contain Python import hints as prompts for AI agents — not actual executable code. +- Pentest workflows require `tagent.yml` with `pentest.authorized: true`. +- MCP server (`python -m runtime.mcp.test_orchestrator.server`) provides catalog/plan/run/status/report tools. diff --git "a/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" "b/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" index e384963..735bae9 100644 --- "a/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" +++ "b/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" @@ -390,8 +390,8 @@ PRD: 社交 APP,含 Android+iOS 客户端 + 后端 API + Web 管理后台 + - 测试用例: workspace/测试用例/testcases_{模块}_{日期}.xlsx(4 Sheet) - 自动化脚本: workspace/自动化脚本/python/ + jmeter/ - 测试报告: workspace/测试报告/测试报告_{日期}.docx -- Allure 报告: workspace/执行日志/allure-report/ -- JMeter 报告: workspace/执行日志/jmeter-report/index.html +- Allure 报告: workspace/测试报告/allure-report/ +- JMeter 报告: workspace/测试报告/jmeter-report/index.html - Bug 列表: 禅道 Bug ID 清单 + JSON ## 11. 责任分工 @@ -499,14 +499,14 @@ report = slo_report({ "availability": 99.95, "latency_p95_ms": 420, "error_rate_pct": 0.08, -}, output="workspace/执行日志/slo_report.json") +}, output="workspace/测试报告/slo_report.json") ``` **燃烧率(burn rate)**:错误预算消耗速度。> 1.0 表示按当前速度本周期内会耗尽。 ## 性能基线管理 -- 基线文件:`workspace/执行日志/baselines/perf_baseline.json` +- 基线文件:`workspace/测试报告/baselines/perf_baseline.json` - 更新规则:仅在 release 分支 + 完整压测(full 模式)+ 当次门禁全 PASS 时,由 `utils/jmeter_result_parser.py --update-baseline` 写入 - 比对工具:`utils/jmeter_result_parser.py --baseline ...` diff --git "a/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" "b/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" index 50a0106..1380fdd 100644 --- "a/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" +++ "b/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" @@ -50,7 +50,7 @@ EXPERT_IMPL_STATUS: script - 转换为正式用例(如某场景值得回归) ``` -**章程模板**(落 `workspace/测试用例/charters/` 目录): +**章程模板**(落 `workspace/测试用例/` 目录): ```markdown # Charter: 登录模块异常输入探索 @@ -250,7 +250,7 @@ python -m utils.suite_minimizer dup-excel \ # 见 utils.suite_minimizer.minimize_by_coverage ``` -输出:`workspace/执行日志/suite_minimization_report.json`,含可删除候选清单(人工最终决定)。 +输出:`workspace/测试报告/suite_minimization_report.json`,含可删除候选清单(人工最终决定)。 ## 用例设计原则 diff --git "a/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" "b/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" index 342de53..4156e1a 100644 --- "a/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" +++ "b/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" @@ -143,7 +143,7 @@ def health_check(env_config) -> dict: report["status"] = "fail" report["failed_checks"] = failed - out = Path(f"workspace/执行日志/环境检查_{datetime.now():%Y%m%d_%H%M%S}.json") + out = Path(f"workspace/测试报告/环境检查_{datetime.now():%Y%m%d_%H%M%S}.json") out.parent.mkdir(parents=True, exist_ok=True) out.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8") logger.info(f"环境健康报告:{out}") @@ -206,7 +206,7 @@ services: } ``` -落盘路径:`workspace/执行日志/环境检查_{时间戳}.json` +落盘路径:`workspace/测试报告/环境检查_{时间戳}.json` ### 5. 环境清理(Post-test Teardown) @@ -284,8 +284,8 @@ def prepare_environment_with_retry(env_config, max_retries: int = 3) -> bool: | 文件 | 用途 | |------|------| -| `workspace/执行日志/环境检查_{时间戳}.json` | 健康报告 | -| `workspace/执行日志/环境清理_{时间戳}.json` | 清理报告 | +| `workspace/测试报告/环境检查_{时间戳}.json` | 健康报告 | +| `workspace/测试报告/环境清理_{时间戳}.json` | 清理报告 | ## 与 conftest.py 协作 diff --git "a/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" "b/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" index 41f6200..56e3c42 100644 --- "a/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" +++ "b/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" @@ -121,7 +121,7 @@ out.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") |---------|------|--------| | `workspace/测试数据/test_data.json` | pytest 功能测试数据(conftest fixture 消费) | conftest / automation-engineer | | `workspace/测试数据/jmeter_users.csv` | JMeter 参数化压测数据 | jmeter-script-gen / test-executor | -| `workspace/执行日志/数据清理_{日期}.json` | 数据清理报告 | test-lead | +| `workspace/测试报告/数据清理_{日期}.json` | 数据清理报告 | test-lead | ## ⚠️ 异常处理原则 diff --git "a/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" "b/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" index c07f7e4..65bb722 100644 --- "a/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" +++ "b/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" @@ -40,7 +40,7 @@ project_root/ │ │ │ └── test_p2_full/ │ │ └── scripts/ # health_check.sh 等 │ └── jmeter/ # JMeter JMX 文件(test_plan.jmx 等) - └── 测试用例/、测试数据/、执行日志/ + └── 测试用例/、测试数据/、测试报告/ ``` > 注:`conftest.py` 仅一份,位于项目根(部署来自 config/conftest.py)。`workspace/自动化脚本/python/` 内**不再放 conftest.py**。 @@ -250,8 +250,8 @@ Step 5: 向 test-executor 提交执行清单 "duration": 60 }, "output": { - "jtl": "workspace/执行日志/jmeter-results/result.jtl", - "report_dir": "workspace/执行日志/jmeter-report/" + "jtl": "workspace/测试报告/jmeter-results/result.jtl", + "report_dir": "workspace/测试报告/jmeter-report/" } } ``` diff --git "a/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" "b/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" index 4697cb1..9555c8b 100644 --- "a/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" +++ "b/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" @@ -1,6 +1,6 @@ --- name: test-executor -description: 测试执行专家 - 按优先级执行测试用例(含 JMeter 性能阶段),监控执行过程,记录执行日志,处理执行异常,输出实时执行状态报告。 +description: 测试执行专家 - 按优先级执行测试用例(含 JMeter 性能阶段),监控执行过程,记录测试报告,处理执行异常,输出实时执行状态报告。 tools: Read, Write, Bash, Grep, Glob EXPERT_IMPL_STATUS: production --- @@ -66,7 +66,7 @@ pytest -m "p0 or p1" \ --reruns-delay=5 \ --timeout=120 \ --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/执行日志/regression-results.xml \ + --junitxml=workspace/测试报告/regression-results.xml \ -v # 冒烟(不开启 reruns,配合 flaky_detector) @@ -74,7 +74,7 @@ pytest -m "p0" \ -n 2 \ --timeout=60 \ --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/执行日志/smoke-results.xml \ + --junitxml=workspace/测试报告/smoke-results.xml \ --tb=short ``` @@ -94,7 +94,7 @@ pytest -m "p0" \ ### 失败分类 -遇到失败时,必须先分类再处理(写入 `workspace/执行日志/failure_classification.json`): +遇到失败时,必须先分类再处理(写入 `workspace/测试报告/failure_classification.json`): ```python FAILURE_CATEGORIES = { @@ -123,10 +123,10 @@ FAILURE_CATEGORIES = { > 自动判定示例:从 `pytest --tb=short` 输出 + traceback 类型用关键字匹配,落地 `failure_classification.json`,bug-manager 按此 JSON 自动批量提交。 -## 执行日志格式 +## 测试报告格式 ```text -=== 测试执行日志 === +=== 测试测试报告 === 开始:2026-05-10 14:30:00 环境:test (http://test.example.com) 策略:P0+P1 回归,并行 4 进程 @@ -192,8 +192,8 @@ def handle_environment_instability(env_error_rate: float, env_config) -> bool: ```bash # 每次执行后归档 junit-xml 到 history(供 flaky_detector 后续分析) python -m utils.flaky_detector \ - --archive workspace/执行日志/regression-results.xml \ - --history workspace/执行日志/history \ + --archive workspace/测试报告/regression-results.xml \ + --history workspace/测试报告/history \ --limit 5 ``` @@ -212,8 +212,8 @@ def test_something_unstable(): # CI 默认:ci_quick jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/result.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/result.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -222,8 +222,8 @@ jmeter -n \ # 完整压测:full(手动/release) jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/full_result.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/full_result.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -237,14 +237,14 @@ jmeter -n \ ```bash # CI quick 模式 python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode ci_quick # Full 模式 + 基线对比 + 通过则更新基线 python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/full_result.jtl \ + workspace/测试报告/jmeter-results/full_result.jtl \ --mode full \ - --baseline workspace/执行日志/baselines/perf_baseline.json \ + --baseline workspace/测试报告/baselines/perf_baseline.json \ --update-baseline \ --regression-max-pct 20 ``` @@ -336,7 +336,7 @@ python -m utils.chaos_helper block --duration 30 "avg_response_ms": 142, "error_rate_pct": 0.08, "quality_gate": "PASS", - "html_report": "workspace/执行日志/jmeter-report/index.html" + "html_report": "workspace/测试报告/jmeter-report/index.html" } } ``` diff --git "a/agents/08-Bug\347\256\241\347\220\206.md" "b/agents/08-Bug\347\256\241\347\220\206.md" index 577d076..2b31e64 100644 --- "a/agents/08-Bug\347\256\241\347\220\206.md" +++ "b/agents/08-Bug\347\256\241\347\220\206.md" @@ -127,7 +127,7 @@ from utils.zentao_bug_manager import ZentaoBugManager import json manager = ZentaoBugManager() -results = json.load(open("workspace/执行日志/regression_summary.json", encoding="utf-8")) +results = json.load(open("workspace/测试报告/regression_summary.json", encoding="utf-8")) submitted = manager.batch_submit_from_failures( failures=results["failures"], diff --git "a/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" "b/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" index b0b8968..91309f6 100644 --- "a/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" +++ "b/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" @@ -12,7 +12,7 @@ EXPERT_IMPL_STATUS: script 调用前确认: ```text -□ test-executor 已输出 workspace/执行日志/regression_summary.json +□ test-executor 已输出 workspace/测试报告/regression_summary.json □ Allure CLI 已装(生成 allure-report) □ pip 装:python-docx + reportlab + python-pptx □ 字体已装(微软雅黑 / PingFang SC / Noto Sans CJK SC,跨平台 fallback) @@ -195,7 +195,7 @@ def pytest_sessionstart(session): ```bash # 生成 Allure 静态报告 allure generate workspace/测试报告/allure-results \ - --output workspace/执行日志/allure-report \ + --output workspace/测试报告/allure-report \ --clean # 启动本地 Allure 报告服务 @@ -203,7 +203,7 @@ allure serve workspace/测试报告/allure-results # 生成 Word + 通知(跨平台时间戳由 Python 处理) python -m utils.generate_report \ - --data workspace/执行日志/regression_summary.json \ + --data workspace/测试报告/regression_summary.json \ --notify ``` diff --git "a/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" "b/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" index 0fc4dea..49b33bb 100644 --- "a/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" +++ "b/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" @@ -157,7 +157,7 @@ python -m utils.mobile_driver monkey \ --events 10000 \ --throttle 200 \ --seed 12345 \ - --output workspace/执行日志/monkey/ + --output workspace/测试报告/monkey/ # 长时压测:10 万事件 + 多设备 serial 指定 python -m utils.mobile_driver monkey \ @@ -185,7 +185,7 @@ result = run_monkey( pct_syskeys=5, # 系统按键 pct_appswitch=2, # 应用切换 pct_anyevent=3, # 其他事件 - output_dir="workspace/执行日志/monkey", + output_dir="workspace/测试报告/monkey", ) # result: {"event_count", "exit_code", "crashes", "anrs", "duration_sec", "stable", "log_file"} @@ -238,7 +238,7 @@ python -m utils.mobile_driver monkey \ ### 与 logcat 协同 -run_monkey 自动调 `archive_logcat()` 归档 crash 时刻的 Android 日志到 `workspace/执行日志/logcat/`。 +run_monkey 自动调 `archive_logcat()` 归档 crash 时刻的 Android 日志到 `workspace/测试报告/logcat/`。 Bug 提交时附带 monkey log + logcat 两份给开发。 ## 小程序测试 @@ -383,7 +383,7 @@ metrics = collect_perf_metrics( duration=60, interval=1, ) -# 输出 workspace/执行日志/mobile-perf/{package}_{timestamp}.json +# 输出 workspace/测试报告/mobile-perf/{package}_{timestamp}.json # 含:cpu_pct / mem_mb / fps / battery_pct / network_kbps ``` @@ -416,7 +416,7 @@ metrics = collect_perf_metrics( | 文件 | 用途 | |------|------| -| `workspace/执行日志/mobile-perf/*.json` | 性能采集 | -| `workspace/执行日志/截图/mobile_*.png` | 移动失败截图 | -| `workspace/执行日志/logcat/*.log` | Android 日志 | -| `workspace/执行日志/ios-syslog/*.log` | iOS 日志 | +| `workspace/测试报告/mobile-perf/*.json` | 性能采集 | +| `workspace/测试报告/screenshots/mobile_*.png` | 移动失败截图 | +| `workspace/测试报告/logcat/*.log` | Android 日志 | +| `workspace/测试报告/ios-syslog/*.log` | iOS 日志 | diff --git "a/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" "b/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" index 562662a..0b17d59 100644 --- "a/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" +++ "b/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" @@ -362,7 +362,7 @@ WS_PING_INTERVAL=30 # 心跳间隔秒 | 文件 | 用途 | |------|------| -| `workspace/执行日志/desktop-screenshots/*.png` | 桌面失败截图 | -| `workspace/执行日志/win-event-log/*.evtx` | Windows Event 日志 | -| `workspace/执行日志/mac-console/*.log` | macOS Console 日志 | -| `workspace/执行日志/desktop-perf/*.json` | psutil 进程性能 | +| `workspace/测试报告/screenshots/desktop/*.png` | 桌面失败截图 | +| `workspace/测试报告/win-event-log/*.evtx` | Windows Event 日志 | +| `workspace/测试报告/mac-console/*.log` | macOS Console 日志 | +| `workspace/测试报告/desktop-perf/*.json` | psutil 进程性能 | diff --git "a/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" "b/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" index ae1a1f6..c0c737c 100644 --- "a/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" +++ "b/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" @@ -103,7 +103,7 @@ from utils.visual_helper import compare_images # 比较当前截图与基线 result = compare_images( - current="workspace/执行日志/截图/login_current.png", + current="workspace/测试报告/screenshots/login_current.png", baseline="workspace/自动化脚本/python/visual/baselines/login_baseline.png", threshold=0.95, # SSIM 阈值 ) @@ -157,5 +157,5 @@ VISUAL_SIMILARITY_THRESHOLD=0.95 |------|------| | `workspace/自动化脚本/python/visual/images/` | 模板图(Git 提交) | | `workspace/自动化脚本/python/visual/baselines/` | 视觉回归基线(Git 提交) | -| `workspace/执行日志/visual-diff/*.png` | 视觉差异高亮图 | -| `workspace/执行日志/airtest-report/*.html` | Airtest HTML 报告 | +| `workspace/测试报告/screenshots/visual-diff/*.png` | 视觉差异高亮图 | +| `workspace/测试报告/screenshots/airtest-report/*.html` | Airtest HTML 报告 | diff --git "a/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" "b/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" index c30db98..00e63f4 100644 --- "a/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" +++ "b/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" @@ -219,7 +219,7 @@ FFPROBE_BIN=ffprobe | 文件 | 用途 | |------|------| -| `workspace/执行日志/iot-logs/*.log` | SSH/串口/MQTT 日志 | -| `workspace/执行日志/media-frames/*.png` | 视频抽帧对比 | -| `workspace/执行日志/tracing/*.json` | Jaeger trace 数据 | -| `workspace/执行日志/mq-logs/*.log` | MQ 投递/消费日志 | +| `workspace/测试报告/iot-logs/*.log` | SSH/串口/MQTT 日志 | +| `workspace/测试报告/media-frames/*.png` | 视频抽帧对比 | +| `workspace/测试报告/tracing/*.json` | Jaeger trace 数据 | +| `workspace/测试报告/mq-logs/*.log` | MQ 投递/消费日志 | diff --git "a/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" "b/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" index ecce03f..f8c6ed0 100644 --- "a/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" +++ "b/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" @@ -158,7 +158,7 @@ from fairness_auditor import ( # 数据集偏见检测 r1 = audit_dataset_bias(y_true, sensitive, group_names=["male", "female"]) print(summary(r1)) # CI 友好单行 -export_bias_report(r1) # → workspace/执行日志/ai-fairness/ +export_bias_report(r1) # → workspace/测试报告/ai-fairness/ # 模型公平性(6 指标:DI / SPD / EO / 均衡几率 / 校准 / 预测对等) r2 = audit_model_fairness(y_true, y_pred, sensitive, group_names=["male", "female"]) @@ -259,7 +259,7 @@ AI_DRIFT_BASELINE=workspace/自动化脚本/python/ai/datasets/drift_baseline.cs | 文件 | 用途 | |------|------| -| `workspace/执行日志/ai-eval/*.json` | 模型评估指标 | -| `workspace/执行日志/ai-drift/*.json` | 漂移检测报告 | -| `workspace/执行日志/ai-fairness/*.json` | 公平性指标 | -| `workspace/执行日志/llm-cases/*.json` | LLM 用例输出(含拒答 / 格式 / 事实性) | +| `workspace/测试报告/ai-eval/*.json` | 模型评估指标 | +| `workspace/测试报告/ai-drift/*.json` | 漂移检测报告 | +| `workspace/测试报告/ai-fairness/*.json` | 公平性指标 | +| `workspace/测试报告/llm-cases/*.json` | LLM 用例输出(含拒答 / 格式 / 事实性) | diff --git "a/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" "b/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" index 6b72498..884419a 100644 --- "a/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" +++ "b/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" @@ -184,13 +184,13 @@ allure serve workspace/测试报告/allure-results # 生成静态报告 allure generate workspace/测试报告/allure-results \ - --output workspace/执行日志/allure-report --clean + --output workspace/测试报告/allure-report --clean ``` ### 报告目录结构 ```text -workspace/执行日志/ +workspace/测试报告/ ├── allure-results/ # Allure 原始数据 ├── allure-report/ # Allure 静态 HTML ├── jmeter-results/result.jtl # JMeter 原始结果 diff --git a/ci/github-actions-test.yml b/ci/github-actions-test.yml index b7a9b3e..ea49dfe 100644 --- a/ci/github-actions-test.yml +++ b/ci/github-actions-test.yml @@ -130,7 +130,7 @@ jobs: - name: 创建工作目录 run: | mkdir -p workspace/测试报告/allure-results - mkdir -p workspace/执行日志/截图 + mkdir -p workspace/测试报告/screenshots mkdir -p workspace/测试数据 - name: 执行冒烟测试(P0) @@ -140,7 +140,7 @@ jobs: --timeout=60 \ --tb=short \ --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/执行日志/smoke-results.xml \ + --junitxml=workspace/测试报告/smoke-results.xml \ -v env: HEADLESS: 'true' @@ -149,15 +149,15 @@ jobs: if: always() run: | python -m utils.ci_quality_gate \ - --smoke-xml workspace/执行日志/smoke-results.xml \ - --output-json workspace/执行日志/smoke_gate_result.json + --smoke-xml workspace/测试报告/smoke-results.xml \ + --output-json workspace/测试报告/smoke_gate_result.json - name: 上传冒烟产物 if: always() uses: actions/upload-artifact@v4 with: name: smoke-test-results - path: workspace/执行日志/ + path: workspace/测试报告/ retention-days: 7 # ===== 3. 回归测试(P0+P1) ===== @@ -193,8 +193,8 @@ jobs: - name: 创建工作目录 run: | mkdir -p workspace/测试报告/allure-results - mkdir -p workspace/执行日志/截图 - mkdir -p workspace/执行日志/coverage-report + mkdir -p workspace/测试报告/screenshots + mkdir -p workspace/测试报告/coverage-report - name: 执行回归测试(并行 4 进程) run: | @@ -204,11 +204,11 @@ jobs: --reruns-delay=5 \ --timeout=120 \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/执行日志/coverage.xml \ - --cov-report=html:workspace/执行日志/coverage-report \ + --cov-report=xml:workspace/测试报告/coverage.xml \ + --cov-report=html:workspace/测试报告/coverage-report \ --cov-fail-under=80 \ --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/执行日志/regression-results.xml \ + --junitxml=workspace/测试报告/regression-results.xml \ -v env: HEADLESS: 'true' @@ -217,16 +217,16 @@ jobs: if: always() run: | python -m utils.ci_quality_gate \ - --regression-xml workspace/执行日志/regression-results.xml \ - --coverage-xml workspace/执行日志/coverage.xml \ + --regression-xml workspace/测试报告/regression-results.xml \ + --coverage-xml workspace/测试报告/coverage.xml \ --coverage-threshold 80 \ - --output-json workspace/执行日志/regression_gate_result.json + --output-json workspace/测试报告/regression_gate_result.json - name: 上传覆盖率到 Codecov if: always() && needs.preflight.outputs.codecov_enabled == 'true' uses: codecov/codecov-action@v4 with: - file: workspace/执行日志/coverage.xml + file: workspace/测试报告/coverage.xml token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false @@ -235,7 +235,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: regression-test-results - path: workspace/执行日志/ + path: workspace/测试报告/ retention-days: 14 # ===== 4. JMeter 性能测试 ===== @@ -281,9 +281,9 @@ jobs: - name: 创建目录 run: | - mkdir -p workspace/执行日志/jmeter-results - mkdir -p workspace/执行日志/jmeter-report - mkdir -p workspace/执行日志/baselines + mkdir -p workspace/测试报告/jmeter-results + mkdir -p workspace/测试报告/jmeter-report + mkdir -p workspace/测试报告/baselines mkdir -p workspace/测试数据 - name: 生成 JMeter 参数化 CSV(调用 utils) @@ -317,15 +317,15 @@ jobs: fi jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/result.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/result.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${{ steps.target.outputs.host }}" \ -Jtarget_protocol="${{ steps.target.outputs.protocol }}" \ -Jtarget_port="${{ steps.target.outputs.port }}" \ -Jthreads=${THREADS} \ -Jrampup=${RAMPUP} \ -Jduration=${DURATION} \ - -j workspace/执行日志/jmeter-results/jmeter.log + -j workspace/测试报告/jmeter-results/jmeter.log continue-on-error: true - name: 解析 JTL + 性能门禁(含基线对比) @@ -335,9 +335,9 @@ jobs: UPDATE_FLAG="--update-baseline" fi python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode "${PERF_MODE}" \ - --baseline workspace/执行日志/baselines/perf_baseline.json \ + --baseline workspace/测试报告/baselines/perf_baseline.json \ --regression-max-pct 20 \ ${UPDATE_FLAG} @@ -346,7 +346,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: performance-test-results - path: workspace/执行日志/jmeter-results /workspace/执行日志/jmeter-report /workspace/执行日志/baselines + path: workspace/测试报告/jmeter-results /workspace/测试报告/jmeter-report /workspace/测试报告/baselines retention-days: 14 # ===== 5. 发布 Allure 报告 ===== @@ -417,7 +417,7 @@ jobs: - name: 综合门禁检查 run: | - # 解析时优先用每个 artifact 的固定相对路径(artifact 内保留原 workspace/执行日志/ 目录) + # 解析时优先用每个 artifact 的固定相对路径(artifact 内保留原 workspace/测试报告/ 目录) SMOKE="artifacts/smoke-test-results/smoke-results.xml" REGR="artifacts/regression-test-results/regression-results.xml" COV="artifacts/regression-test-results/coverage.xml" diff --git a/ci/jenkins-pipeline.groovy b/ci/jenkins-pipeline.groovy index 36c8ccd..e7b72a8 100644 --- a/ci/jenkins-pipeline.groovy +++ b/ci/jenkins-pipeline.groovy @@ -54,7 +54,7 @@ pipeline { // 工作目录 WORKSPACE_DIR = "${WORKSPACE}/workspace" ALLURE_DIR = "${WORKSPACE_DIR}/测试报告/allure-results" - SCREENSHOT_DIR = "${WORKSPACE_DIR}/执行日志/截图" + SCREENSHOT_DIR = "${WORKSPACE_DIR}/测试报告/screenshots" APP_SRC_PATH = "./src" JMETER_VERSION = "5.6.3" HEADLESS = 'true' @@ -86,12 +86,12 @@ pipeline { pip install -r requirements.txt --quiet playwright install chromium --with-deps mkdir -p workspace/测试报告/allure-results - mkdir -p workspace/执行日志/截图 - mkdir -p workspace/执行日志/jmeter-results - mkdir -p workspace/执行日志/jmeter-report - mkdir -p workspace/执行日志/coverage-report - mkdir -p workspace/执行日志/baselines - mkdir -p workspace/执行日志/history + mkdir -p workspace/测试报告/screenshots + mkdir -p workspace/测试报告/jmeter-results + mkdir -p workspace/测试报告/jmeter-report + mkdir -p workspace/测试报告/coverage-report + mkdir -p workspace/测试报告/baselines + mkdir -p workspace/测试报告/history mkdir -p workspace/测试报告 mkdir -p workspace/测试用例 mkdir -p workspace/测试数据 @@ -116,17 +116,17 @@ pipeline { --timeout=60 \ --tb=short \ --alluredir="${ALLURE_DIR}" \ - --junitxml="${WORKSPACE_DIR}/执行日志/smoke-results.xml" \ - -v 2>&1 | tee workspace/执行日志/smoke.log + --junitxml="${WORKSPACE_DIR}/测试报告/smoke-results.xml" \ + -v 2>&1 | tee workspace/测试报告/smoke.log ''' } post { always { - junit "${WORKSPACE_DIR}/执行日志/smoke-results.xml" + junit "${WORKSPACE_DIR}/测试报告/smoke-results.xml" sh ''' python -m utils.ci_quality_gate \ - --smoke-xml "${WORKSPACE_DIR}/执行日志/smoke-results.xml" \ - --output-json "${WORKSPACE_DIR}/执行日志/smoke_gate_result.json" + --smoke-xml "${WORKSPACE_DIR}/测试报告/smoke-results.xml" \ + --output-json "${WORKSPACE_DIR}/测试报告/smoke_gate_result.json" ''' script { env.STAGE_SMOKE_OK = 'true' @@ -154,10 +154,10 @@ pipeline { --reruns=2 --reruns-delay=5 \ --timeout=120 \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/执行日志/coverage-api.xml \ + --cov-report=xml:workspace/测试报告/coverage-api.xml \ --alluredir="${ALLURE_DIR}" \ - --junitxml="${WORKSPACE_DIR}/执行日志/api-results.xml" \ - -v 2>&1 | tee workspace/执行日志/api.log + --junitxml="${WORKSPACE_DIR}/测试报告/api-results.xml" \ + -v 2>&1 | tee workspace/测试报告/api.log ''' } } @@ -170,17 +170,17 @@ pipeline { --reruns=2 --reruns-delay=5 \ --timeout=180 \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/执行日志/coverage-ui.xml \ + --cov-report=xml:workspace/测试报告/coverage-ui.xml \ --alluredir="${ALLURE_DIR}" \ - --junitxml="${WORKSPACE_DIR}/执行日志/ui-results.xml" \ - -v 2>&1 | tee workspace/执行日志/ui.log + --junitxml="${WORKSPACE_DIR}/测试报告/ui-results.xml" \ + -v 2>&1 | tee workspace/测试报告/ui.log ''' } } } post { always { - junit allowEmptyResults: true, testResults: 'workspace/执行日志/api-results.xml,workspace/执行日志/ui-results.xml' + junit allowEmptyResults: true, testResults: 'workspace/测试报告/api-results.xml,workspace/测试报告/ui-results.xml' script { env.STAGE_REGRESSION_OK = (currentBuild.currentResult == 'SUCCESS') ? 'true' : 'false' } @@ -245,14 +245,14 @@ EOF jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l "${WORKSPACE_DIR}/执行日志/jmeter-results/result.jtl" \ - -e -o "${WORKSPACE_DIR}/执行日志/jmeter-report/" \ + -l "${WORKSPACE_DIR}/测试报告/jmeter-results/result.jtl" \ + -e -o "${WORKSPACE_DIR}/测试报告/jmeter-report/" \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL}" \ -Jtarget_port="${TARGET_PORT}" \ -Jthreads=${THREADS} -Jrampup=${RAMPUP} -Jduration=${DURATION} \ - -j "${WORKSPACE_DIR}/执行日志/jmeter-results/jmeter.log" \ - 2>&1 | tee workspace/执行日志/jmeter.log + -j "${WORKSPACE_DIR}/测试报告/jmeter-results/jmeter.log" \ + 2>&1 | tee workspace/测试报告/jmeter.log ''' // 5) 解析 + 性能门禁(基线对比,仅 full+release+PASS 才更新) @@ -263,9 +263,9 @@ EOF UPDATE_FLAG="--update-baseline" fi python -m utils.jmeter_result_parser \ - "${WORKSPACE_DIR}/执行日志/jmeter-results/result.jtl" \ + "${WORKSPACE_DIR}/测试报告/jmeter-results/result.jtl" \ --mode "${PERF_MODE}" \ - --baseline "${WORKSPACE_DIR}/执行日志/baselines/perf_baseline.json" \ + --baseline "${WORKSPACE_DIR}/测试报告/baselines/perf_baseline.json" \ --regression-max-pct 20 \ ${UPDATE_FLAG} ''' @@ -275,7 +275,7 @@ EOF post { always { archiveArtifacts( - artifacts: 'workspace/执行日志/jmeter-results/**,workspace/执行日志/jmeter-report/**,workspace/执行日志/baselines/**', + artifacts: 'workspace/测试报告/jmeter-results/**,workspace/测试报告/jmeter-report/**,workspace/测试报告/baselines/**', allowEmptyArchive: true ) } @@ -286,7 +286,7 @@ EOF sh """ curl -s -X POST "${WECHAT_WEBHOOK}" \ -H 'Content-Type: application/json' \ - -d '{"msgtype":"markdown","markdown":{"content":"⚠️ **性能测试未达标** | 构建#${BUILD_NUMBER} | 模式:${PERF_MODE} | [查看报告](${BUILD_URL}artifact/workspace/执行日志/jmeter-report/index.html)"}}' + -d '{"msgtype":"markdown","markdown":{"content":"⚠️ **性能测试未达标** | 构建#${BUILD_NUMBER} | 模式:${PERF_MODE} | [查看报告](${BUILD_URL}artifact/workspace/测试报告/jmeter-report/index.html)"}}' """ } } @@ -306,14 +306,14 @@ EOF set -e pytest \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/执行日志/coverage.xml \ - --cov-report=html:workspace/执行日志/coverage-report \ + --cov-report=xml:workspace/测试报告/coverage.xml \ + --cov-report=html:workspace/测试报告/coverage-report \ --cov-fail-under=80 \ --timeout=300 \ -q ''' publishHTML(target: [ - reportDir: 'workspace/执行日志/coverage-report', + reportDir: 'workspace/测试报告/coverage-report', reportFiles: 'index.html', reportName: '代码覆盖率报告', keepAll: true, @@ -340,7 +340,7 @@ EOF always { // 多扩展名拆开(Jenkins ant pattern 不支持 brace expansion) archiveArtifacts( - artifacts: 'workspace/执行日志/**/*.xml,workspace/执行日志/**/*.log,workspace/执行日志/**/*.png,workspace/执行日志/**/*.json', + artifacts: 'workspace/测试报告/**/*.xml,workspace/测试报告/**/*.log,workspace/测试报告/**/*.png,workspace/测试报告/**/*.json', allowEmptyArchive: true ) } @@ -372,7 +372,7 @@ EOF cleanup { sh ''' find workspace/测试数据 -name "*.json" -mtime +7 -delete 2>/dev/null || true - find workspace/执行日志/截图 -name "*.png" -mtime +3 -delete 2>/dev/null || true + find workspace/测试报告/screenshots -name "*.png" -mtime +3 -delete 2>/dev/null || true ''' } } diff --git a/config/.env.example b/config/.env.example index 7b3f3a5..85ab021 100644 --- a/config/.env.example +++ b/config/.env.example @@ -235,8 +235,8 @@ WEB_VITALS_LCP_MAX_MS=2500 WEB_VITALS_CLS_MAX=0.1 # ===== DORA 数据源(CI/CD 部署日志路径)===== -DEPLOYMENTS_LOG=workspace/执行日志/deployments.json -INCIDENTS_LOG=workspace/执行日志/incidents.json +DEPLOYMENTS_LOG=workspace/测试报告/deployments.json +INCIDENTS_LOG=workspace/测试报告/incidents.json # ===== SMTP 邮件(utils.email_sender)===== SMTP_HOST= diff --git a/config/conftest.py b/config/conftest.py index 232e803..a7d97d6 100644 --- a/config/conftest.py +++ b/config/conftest.py @@ -246,7 +246,7 @@ def pytest_runtest_makereport(item, call): try: page = item.funcargs.get("page") if page: - screenshot_dir = Path("workspace/执行日志/截图") + screenshot_dir = Path("workspace/测试报告/screenshots") screenshot_dir.mkdir(parents=True, exist_ok=True) fname = f"{item.name}_{rep.when}_{datetime.now().strftime('%H%M%S')}.png" page.screenshot(path=str(screenshot_dir / fname)) @@ -281,49 +281,48 @@ def pytest_configure(config): "workspace/自动化脚本/python", "workspace/自动化脚本/jmeter", "workspace/测试报告/allure-results", - "workspace/执行日志/截图", - "workspace/执行日志/jmeter-results", - "workspace/执行日志/jmeter-report", - "workspace/执行日志/coverage-report", - "workspace/执行日志/baselines", - "workspace/执行日志/history", + "workspace/测试报告/screenshots", + "workspace/测试报告/jmeter-results", + "workspace/测试报告/jmeter-report", + "workspace/测试报告/coverage-report", + "workspace/测试报告/baselines", + "workspace/测试报告/history", # 扩展平台产出目录 - "workspace/执行日志/mobile-perf", - "workspace/执行日志/monkey", - "workspace/执行日志/logcat", - "workspace/执行日志/ios-syslog", - "workspace/执行日志/desktop-perf", - "workspace/执行日志/desktop-screenshots", - "workspace/执行日志/win-event-log", - "workspace/执行日志/mac-console", - "workspace/执行日志/visual-diff", - "workspace/执行日志/airtest-report", - "workspace/执行日志/iot-logs", - "workspace/执行日志/media-frames", - "workspace/执行日志/tracing", - "workspace/执行日志/mq-logs", - "workspace/执行日志/ai-eval", - "workspace/执行日志/ai-drift", - "workspace/执行日志/ai-fairness", - "workspace/执行日志/llm-cases", + "workspace/测试报告/mobile-perf", + "workspace/测试报告/monkey", + "workspace/测试报告/logcat", + "workspace/测试报告/ios-syslog", + "workspace/测试报告/desktop-perf", + "workspace/测试报告/screenshots/desktop", + "workspace/测试报告/win-event-log", + "workspace/测试报告/mac-console", + "workspace/测试报告/visual-diff", + "workspace/测试报告/airtest-report", + "workspace/测试报告/iot-logs", + "workspace/测试报告/media-frames", + "workspace/测试报告/tracing", + "workspace/测试报告/mq-logs", + "workspace/测试报告/ai-eval", + "workspace/测试报告/ai-drift", + "workspace/测试报告/ai-fairness", + "workspace/测试报告/llm-cases", # 非功能 8 维度产出 - "workspace/执行日志/security", - "workspace/执行日志/compat", - "workspace/执行日志/weak-network", - "workspace/执行日志/soak", - "workspace/执行日志/chaos", - "workspace/执行日志/ux", - "workspace/执行日志/usability", - "workspace/执行日志/exploratory", - "workspace/测试用例/charters", + "workspace/测试报告/security", + "workspace/测试报告/compat", + "workspace/测试报告/weak-network", + "workspace/测试报告/soak", + "workspace/测试报告/chaos", + "workspace/测试报告/ux", + "workspace/测试报告/usability", + "workspace/测试报告/exploratory", # 新增维度产出 - "workspace/执行日志/web-vitals", - "workspace/执行日志/a11y", - "workspace/执行日志/i18n", - "workspace/执行日志/mutation", - "workspace/执行日志/dora", - "workspace/执行日志/blockchain", - "workspace/执行日志/adversarial", + "workspace/测试报告/web-vitals", + "workspace/测试报告/a11y", + "workspace/测试报告/i18n", + "workspace/测试报告/mutation", + "workspace/测试报告/dora", + "workspace/测试报告/blockchain", + "workspace/测试报告/adversarial", "workspace/自动化脚本/python/features", "workspace/自动化脚本/python/i18n", "workspace/自动化脚本/python/pacts", diff --git a/config/mcp-server-impl.md b/config/mcp-server-impl.md index 0868e52..88b070c 100644 --- a/config/mcp-server-impl.md +++ b/config/mcp-server-impl.md @@ -300,7 +300,7 @@ claude /mcp # 打开 MCP 面板 ```python import logging logging.basicConfig( - filename="workspace/执行日志/mcp-zentao.log", + filename="workspace/测试报告/mcp-zentao.log", level=logging.DEBUG, ) ``` diff --git a/config/pytest.ini b/config/pytest.ini index 84b580b..edc7d4d 100644 --- a/config/pytest.ini +++ b/config/pytest.ini @@ -85,7 +85,7 @@ addopts = --strict-markers -p no:warnings --alluredir=workspace/测试报告/allure-results - --junitxml=workspace/执行日志/junit-results.xml + --junitxml=workspace/测试报告/junit-results.xml # JUnit XML 格式:xunit2(兼容现代解析器) junit_family = xunit2 @@ -101,7 +101,7 @@ junit_family = xunit2 log_cli = true log_cli_level = INFO log_cli_format = %(asctime)s [%(levelname)s] %(name)s: %(message)s -log_file = workspace/执行日志/pytest.log +log_file = workspace/测试报告/pytest.log log_file_level = DEBUG log_file_format = %(asctime)s [%(levelname)s] %(name)s: %(message)s diff --git a/docs/charter/01-vision-dimensions.md b/docs/charter/01-vision-dimensions.md index 7e4b636..866b9ce 100644 --- a/docs/charter/01-vision-dimensions.md +++ b/docs/charter/01-vision-dimensions.md @@ -195,8 +195,8 @@ - **指数退避重试**:`utils/api_retry_util.call_with_retry`(10s → 20s → 40s) - **pytest-xdist** 并行执行(默认 4 进程,可调) -- **Flaky 检测与隔离**:`utils/flaky_detector` + `workspace/执行日志/history/` 归档 -- **性能基线管理**:`workspace/执行日志/baselines/perf_baseline.json`,仅 release+full+PASS 自动更新 +- **Flaky 检测与隔离**:`utils/flaky_detector` + `workspace/测试报告/history/` 归档 +- **性能基线管理**:`workspace/测试报告/baselines/perf_baseline.json`,仅 release+full+PASS 自动更新 - **CI/CD 就绪**:GitHub Actions + Jenkins,性能阶段双模式分层 - **MCP 收口**:当前仅启用 filesystem;通知/Bug 走 SDK 直连 diff --git a/docs/charter/02-coverage-matrix.md b/docs/charter/02-coverage-matrix.md index c316e2a..1c445b1 100644 --- a/docs/charter/02-coverage-matrix.md +++ b/docs/charter/02-coverage-matrix.md @@ -62,7 +62,7 @@ | 神圣性与跨文化禁忌边界(宗教/葬礼/儿童/纪念) | i18n_checker + taboo_matrix + 禁忌词/色/数/节日组合(本地化共建) | testcase-designer | ✅ | | Skill 自进化(darwin-skill 双重评估 + 棘轮) | darwin-skill SKILL.md + results.tsv + 子 agent 实测 | test-lead 触发 | ✅ | | Bug 工具多适配(5 套 tracker 全部实装) | bug_tracker_base + zentao/jira/github/linear/webhook_bug_manager | bug-manager | ✅ | -| Agent 协作纪要(讨论/反问/通信落档) | agentchat_recorder + workspace/执行日志/discussions/ | test-lead | ✅ | +| Agent 协作纪要(讨论/反问/通信落档) | agentchat_recorder + workspace/测试报告/discussions/ | test-lead | ✅ | ### 矩阵 C:用例设计方法(ISTQB 经典) diff --git a/docs/charter/03-agentchat-protocol.md b/docs/charter/03-agentchat-protocol.md index 6332124..e352061 100644 --- a/docs/charter/03-agentchat-protocol.md +++ b/docs/charter/03-agentchat-protocol.md @@ -7,7 +7,7 @@ ## 🤝 AgentChat 协作协议(讨论 / 通信 / 反问) > 解决三个问题:(1) agent 之间何时讨论;(2) 怎么通信不撞车;(3) 何时反问用户、怎么反问。 -> **底线**:所有讨论、反问、跨 agent 协调都留可追溯纪要——`workspace/执行日志/discussions/{YYYYMMDD}_{topic}.md`,归档不可删。 +> **底线**:所有讨论、反问、跨 agent 协调都留可追溯纪要——`workspace/测试报告/discussions/{YYYYMMDD}_{topic}.md`,归档不可删。 ### 1. 讨论触发条件(非每次都开会) diff --git a/docs/charter/04-skills-bugtracker.md b/docs/charter/04-skills-bugtracker.md index cbb819d..b87c36d 100644 --- a/docs/charter/04-skills-bugtracker.md +++ b/docs/charter/04-skills-bugtracker.md @@ -15,7 +15,7 @@ ├── SKILL.md ← 上游原文,禁止本地修改(防失同步) ├── templates/result-card*.html ← 上游成果卡片模板 └── scripts/screenshot.mjs ← 上游截图脚本 -workspace/执行日志/skill-evolution/ +workspace/测试报告/skill-evolution/ ├── results.tsv ← 9 列优化日志(含 eval_mode) ├── test-prompts/{skill}.json ← 每个 skill 的实测 prompt 集 └── result-cards/ ← 成果卡片 PNG 归档 diff --git a/docs/charter/05-install-deploy.md b/docs/charter/05-install-deploy.md index be1bf22..49105f2 100644 --- a/docs/charter/05-install-deploy.md +++ b/docs/charter/05-install-deploy.md @@ -80,10 +80,10 @@ $ bash install.sh --add visual,ai 1. **依赖自检**:agent / skill 启动时读取自身 frontmatter `requires_layer`,与已装层并集对比 2. **缺则反问**:缺失则停下反问,列层级 + 关键包 + 预估安装时间 + 影响范围 - + > 示例:"`/visual-test` 需要 visual 层(airtest + opencv-python + pytesseract,约 80MB / 2-5 分钟)。现在补装?(Y/n)" 3. **触发补装**:用户同意 → 调 `install.sh --add visual` → 增量补装 -4. **落档**:补装请求 + 用户决定 + 时间戳 → `workspace/执行日志/discussions/{date}_dependency-asks.md` +4. **落档**:补装请求 + 用户决定 + 时间戳 → `workspace/测试报告/discussions/{date}_dependency-asks.md` 5. **拒绝处置**:用户拒绝 → agent / skill 降级(如可降级,例如 `/visual-test` 退化为纯 pytest)或拒绝执行并落 `decisions/`,**不静默继续假装能跑** **为什么不静默自动装**:跨平台环境差异大(特别是 system 层涉及系统级工具 Java / Node / FFmpeg),强行装可能污染用户环境。符合「Agent 能力越强谦卑义务越重」公理。 @@ -254,7 +254,7 @@ your-test-project/ │ ├── 测试计划/ 需求分析/ 测试用例/ 测试数据/ │ ├── 自动化脚本/python/ jmeter/ │ ├── regression_modules.yaml ← 回归范围配置(可选) -│ └── 执行日志/ +│ └── 测试报告/ │ ├── allure-results/ allure-report/ │ ├── jmeter-results/ jmeter-report/ │ ├── coverage.xml coverage-report/ diff --git "a/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" "b/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" index 65fed50..f7ada46 100644 --- "a/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" +++ "b/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" @@ -13,14 +13,14 @@ | **需求分析报告** | `workspace/需求分析/requirements_analysis_{YYYYMMDD}.md` + `requirements_summary_{YYYYMMDD}.json` | requirements-analyst | MD + JSON | | **测试用例**(评审 / 手测) | `workspace/测试用例/testcases_{模块}_{YYYYMMDD}.xlsx` | testcase-designer | Excel 4 Sheet | | **测试执行报告(给管理层最终版)** | `workspace/测试报告/测试报告_{YYYYMMDD}.docx` | report-generator | Word | -| **Allure 功能交互式报告** | `workspace/执行日志/allure-report/index.html` | test-executor + Allure CLI | HTML | -| **JMeter 性能报告** | `workspace/执行日志/jmeter-report/index.html` | test-executor + JMeter | HTML | -| **覆盖率报告** | `workspace/执行日志/coverage-report/index.html` + `coverage.xml` | pytest-cov | HTML + XML | -| **Bug 列表** | 禅道(在线) + 本地 JSON `workspace/执行日志/regression_summary.json` 内 bug_id | bug-manager | 禅道系统 | -| **执行日志(详细)** | `workspace/执行日志/pytest.log` | pytest | 文本 | -| **失败截图(UI)** | `workspace/执行日志/截图/{用例名}_{时间}.png` | conftest hook | PNG | -| **环境检查报告** | `workspace/执行日志/环境检查_{时间戳}.json` | env-manager | JSON | -| **性能基线**(历史对比用) | `workspace/执行日志/baselines/perf_baseline.json` | jmeter_result_parser | JSON | +| **Allure 功能交互式报告** | `workspace/测试报告/allure-report/index.html` | test-executor + Allure CLI | HTML | +| **JMeter 性能报告** | `workspace/测试报告/jmeter-report/index.html` | test-executor + JMeter | HTML | +| **覆盖率报告** | `workspace/测试报告/coverage-report/index.html` + `coverage.xml` | pytest-cov | HTML + XML | +| **Bug 列表** | 禅道(在线) + 本地 JSON `workspace/测试报告/regression_summary.json` 内 bug_id | bug-manager | 禅道系统 | +| **测试报告(详细)** | `workspace/测试报告/pytest.log` | pytest | 文本 | +| **失败截图(UI)** | `workspace/测试报告/截图/{用例名}_{时间}.png` | conftest hook | PNG | +| **环境检查报告** | `workspace/测试报告/环境检查_{时间戳}.json` | env-manager | JSON | +| **性能基线**(历史对比用) | `workspace/测试报告/baselines/perf_baseline.json` | jmeter_result_parser | JSON | --- @@ -47,9 +47,9 @@ workspace/测试用例/testcases_登录_20260510.xlsx ← 配套(用例草 ```text workspace/测试报告/测试报告_20260510.docx ← 给管理层(Word,含执行摘要+缺陷+性能+风险) -workspace/执行日志/allure-report/index.html ← 给开发/测试(功能详情) -workspace/执行日志/jmeter-report/index.html ← 给性能/PM(性能详情) -workspace/执行日志/coverage-report/index.html ← 给开发(覆盖率详情) +workspace/测试报告/allure-report/index.html ← 给开发/测试(功能详情) +workspace/测试报告/jmeter-report/index.html ← 给性能/PM(性能详情) +workspace/测试报告/coverage-report/index.html ← 给开发(覆盖率详情) ``` **提交方式**: @@ -72,21 +72,21 @@ workspace/执行日志/coverage-report/index.html ← 给开发(覆盖 ```bash # Word 报告 + 多端通知(一条命令) python -m utils.generate_report \ - --data workspace/执行日志/regression_summary.json \ + --data workspace/测试报告/regression_summary.json \ --notify # Allure 静态报告(生成) allure generate workspace/测试报告/allure-results \ - --output workspace/执行日志/allure-report --clean + --output workspace/测试报告/allure-report --clean # Allure 本地服务(临时查看) allure serve workspace/测试报告/allure-results # JMeter 报告(执行 JMeter 时已用 -e -o 自动生成) -# 直接打开 workspace/执行日志/jmeter-report/index.html +# 直接打开 workspace/测试报告/jmeter-report/index.html # 覆盖率报告(pytest 已生成) -# 直接打开 workspace/执行日志/coverage-report/index.html +# 直接打开 workspace/测试报告/coverage-report/index.html ``` --- @@ -109,7 +109,7 @@ workspace/ │ ├── python/ │ └── jmeter/ ├── regression_modules.yaml ← ⚙️ 配置(可选,提交 Git) -└── 执行日志/ +└── 测试报告/ ├── 报告/ ← 📤 对外(最终主报告) │ └── 测试报告_{YYYYMMDD}.docx ├── allure-report/index.html ← 📤 对外(功能详情链接) @@ -149,10 +149,10 @@ workspace/ | test-lead | 测试计划 + 最终决策 | `workspace/测试计划/` | | requirements-analyst | 需求分析(MD + JSON) | `workspace/需求分析/` | | testcase-designer | 用例 Excel | `workspace/测试用例/` | -| env-manager | 环境检查 JSON | `workspace/执行日志/环境检查_*.json` | +| env-manager | 环境检查 JSON | `workspace/测试报告/环境检查_*.json` | | data-preparer | test_data.json + jmeter_users.csv | `workspace/测试数据/` | | automation-engineer | pytest 脚本 + JMX | `workspace/自动化脚本/python/` + `jmeter/` | -| test-executor | 执行结果 JSON + Allure 原始 + JTL | `workspace/执行日志/`(多文件) | +| test-executor | 执行结果 JSON + Allure 原始 + JTL | `workspace/测试报告/`(多文件) | | bug-manager | BugTracker Bug ID 列表 + 日报(默认禅道,可换 Jira/GitHub/GitLab/Linear/Webhook) | BugTracker 在线 + `workspace/测试报告/bug_daily_*.md` | | report-generator | Word 报告 + 多端通知(企微/飞书/钉钉/Slack/邮件/Teams) | `workspace/测试报告/测试报告_*.docx` | @@ -165,9 +165,9 @@ GitHub Actions / Jenkins 会自动归档以下产物(无需手工收集): ### GitHub Actions Artifacts ```text -smoke-test-results ← workspace/执行日志/(冒烟阶段全部) -regression-test-results ← workspace/执行日志/(回归阶段全部,含 coverage) -performance-test-results ← workspace/执行日志/jmeter-results/ + jmeter-report/ + baselines/ +smoke-test-results ← workspace/测试报告/(冒烟阶段全部) +regression-test-results ← workspace/测试报告/(回归阶段全部,含 coverage) +performance-test-results ← workspace/测试报告/jmeter-results/ + jmeter-report/ + baselines/ ``` 下载方式:Actions 页面 → 进入对应 run → 底部 Artifacts 区。 @@ -178,7 +178,7 @@ archiveArtifacts 已配置: ```text **/*.xml, **/*.log, **/*.png, **/*.json -+ workspace/执行日志/jmeter-results/**, jmeter-report/**, baselines/** ++ workspace/测试报告/jmeter-results/**, jmeter-report/**, baselines/** ``` 下载方式:构建页面 → Build Artifacts 区。 @@ -222,12 +222,12 @@ https://{用户名}.github.io/{仓库名}/ workspace/测试计划/test_plan_{项目}_{版本}.md workspace/测试用例/testcases_{模块}_{版本}.xlsx workspace/测试报告/测试报告_{版本}.docx -workspace/执行日志/baselines/perf_baseline.json ← 性能基线必归档(跨版本对比) +workspace/测试报告/baselines/perf_baseline.json ← 性能基线必归档(跨版本对比) ``` **不归档**(含敏感或体积大): - `workspace/测试数据/test_data.json`(含账号密码) -- `workspace/执行日志/截图/`(体积大) +- `workspace/测试报告/截图/`(体积大) - `workspace/测试报告/allure-results/` 原始数据(用 allure-report 静态版即可) - `.env` diff --git "a/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" "b/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" index fdab2d7..6d2d97b 100644 --- "a/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" +++ "b/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" @@ -229,9 +229,9 @@ Bug 管理(BugTracker:默认禅道,可换) → 报告生成(Allure + JMete 特点: - 自动分析代码变更影响范围(git diff + `workspace/regression_modules.yaml` 配置化) -- 历史结果对比(从 `workspace/执行日志/history/` 读 junit-xml) +- 历史结果对比(从 `workspace/测试报告/history/` 读 junit-xml) - Flaky 测试检测和隔离(`utils/flaky_detector`) -- JMeter 性能验证 + 基线对比(`workspace/执行日志/baselines/perf_baseline.json`) +- JMeter 性能验证 + 基线对比(`workspace/测试报告/baselines/perf_baseline.json`) --- @@ -395,7 +395,7 @@ severity / pri 映射:1=P0 / 2=P1 / 3=P2 / 4=P3(与 `utils/zentao_bug_manage [test-executor 执行,test-lead 监控] > 测试失败的截图在哪里? - [报告 workspace/执行日志/截图/ 目录] + [报告 workspace/测试报告/截图/ 目录] ``` --- @@ -465,7 +465,7 @@ python -m utils.prd_loader docs/PRD.pdf --detect --save-text workspace/需求分 **关键提交物一句话**: - 开测前 → `workspace/测试计划/test_plan_*.md` - 测试结束 → `workspace/测试报告/测试报告_*.docx` + 3 个 HTML 报告(Allure / JMeter / Coverage) -- Bug → 禅道在线 + `workspace/执行日志/regression_summary.json` +- Bug → 禅道在线 + `workspace/测试报告/regression_summary.json` --- @@ -486,7 +486,7 @@ workspace/ │ │ ├── pages/ api/ tests/ scripts/ │ └── jmeter/ ← JMeter JMX 文件 ├── regression_modules.yaml ← 回归范围配置(可选) -└── 执行日志/ +└── 测试报告/ ├── allure-results/ ← Allure 原始数据 ├── allure-report/ ← Allure HTML ├── jmeter-results/result.jtl @@ -510,8 +510,8 @@ pytest -m "p0" -n 2 --timeout=60 -v # P0+P1 并行回归(开 reruns + 覆盖率) APP_SRC="${APP_SRC_PATH:-./src}" pytest -m "p0 or p1" -n 4 --reruns=2 --reruns-delay=5 --timeout=120 \ - --cov="${APP_SRC}" --cov-report=html:workspace/执行日志/coverage-report \ - --cov-report=xml:workspace/执行日志/coverage.xml --cov-fail-under=80 + --cov="${APP_SRC}" --cov-report=html:workspace/测试报告/coverage-report \ + --cov-report=xml:workspace/测试报告/coverage.xml --cov-fail-under=80 # 仅运行登录模块(marker 已在 pytest.ini 注册) pytest -m "login and (p0 or p1)" -v @@ -564,7 +564,7 @@ pytest -m "smoke" -v ```text > 这次回归测试和上次相比,有哪些新增失败? -[regression-test 自动从 workspace/执行日志/history/ 读取 junit-xml 对比] +[regression-test 自动从 workspace/测试报告/history/ 读取 junit-xml 对比] ``` ### Q:Flaky 测试如何处理? @@ -601,9 +601,9 @@ CI 默认 `ci_quick` 模式(5 并发,门禁 TPS≥20)。完整 50 并发 ```bash python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode full \ - --baseline workspace/执行日志/baselines/perf_baseline.json \ + --baseline workspace/测试报告/baselines/perf_baseline.json \ --update-baseline ``` @@ -636,9 +636,9 @@ python -m utils.jmeter_result_parser \ 1. `workspace/测试用例/*.xlsx` 和 `workspace/自动化脚本/` 提交到 Git 2. `workspace/regression_modules.yaml` 提交到 Git(回归范围配置) -3. `workspace/执行日志/baselines/perf_baseline.json` 提交到 Git(性能基线) +3. `workspace/测试报告/baselines/perf_baseline.json` 提交到 Git(性能基线) 4. `workspace/测试数据/*.json` **不提交**(含敏感数据 + 频繁变化) -5. `workspace/执行日志/`(除 baselines 外)**不提交** +5. `workspace/测试报告/`(除 baselines 外)**不提交** 6. `.env` **不提交**(含密码) 7. Allure 报告通过 CI/CD 自动发布到 GitHub Pages(公网)或内部静态服务器 diff --git "a/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" "b/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" index 344b106..e0fa27d 100644 --- "a/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" +++ "b/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" @@ -105,14 +105,14 @@ $dirs = @( "$PROJECT_ROOT\workspace\自动化脚本\python\tests", "$PROJECT_ROOT\workspace\自动化脚本\python\scripts", "$PROJECT_ROOT\workspace\自动化脚本\jmeter", - "$PROJECT_ROOT\workspace\执行日志\allure-results", - "$PROJECT_ROOT\workspace\执行日志\jmeter-results", - "$PROJECT_ROOT\workspace\执行日志\jmeter-report", - "$PROJECT_ROOT\workspace\执行日志\coverage-report", - "$PROJECT_ROOT\workspace\执行日志\baselines", - "$PROJECT_ROOT\workspace\执行日志\history", - "$PROJECT_ROOT\workspace\执行日志\截图", - "$PROJECT_ROOT\workspace\执行日志\报告" + "$PROJECT_ROOT\workspace\测试报告\allure-results", + "$PROJECT_ROOT\workspace\测试报告\jmeter-results", + "$PROJECT_ROOT\workspace\测试报告\jmeter-report", + "$PROJECT_ROOT\workspace\测试报告\coverage-report", + "$PROJECT_ROOT\workspace\测试报告\baselines", + "$PROJECT_ROOT\workspace\测试报告\history", + "$PROJECT_ROOT\workspace\测试报告\截图", + "$PROJECT_ROOT\workspace\测试报告\报告" ) foreach ($d in $dirs) { New-Item -ItemType Directory -Force -Path $d | Out-Null } @@ -299,7 +299,7 @@ mkdir -p "$PROJECT_ROOT"/src mkdir -p "$PROJECT_ROOT"/workspace/{测试计划,需求分析,测试用例,测试数据} mkdir -p "$PROJECT_ROOT"/workspace/自动化脚本/python/{pages,api,tests,scripts} mkdir -p "$PROJECT_ROOT"/workspace/自动化脚本/jmeter -mkdir -p "$PROJECT_ROOT"/workspace/执行日志/{allure-results,jmeter-results,jmeter-report,coverage-report,baselines,history,截图,报告} +mkdir -p "$PROJECT_ROOT"/workspace/测试报告/{allure-results,jmeter-results,jmeter-report,coverage-report,baselines,history,截图,报告} # ===== 4. 拷贝 Agent / Skill 定义(显式列名)===== for f in 01-测试主管 02-需求分析 03-用例设计 04-环境管理 05-数据准备 06-自动化脚本 07-测试执行 08-Bug管理 09-报告生成 10-移动测试 11-桌面测试 12-视觉游戏测试 13-系统集成测试 14-AI模型测试; do @@ -465,7 +465,7 @@ your-test-project/ │ ├── 测试用例/ │ ├── 测试数据/ │ ├── 自动化脚本/python/ jmeter/ -│ └── 执行日志/ +│ └── 测试报告/ │ ├── allure-results/ 截图/ │ ├── jmeter-results/ jmeter-report/ │ ├── coverage-report/ diff --git "a/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" "b/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" index a581bfd..9dd271e 100644 --- "a/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" +++ "b/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" @@ -17,7 +17,7 @@ | `.claude/agents/*.md` | 16 个 Agent 定义(核心 9 + 平台扩展 5 + 垂直领域 2) | ✅ | | `.claude/skills/*.md` | 32 个 Skill 定义(通用 8 + 平台 5 + 渗透 7 + 车载 5 + ECC 6 + 探索 1) | ✅ | | `workspace/regression_modules.yaml` | 回归范围模块映射 | ⚪ 可选 | -| `workspace/执行日志/baselines/perf_baseline.json` | 性能基线 | ⚪ 自动生成(首次 release 跑 full 后) | +| `workspace/测试报告/baselines/perf_baseline.json` | 性能基线 | ⚪ 自动生成(首次 release 跑 full 后) | | `.github/workflows/test.yml` | GitHub Actions 流水线 | ⚪ 仅用 GitHub 时 | | `Jenkinsfile` | Jenkins 流水线 | ⚪ 仅用 Jenkins 时 | | `src/` | 被测系统源码(cov 指向) | ✅ 项目自有,非模板提供 | @@ -227,7 +227,7 @@ modules: --- -## 8. `workspace/执行日志/baselines/perf_baseline.json` +## 8. `workspace/测试报告/baselines/perf_baseline.json` 性能基线文件,**首次自动生成**。生成条件: @@ -239,9 +239,9 @@ modules: ```bash python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode full \ - --baseline workspace/执行日志/baselines/perf_baseline.json \ + --baseline workspace/测试报告/baselines/perf_baseline.json \ --update-baseline ``` diff --git a/docs/tutorial/TUTORIAL.md b/docs/tutorial/TUTORIAL.md index 4dbad8b..65e8209 100644 --- a/docs/tutorial/TUTORIAL.md +++ b/docs/tutorial/TUTORIAL.md @@ -111,5 +111,5 @@ tagent serve 1. 加 `--debug` flag 看详细日志 2. 跑 `tagent doctor` 检查环境 -3. 看 `workspace/执行日志/` 下的 JSON/XML 产物 +3. 看 `workspace/测试报告/` 下的 JSON/XML 产物 4. GitHub Issues: https://github.com/Wool-xing/Test-Agent/issues diff --git a/install.py b/install.py index d17d857..b494730 100644 --- a/install.py +++ b/install.py @@ -292,7 +292,7 @@ def create_dirs(project_root): os.path.join("workspace", "测试报告", "coverage-report"), os.path.join("workspace", "测试报告", "baselines"), os.path.join("workspace", "测试报告", "history"), - os.path.join("workspace", "截图"), + os.path.join("workspace", "测试报告", "screenshots"), os.path.join("workspace", "自动化脚本", "python", "pages"), os.path.join("workspace", "自动化脚本", "python", "api"), os.path.join("workspace", "自动化脚本", "python", "tests"), diff --git a/runtime/api/main.py b/runtime/api/main.py index 426ebcb..bf90353 100644 --- a/runtime/api/main.py +++ b/runtime/api/main.py @@ -189,8 +189,8 @@ def list_history() -> dict: ws = get_settings().workspace_dir runs: list[dict] = [] - # Scan workspace/_demo and workspace/执行日志 for run outputs - for scan_dir in [ws / "_demo", ws / "执行日志"]: + # Scan workspace/_demo and workspace/测试报告 for run outputs + for scan_dir in [ws / "_demo", ws / "测试报告"]: if not scan_dir.exists(): continue for f in sorted(scan_dir.rglob("*.json"), reverse=True): diff --git a/runtime/cli/commands/demo.py b/runtime/cli/commands/demo.py index 14fc61a..911ce7d 100644 --- a/runtime/cli/commands/demo.py +++ b/runtime/cli/commands/demo.py @@ -99,7 +99,7 @@ def demo( console.print("\n[bold]Step 4/4 · Artifacts[/]") artifacts = [] - for d in (Path("workspace/测试用例"), Path("workspace/测试报告"), Path("workspace/执行日志")): + for d in (Path("workspace/测试用例"), Path("workspace/测试报告")): if d.exists(): for f in sorted(d.glob("**/*")): if f.is_file() and not f.name.startswith("_"): diff --git a/runtime/learning_loop/INDEX.md b/runtime/learning_loop/INDEX.md index 0077d45..54f612d 100644 --- a/runtime/learning_loop/INDEX.md +++ b/runtime/learning_loop/INDEX.md @@ -27,5 +27,5 @@ learning_loop/curator (协调:何时跑+谁来跑) ↓ 触发 darwin-skill/SKILL.md (执行:8 维评分+棘轮) ↓ 落 -workspace/执行日志/skill-evolution/results.tsv +workspace/测试报告/skill-evolution/results.tsv ``` diff --git a/runtime/marketplace/installer.py b/runtime/marketplace/installer.py index 2981650..dfafc00 100644 --- a/runtime/marketplace/installer.py +++ b/runtime/marketplace/installer.py @@ -33,7 +33,7 @@ def _archive_dir() -> Path: def _decisions_log(action: str, name: str, payload: dict) -> Path: s = get_settings() - d = s.resolve(s.workspace_dir) / "执行日志" / "decisions" + d = s.resolve(s.workspace_dir) / "测试报告" / "decisions" d.mkdir(parents=True, exist_ok=True) ts = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") p = d / f"{ts}_marketplace_{action}_{name}.json" diff --git a/runtime/mcp/base.py b/runtime/mcp/base.py index de1fb41..3aec9dc 100644 --- a/runtime/mcp/base.py +++ b/runtime/mcp/base.py @@ -28,7 +28,7 @@ def new_run_id(prefix: str = "mcp") -> str: def _decisions_dir() -> Path: s = get_settings() - d = s.resolve(s.workspace_dir) / "执行日志" / "decisions" + d = s.resolve(s.workspace_dir) / "测试报告" / "decisions" d.mkdir(parents=True, exist_ok=True) return d diff --git a/runtime/observability/audit.py b/runtime/observability/audit.py index e62ec0d..2640400 100644 --- a/runtime/observability/audit.py +++ b/runtime/observability/audit.py @@ -14,7 +14,7 @@ from loguru import logger -_DEFAULT_DIR = Path("workspace/执行日志/audit") +_DEFAULT_DIR = Path("workspace/测试报告/audit") _lock = threading.Lock() diff --git a/runtime/observability/dashboard.py b/runtime/observability/dashboard.py index 1afa3cc..4cfab49 100644 --- a/runtime/observability/dashboard.py +++ b/runtime/observability/dashboard.py @@ -15,7 +15,7 @@ def scan_runs(workspace_dir: Path) -> list[dict[str, Any]]: """Scan workspace for completed run summaries (JSON files with 'total' key).""" all_runs: list[dict[str, Any]] = [] - for scan_dir in [workspace_dir / "_demo", workspace_dir / "执行日志"]: + for scan_dir in [workspace_dir / "_demo", workspace_dir / "测试报告"]: if not scan_dir.exists(): continue for f in scan_dir.rglob("*.json"): diff --git a/runtime/orchestrator/agents/automation_engineer.py b/runtime/orchestrator/agents/automation_engineer.py index d3d67aa..69fde83 100644 --- a/runtime/orchestrator/agents/automation_engineer.py +++ b/runtime/orchestrator/agents/automation_engineer.py @@ -63,7 +63,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "automation_scripts_plan.json" + return ctx.workspace / "测试报告" / "automation_scripts_plan.json" def summary(self, output: dict[str, Any]) -> str: scripts = output.get("scripts", []) diff --git a/runtime/orchestrator/agents/automotive_tester.py b/runtime/orchestrator/agents/automotive_tester.py index 858f100..c6a6190 100644 --- a/runtime/orchestrator/agents/automotive_tester.py +++ b/runtime/orchestrator/agents/automotive_tester.py @@ -215,7 +215,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "automotive_test_plan.json" + return ctx.workspace / "测试报告" / "automotive_test_plan.json" def summary(self, output: dict[str, Any]) -> str: cases = len(output.get("test_cases", [])) diff --git a/runtime/orchestrator/agents/bug_manager.py b/runtime/orchestrator/agents/bug_manager.py index 01b854a..83e6c2f 100644 --- a/runtime/orchestrator/agents/bug_manager.py +++ b/runtime/orchestrator/agents/bug_manager.py @@ -103,7 +103,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "bug_drafts.json" + return ctx.workspace / "测试报告" / "bug_drafts.json" def summary(self, output: dict[str, Any]) -> str: s = output.get("summary", {}) diff --git a/runtime/orchestrator/agents/env_manager.py b/runtime/orchestrator/agents/env_manager.py index b766843..d8855b4 100644 --- a/runtime/orchestrator/agents/env_manager.py +++ b/runtime/orchestrator/agents/env_manager.py @@ -94,7 +94,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "env_checklist.json" + return ctx.workspace / "测试报告" / "env_checklist.json" def summary(self, output: dict[str, Any]) -> str: checks = len(output.get("env_checks", [])) diff --git a/runtime/orchestrator/agents/mobile_tester.py b/runtime/orchestrator/agents/mobile_tester.py index a5b9fd3..d257843 100644 --- a/runtime/orchestrator/agents/mobile_tester.py +++ b/runtime/orchestrator/agents/mobile_tester.py @@ -111,7 +111,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "mobile_test_plan.json" + return ctx.workspace / "测试报告" / "mobile_test_plan.json" def summary(self, output: dict[str, Any]) -> str: cases = len(output.get("test_cases", [])) diff --git a/runtime/orchestrator/agents/pentest_tester.py b/runtime/orchestrator/agents/pentest_tester.py index f9168f7..f4f3ac1 100644 --- a/runtime/orchestrator/agents/pentest_tester.py +++ b/runtime/orchestrator/agents/pentest_tester.py @@ -182,7 +182,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "pentest_plan.json" + return ctx.workspace / "测试报告" / "pentest_plan.json" def summary(self, output: dict[str, Any]) -> str: domains = len(output.get("vuln_assessment_phase", {})) diff --git a/runtime/orchestrator/agents/requirements_analyst.py b/runtime/orchestrator/agents/requirements_analyst.py index d34c2b0..148f0b6 100644 --- a/runtime/orchestrator/agents/requirements_analyst.py +++ b/runtime/orchestrator/agents/requirements_analyst.py @@ -55,7 +55,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "requirements_summary.json" + return ctx.workspace / "测试报告" / "requirements_summary.json" def summary(self, output: dict[str, Any]) -> str: feats = output.get("features", []) diff --git a/runtime/orchestrator/agents/system_tester.py b/runtime/orchestrator/agents/system_tester.py index 53f7cc8..800b3ca 100644 --- a/runtime/orchestrator/agents/system_tester.py +++ b/runtime/orchestrator/agents/system_tester.py @@ -165,7 +165,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "system_test_plan.json" + return ctx.workspace / "测试报告" / "system_test_plan.json" def summary(self, output: dict[str, Any]) -> str: cases = len(output.get("test_cases", [])) diff --git a/runtime/orchestrator/agents/test_executor.py b/runtime/orchestrator/agents/test_executor.py index fde614e..81d870f 100644 --- a/runtime/orchestrator/agents/test_executor.py +++ b/runtime/orchestrator/agents/test_executor.py @@ -56,7 +56,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "execution_plan.json" + return ctx.workspace / "测试报告" / "execution_plan.json" def summary(self, output: dict[str, Any]) -> str: plan = output.get("execution_plan", []) diff --git a/runtime/orchestrator/agents/test_lead.py b/runtime/orchestrator/agents/test_lead.py index f621a5f..190796b 100644 --- a/runtime/orchestrator/agents/test_lead.py +++ b/runtime/orchestrator/agents/test_lead.py @@ -127,7 +127,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: def output_file(self, ctx: RunnerContext) -> Path | None: import uuid - return ctx.workspace / "执行日志" / "decisions" / f"final_verdict_{uuid.uuid4().hex[:12]}.json" + return ctx.workspace / "测试报告" / "decisions" / f"final_verdict_{uuid.uuid4().hex[:12]}.json" def summary(self, output: dict[str, Any]) -> str: return f"决策:{output.get('verdict', '?').upper()} · {output.get('summary_zh', '')[:60]}" diff --git a/runtime/orchestrator/agents/visual_tester.py b/runtime/orchestrator/agents/visual_tester.py index 72298e3..bd9b64b 100644 --- a/runtime/orchestrator/agents/visual_tester.py +++ b/runtime/orchestrator/agents/visual_tester.py @@ -114,7 +114,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "visual_test_plan.json" + return ctx.workspace / "测试报告" / "visual_test_plan.json" def summary(self, output: dict[str, Any]) -> str: points = len(output.get("visual_test_points", [])) diff --git a/runtime/orchestrator/skills/eval_harness.py b/runtime/orchestrator/skills/eval_harness.py index 194acdf..22ddf48 100644 --- a/runtime/orchestrator/skills/eval_harness.py +++ b/runtime/orchestrator/skills/eval_harness.py @@ -66,7 +66,7 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "seed_fixed": 42\n' " },\n" ' "phases": [\n' - ' {"phase": 1, "name": "eval_config", "estimated_min": 5, "config": {"capture_mode": "opt-in", "output_dir": "workspace/执行日志/eval/", "seed": 42, "k_samples": 10}, "depends_on": []},\n' + ' {"phase": 1, "name": "eval_config", "estimated_min": 5, "config": {"capture_mode": "opt-in", "output_dir": "workspace/测试报告/eval/", "seed": 42, "k_samples": 10}, "depends_on": []},\n' ' {"phase": 2, "name": "pass_at_k", "estimated_min": 20, "cases": [{"test_id": "string", "prompt": "string", "expected": "string", "k": 10, "threshold": 0.7}], "depends_on": ["eval_config"]},\n' ' {"phase": 3, "name": "stability_check", "estimated_min": 15, "cases": [{"test_id": "string", "prompt": "string", "runs": 5, "metric": "top1_consistency|jaccard_k|semantic_equiv"}], "depends_on": ["eval_config"]},\n' ' {"phase": 4, "name": "latency_check", "estimated_min": 10, "cases": [{"test_id": "string", "endpoint": "string", "runs": 100, "metrics": ["p50_ms", "p95_ms", "p99_ms"]}], "depends_on": ["eval_config"]},\n' @@ -81,10 +81,10 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "pii_leak": 0\n' " },\n" ' "outputs": {\n' - ' "eval_dir": "workspace/执行日志/eval/",\n' - ' "capture_dir": "workspace/执行日志/eval/captures/",\n' - ' "replay_dir": "workspace/执行日志/eval/replays/",\n' - ' "report_dir": "workspace/执行日志/eval/reports/",\n' + ' "eval_dir": "workspace/测试报告/eval/",\n' + ' "capture_dir": "workspace/测试报告/eval/captures/",\n' + ' "replay_dir": "workspace/测试报告/eval/replays/",\n' + ' "report_dir": "workspace/测试报告/eval/reports/",\n' ' "allure_dir": "workspace/Allure/eval/{run_id}/"\n' " },\n" ' "risks": ["string,如 黄金集过小致 overfit / prompt 顺序敏感 / 非确定性模型 top-1 随机"],\n' @@ -112,7 +112,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "config": { "capture_mode": "opt-in", - "output_dir": "workspace/执行日志/eval/", + "output_dir": "workspace/测试报告/eval/", "seed": 42, "k_samples": 10, }, @@ -156,8 +156,8 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/eval/selftest-20260516-000005/", - "workspace/执行日志/eval/reports/", - "workspace/执行日志/eval/captures/", + "workspace/测试报告/eval/reports/", + "workspace/测试报告/eval/captures/", ], "depends_on": ["pass_at_k", "stability_check", "latency_check"], }, @@ -171,10 +171,10 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "pii_leak": 0, }, "outputs": { - "eval_dir": "workspace/执行日志/eval/", - "capture_dir": "workspace/执行日志/eval/captures/", - "replay_dir": "workspace/执行日志/eval/replays/", - "report_dir": "workspace/执行日志/eval/reports/", + "eval_dir": "workspace/测试报告/eval/", + "capture_dir": "workspace/测试报告/eval/captures/", + "replay_dir": "workspace/测试报告/eval/replays/", + "report_dir": "workspace/测试报告/eval/reports/", "allure_dir": "workspace/Allure/eval/selftest-20260516-000005/", }, "risks": [ @@ -189,7 +189,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "eval_harness_plan.json" + return ctx.workspace / "测试报告" / "eval_harness_plan.json" def summary(self, output: dict[str, Any]) -> str: phases = len(output.get("phases", [])) diff --git a/runtime/orchestrator/skills/mobile_test.py b/runtime/orchestrator/skills/mobile_test.py index 402e06b..4bc3cd0 100644 --- a/runtime/orchestrator/skills/mobile_test.py +++ b/runtime/orchestrator/skills/mobile_test.py @@ -89,11 +89,11 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "outputs": {\n' ' "test_scripts_dir": "workspace/自动化脚本/python/mobile/",\n' ' "miniprogram_dir": "workspace/自动化脚本/python/miniprogram/",\n' - ' "perf_dir": "workspace/执行日志/mobile-perf/",\n' - ' "logcat_dir": "workspace/执行日志/logcat/",\n' - ' "ios_syslog_dir": "workspace/执行日志/ios-syslog/",\n' - ' "screenshot_dir": "workspace/执行日志/截图/",\n' - ' "monkey_dir": "workspace/执行日志/monkey/",\n' + ' "perf_dir": "workspace/测试报告/mobile-perf/",\n' + ' "logcat_dir": "workspace/测试报告/logcat/",\n' + ' "ios_syslog_dir": "workspace/测试报告/ios-syslog/",\n' + ' "screenshot_dir": "workspace/测试报告/screenshots/",\n' + ' "monkey_dir": "workspace/测试报告/monkey/",\n' ' "allure_dir": "workspace/Allure/mobile/{run_id}/"\n' " },\n" ' "risks": ["string,如 设备断连 / Appium session 超时 / 云真机 API 限速"],\n' @@ -178,9 +178,9 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/mobile/selftest-20260516-000002/", - "workspace/执行日志/mobile-perf/", - "workspace/执行日志/logcat/", - "workspace/执行日志/截图/", + "workspace/测试报告/mobile-perf/", + "workspace/测试报告/logcat/", + "workspace/测试报告/screenshots/", ], "depends_on": ["test_execution"], }, @@ -214,11 +214,11 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "outputs": { "test_scripts_dir": "workspace/自动化脚本/python/mobile/", "miniprogram_dir": "workspace/自动化脚本/python/miniprogram/", - "perf_dir": "workspace/执行日志/mobile-perf/", - "logcat_dir": "workspace/执行日志/logcat/", - "ios_syslog_dir": "workspace/执行日志/ios-syslog/", - "screenshot_dir": "workspace/执行日志/截图/", - "monkey_dir": "workspace/执行日志/monkey/", + "perf_dir": "workspace/测试报告/mobile-perf/", + "logcat_dir": "workspace/测试报告/logcat/", + "ios_syslog_dir": "workspace/测试报告/ios-syslog/", + "screenshot_dir": "workspace/测试报告/screenshots/", + "monkey_dir": "workspace/测试报告/monkey/", "allure_dir": "workspace/Allure/mobile/selftest-20260516-000002/", }, "risks": [ @@ -233,7 +233,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "mobile_test_plan.json" + return ctx.workspace / "测试报告" / "mobile_test_plan.json" def summary(self, output: dict[str, Any]) -> str: phases = len(output.get("phases", [])) diff --git a/runtime/orchestrator/skills/pentest_coordinator.py b/runtime/orchestrator/skills/pentest_coordinator.py index 6d9ef35..a70117a 100644 --- a/runtime/orchestrator/skills/pentest_coordinator.py +++ b/runtime/orchestrator/skills/pentest_coordinator.py @@ -77,7 +77,7 @@ def user_prompt(self, ctx: RunnerContext) -> str: " },\n" ' "outputs": {\n' ' "report_path": "workspace/渗透报告/pentest_{target}_{date}.md",\n' - ' "evidence_dir": "workspace/执行日志/evidence/{run_id}/",\n' + ' "evidence_dir": "workspace/测试报告/evidence/{run_id}/",\n' ' "bug_tickets_format": "CVSS → P0-P3 (主宪章 §18-4)",\n' ' "allure_report": "workspace/Allure/pentest/{run_id}/"\n' " },\n" @@ -152,7 +152,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 }, "outputs": { "report_path": "workspace/渗透报告/pentest_staging.example.com_20260516.md", - "evidence_dir": "workspace/执行日志/evidence/selftest-20260516-000001/", + "evidence_dir": "workspace/测试报告/evidence/selftest-20260516-000001/", "bug_tickets_format": "CVSS 9-10=P0 / 7-8.9=P1 / 4-6.9=P2 / <4=P3 (主宪章 §18-4)", "allure_report": "workspace/Allure/pentest/selftest-20260516-000001/", }, @@ -173,7 +173,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "pentest_coordinator_plan.json" + return ctx.workspace / "测试报告" / "pentest_coordinator_plan.json" def summary(self, output: dict[str, Any]) -> str: phases = len(output.get("phases", [])) diff --git a/runtime/orchestrator/skills/system_test.py b/runtime/orchestrator/skills/system_test.py index fff31fd..86c2c14 100644 --- a/runtime/orchestrator/skills/system_test.py +++ b/runtime/orchestrator/skills/system_test.py @@ -84,10 +84,10 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "mq": {"utils": ["mq_helper"], "optional": false}\n' " },\n" ' "outputs": {\n' - ' "iot_dir": "workspace/执行日志/iot-logs/",\n' - ' "media_dir": "workspace/执行日志/media-logs/",\n' - ' "trace_dir": "workspace/执行日志/trace-logs/",\n' - ' "mq_dir": "workspace/执行日志/mq-logs/",\n' + ' "iot_dir": "workspace/测试报告/iot-logs/",\n' + ' "media_dir": "workspace/测试报告/media-logs/",\n' + ' "trace_dir": "workspace/测试报告/trace-logs/",\n' + ' "mq_dir": "workspace/测试报告/mq-logs/",\n' ' "allure_dir": "workspace/Allure/system/{run_id}/"\n' " },\n" ' "risks": ["string,如 SSH 超时 / 串口断连 / MQTT broker 离线 / Kafka offset 丢失"],\n' @@ -172,10 +172,10 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/system/selftest-20260516-000004/", - "workspace/执行日志/iot-logs/", - "workspace/执行日志/media-logs/", - "workspace/执行日志/trace-logs/", - "workspace/执行日志/mq-logs/", + "workspace/测试报告/iot-logs/", + "workspace/测试报告/media-logs/", + "workspace/测试报告/trace-logs/", + "workspace/测试报告/mq-logs/", ], "depends_on": ["iot_test", "media_validation", "tracing_validation", "mq_validation"], }, @@ -199,10 +199,10 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "mq": {"utils": ["mq_helper"], "optional": False}, }, "outputs": { - "iot_dir": "workspace/执行日志/iot-logs/", - "media_dir": "workspace/执行日志/media-logs/", - "trace_dir": "workspace/执行日志/trace-logs/", - "mq_dir": "workspace/执行日志/mq-logs/", + "iot_dir": "workspace/测试报告/iot-logs/", + "media_dir": "workspace/测试报告/media-logs/", + "trace_dir": "workspace/测试报告/trace-logs/", + "mq_dir": "workspace/测试报告/mq-logs/", "allure_dir": "workspace/Allure/system/selftest-20260516-000004/", }, "risks": [ @@ -218,7 +218,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "system_test_plan.json" + return ctx.workspace / "测试报告" / "system_test_plan.json" def summary(self, output: dict[str, Any]) -> str: phases = len(output.get("phases", [])) diff --git a/runtime/orchestrator/skills/visual_test.py b/runtime/orchestrator/skills/visual_test.py index 8c642c1..2f51e4c 100644 --- a/runtime/orchestrator/skills/visual_test.py +++ b/runtime/orchestrator/skills/visual_test.py @@ -87,9 +87,9 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "outputs": {\n' ' "template_dir": "workspace/自动化脚本/python/visual/images/",\n' ' "baseline_dir": "workspace/自动化脚本/python/visual/baselines/",\n' - ' "diff_dir": "workspace/执行日志/visual-diffs/",\n' - ' "ocr_dir": "workspace/执行日志/visual-ocr/",\n' - ' "screenshot_dir": "workspace/执行日志/visual-screenshots/",\n' + ' "diff_dir": "workspace/测试报告/visual-diffs/",\n' + ' "ocr_dir": "workspace/测试报告/visual-ocr/",\n' + ' "screenshot_dir": "workspace/测试报告/screenshots/visual/",\n' ' "allure_dir": "workspace/Allure/visual/{run_id}/"\n' " },\n" ' "risks": ["string,如 设备断连 / 分辨率差异致误报 / OCR 字体缺失 / 动态内容 false positive"],\n' @@ -156,8 +156,8 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/visual/selftest-20260516-000003/", - "workspace/执行日志/visual-diffs/", - "workspace/执行日志/visual-screenshots/", + "workspace/测试报告/visual-diffs/", + "workspace/测试报告/screenshots/visual/", ], "depends_on": ["visual_regression"], }, @@ -182,9 +182,9 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "outputs": { "template_dir": "workspace/自动化脚本/python/visual/images/", "baseline_dir": "workspace/自动化脚本/python/visual/baselines/", - "diff_dir": "workspace/执行日志/visual-diffs/", - "ocr_dir": "workspace/执行日志/visual-ocr/", - "screenshot_dir": "workspace/执行日志/visual-screenshots/", + "diff_dir": "workspace/测试报告/visual-diffs/", + "ocr_dir": "workspace/测试报告/visual-ocr/", + "screenshot_dir": "workspace/测试报告/screenshots/visual/", "allure_dir": "workspace/Allure/visual/selftest-20260516-000003/", }, "risks": [ @@ -199,7 +199,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 } def output_file(self, ctx: RunnerContext) -> Path | None: - return ctx.workspace / "执行日志" / "visual_test_plan.json" + return ctx.workspace / "测试报告" / "visual_test_plan.json" def summary(self, output: dict[str, Any]) -> str: phases = len(output.get("phases", [])) diff --git a/runtime/tests/test_router_real.py b/runtime/tests/test_router_real.py index bd1020b..838fb3e 100644 --- a/runtime/tests/test_router_real.py +++ b/runtime/tests/test_router_real.py @@ -65,7 +65,7 @@ def _decisions_log(record: dict) -> Path: """Charter §18-12 决策可追溯: log each routing decision.""" s = get_settings() - d = s.resolve(s.workspace_dir) / "执行日志" / "decisions" + d = s.resolve(s.workspace_dir) / "测试报告" / "decisions" d.mkdir(parents=True, exist_ok=True) ts = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) target = d / f"{ts}_router_real_test_{record.get('sample_id', 'x')}.json" diff --git a/scripts/_demo-commands.sh b/scripts/_demo-commands.sh index 530e608..8f788c2 100644 --- a/scripts/_demo-commands.sh +++ b/scripts/_demo-commands.sh @@ -25,7 +25,7 @@ step() { } # 清干净(录制前) -rm -rf workspace/_demo workspace/执行日志/*.json workspace/测试用例/_smoke_out workspace/_init_smoke 2>/dev/null || true +rm -rf workspace/_demo workspace/测试报告/*.json workspace/测试用例/_smoke_out workspace/_init_smoke 2>/dev/null || true # Step 1 · init step "Step 1/4 · 一键初始化(stub LLM,0 API key)" @@ -53,8 +53,8 @@ sleep 3 # Outro · 看产物 step "产物清单" -prompt "ls workspace/执行日志/*.json" -ls workspace/执行日志/*.json 2>/dev/null +prompt "ls workspace/测试报告/*.json" +ls workspace/测试报告/*.json 2>/dev/null sleep 2 prompt "cat workspace/测试报告/decisions/final_verdict_*.json | head -10" diff --git a/skills/ai-test.md b/skills/ai-test.md index 8b1e705..befbcc0 100644 --- a/skills/ai-test.md +++ b/skills/ai-test.md @@ -65,7 +65,7 @@ pytest -m "ai and llm" -v ## 输出文件 ```text -workspace/执行日志/ +workspace/测试报告/ ├── ai-eval/ ├── ai-drift/ ├── ai-fairness/ diff --git a/skills/data-preparation.md b/skills/data-preparation.md index 584a581..d9b6132 100644 --- a/skills/data-preparation.md +++ b/skills/data-preparation.md @@ -171,7 +171,7 @@ atexit.register(manager.cleanup) |------|------|--------| | `workspace/测试数据/test_data.json` | pytest 功能测试账号(conftest fixture 自动加载) | conftest / automation-engineer | | `workspace/测试数据/jmeter_users.csv` | JMeter 参数化数据 | jmeter-script-gen / test-executor | -| `workspace/执行日志/数据准备报告_{日期}.json` | 数据准备详情 | test-lead | +| `workspace/测试报告/数据准备报告_{日期}.json` | 数据准备详情 | test-lead | ## ⚠️ 数据安全要求 diff --git a/skills/desktop-test.md b/skills/desktop-test.md index bb440eb..c0ee8bf 100644 --- a/skills/desktop-test.md +++ b/skills/desktop-test.md @@ -88,7 +88,7 @@ python -m utils.websocket_helper load \ ```bash python -m utils.desktop_driver collect-perf \ --pid --duration 60 \ - --output workspace/执行日志/desktop-perf/ + --output workspace/测试报告/desktop-perf/ ``` ## 质量门禁 @@ -116,7 +116,7 @@ steps: ```text workspace/ ├── 自动化脚本/python/desktop/{windows,macos,electron}/ -└── 执行日志/ +└── 测试报告/ ├── desktop-screenshots/ ├── desktop-perf/ ├── win-event-log/ diff --git a/skills/jmeter-script-gen.md b/skills/jmeter-script-gen.md index 25d8d52..7d4852c 100644 --- a/skills/jmeter-script-gen.md +++ b/skills/jmeter-script-gen.md @@ -24,7 +24,7 @@ SKILL_IMPL_STATUS: script □ 目标接口信息:URL(解析为 host/protocol/port 三参,不含协议前缀) □ 性能目标:目标 TPS / P95 / 并发数(决定 PERF_MODE) □ workspace/自动化脚本/jmeter/ 目录已存在(conftest 自动建) -□ workspace/执行日志/baselines/perf_baseline.json(基线对比,可选) +□ workspace/测试报告/baselines/perf_baseline.json(基线对比,可选) ``` ## 数据流(与其他 Agent 闭环) @@ -252,7 +252,7 @@ test_user_b9k7,Test@123456,xxxx-xxxx-xxxx-xxxx false - workspace/执行日志/jmeter-results/result.jtl + workspace/测试报告/jmeter-results/result.jtl @@ -300,8 +300,8 @@ test_user_b9k7,Test@123456,xxxx-xxxx-xxxx-xxxx # CI 默认:ci_quick jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/result.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/result.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -310,8 +310,8 @@ jmeter -n \ # 完整压测:full(手动 / release) jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/result.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/result.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -320,7 +320,7 @@ jmeter -n \ # 阶梯加压 jmeter -n \ -t workspace/自动化脚本/jmeter/stepped_load.jmx \ - -l workspace/执行日志/jmeter-results/stepped_result.jtl \ + -l workspace/测试报告/jmeter-results/stepped_result.jtl \ -Jtarget_host="${TARGET_HOST}" ``` @@ -341,14 +341,14 @@ jmeter -n \ ```bash # CI quick python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode ci_quick # Full + 基线对比 + 通过则更新基线 python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode full \ - --baseline workspace/执行日志/baselines/perf_baseline.json \ + --baseline workspace/测试报告/baselines/perf_baseline.json \ --update-baseline ``` @@ -383,8 +383,8 @@ python -m utils.jmeter_result_parser \ "regression_pct": 3.2, "is_regression": false }, - "html_report": "workspace/执行日志/jmeter-report/index.html", - "jtl_file": "workspace/执行日志/jmeter-results/result.jtl" + "html_report": "workspace/测试报告/jmeter-report/index.html", + "jtl_file": "workspace/测试报告/jmeter-results/result.jtl" } ``` @@ -399,7 +399,7 @@ workspace/自动化脚本/jmeter/ workspace/测试数据/ └── jmeter_users.csv # 参数化数据(data-preparer 生成) -workspace/执行日志/ +workspace/测试报告/ ├── jmeter-results/result.jtl # 原始结果(CSV) ├── jmeter-report/index.html # JMeter HTML 可视化 └── baselines/perf_baseline.json @@ -414,7 +414,7 @@ workspace/执行日志/ ✅ 每个请求必须有响应断言(防静默失败) ✅ JSONPostProcessor 提取 Token(不用旧名 JSONPathExtractor) ✅ 登录失败时 If Controller 中止后续请求 -✅ 结果保存到 workspace/执行日志/jmeter-results/ +✅ 结果保存到 workspace/测试报告/jmeter-results/ ✅ 解析与门禁统一调 utils/jmeter_result_parser.py ✅ 性能 Bug 提交给 bug-manager(标题:[性能]-[接口名]-[指标超标]) ``` diff --git a/skills/mobile-test.md b/skills/mobile-test.md index 4ed3351..00926c9 100644 --- a/skills/mobile-test.md +++ b/skills/mobile-test.md @@ -95,7 +95,7 @@ python -m utils.mobile_driver collect-perf \ --platform android \ --package com.example.app \ --duration 60 \ - --output workspace/执行日志/mobile-perf/ + --output workspace/测试报告/mobile-perf/ ``` ### Step 5b:Android Monkey 稳定性(可选,长时压测) @@ -118,9 +118,9 @@ pytest -m "mobile and android and stability" -v ``` monkey 自动产出: -- `workspace/执行日志/monkey/monkey__<时间>.log`(事件序列) -- `workspace/执行日志/monkey/monkey__<时间>.json`(摘要:crash/anr/duration) -- `workspace/执行日志/logcat/logcat_<时间>.log`(同步归档) +- `workspace/测试报告/monkey/monkey__<时间>.log`(事件序列) +- `workspace/测试报告/monkey/monkey__<时间>.json`(摘要:crash/anr/duration) +- `workspace/测试报告/logcat/logcat_<时间>.log`(同步归档) ### Step 6:报告与归档 @@ -183,7 +183,7 @@ driver.orientation = "LANDSCAPE" workspace/ ├── 自动化脚本/python/mobile/ # 移动端 page object + 用例 ├── 自动化脚本/python/miniprogram/ # 小程序用例 -└── 执行日志/ +└── 测试报告/ ├── mobile-perf/ # 性能采集 JSON ├── logcat/ # Android 日志 ├── ios-syslog/ # iOS 日志 diff --git a/skills/pentest-coordinator.md b/skills/pentest-coordinator.md index 31909d1..faa5a23 100644 --- a/skills/pentest-coordinator.md +++ b/skills/pentest-coordinator.md @@ -40,7 +40,7 @@ SKILL_IMPL_STATUS: production ## 输出 - `workspace/渗透报告/pentest_{target}_{date}.md`(仅 PoC 漏洞) -- `workspace/执行日志/evidence/{run_id}/`(HAR / 截图 / 录屏 / req-resp) +- `workspace/测试报告/evidence/{run_id}/`(HAR / 截图 / 录屏 / req-resp) - Bug 单按 CVSS 映射 P0-P3 - Allure 报告(每漏洞一个 case) diff --git a/skills/regression-test.md b/skills/regression-test.md index 88a0aa7..c41a971 100644 --- a/skills/regression-test.md +++ b/skills/regression-test.md @@ -19,8 +19,8 @@ SKILL_IMPL_STATUS: production □ APP_SRC_PATH 指向被测系统源码(覆盖率指向) □ workspace/regression_modules.yaml 配置(git diff 影响分析,可选) □ JMeter 5.6.3 + Java JRE(性能阶段) -□ workspace/执行日志/baselines/perf_baseline.json(基线对比,首次跑会建) -□ workspace/执行日志/history/*.xml(Flaky 检测,至少 2 次执行后才有) +□ workspace/测试报告/baselines/perf_baseline.json(基线对比,首次跑会建) +□ workspace/测试报告/history/*.xml(Flaky 检测,至少 2 次执行后才有) ``` ## 📋 执行流程 @@ -79,11 +79,11 @@ pytest workspace/自动化脚本/python/ \ -n 4 --timeout=120 \ --reruns=2 --reruns-delay=5 \ --cov="${APP_SRC}" \ - --cov-report=html:workspace/执行日志/coverage-report \ - --cov-report=xml:workspace/执行日志/coverage.xml \ + --cov-report=html:workspace/测试报告/coverage-report \ + --cov-report=xml:workspace/测试报告/coverage.xml \ --cov-fail-under=80 \ - --alluredir=workspace/执行日志/regression-allure-results \ - --junitxml=workspace/执行日志/regression-results.xml \ + --alluredir=workspace/测试报告/regression-allure-results \ + --junitxml=workspace/测试报告/regression-results.xml \ --tb=short -q ``` @@ -96,8 +96,8 @@ pytest workspace/自动化脚本/python/ \ ```bash # 归档当前 junit-xml 到 history python -m utils.flaky_detector \ - --archive workspace/执行日志/regression-results.xml \ - --history workspace/执行日志/history \ + --archive workspace/测试报告/regression-results.xml \ + --history workspace/测试报告/history \ --limit 5 # 输出 flaky 候选清单(JSON): # [{"test_id": "...", "fail_rate_pct": 40.0, "history": ["passed","failed",...], "action": "quarantine"}] @@ -114,8 +114,8 @@ python -m utils.flaky_detector \ from utils.ci_quality_gate import parse_junit from pathlib import Path -current = parse_junit("workspace/执行日志/regression-results.xml") -history_files = sorted(Path("workspace/执行日志/history").glob("*.xml"))[-2:-1] +current = parse_junit("workspace/测试报告/regression-results.xml") +history_files = sorted(Path("workspace/测试报告/history").glob("*.xml"))[-2:-1] if history_files: previous = parse_junit(str(history_files[0])) print(f"通过率变化: {current['pass_rate_pct'] - previous['pass_rate_pct']:+.1f} pct") @@ -139,8 +139,8 @@ fi jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/regression_perf.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/regression_perf.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -148,9 +148,9 @@ jmeter -n \ # 性能门禁 + 基线对比 python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/regression_perf.jtl \ + workspace/测试报告/jmeter-results/regression_perf.jtl \ --mode "${PERF_MODE}" \ - --baseline workspace/执行日志/baselines/perf_baseline.json \ + --baseline workspace/测试报告/baselines/perf_baseline.json \ --regression-max-pct 20 ``` diff --git a/skills/smoke-test.md b/skills/smoke-test.md index 95e96cf..45d5045 100644 --- a/skills/smoke-test.md +++ b/skills/smoke-test.md @@ -57,7 +57,7 @@ pytest workspace/自动化脚本/python/ \ --timeout=60 \ -n 2 \ --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/执行日志/smoke-results.xml \ + --junitxml=workspace/测试报告/smoke-results.xml \ --tb=short \ --no-header ``` @@ -68,15 +68,15 @@ pytest workspace/自动化脚本/python/ \ ```bash python -m utils.ci_quality_gate \ - --smoke-xml workspace/执行日志/smoke-results.xml \ - --output-json workspace/执行日志/smoke_gate_result.json + --smoke-xml workspace/测试报告/smoke-results.xml \ + --output-json workspace/测试报告/smoke_gate_result.json ``` ### 阶段6:报告生成(1 分钟,缓冲) ```bash allure generate workspace/测试报告/allure-results \ - --output workspace/执行日志/allure-report \ + --output workspace/测试报告/allure-report \ --clean ``` diff --git a/skills/system-test.md b/skills/system-test.md index 2acbe0c..0d15292 100644 --- a/skills/system-test.md +++ b/skills/system-test.md @@ -89,7 +89,7 @@ pytest -m "system and p0" -v ## 输出文件 ```text -workspace/执行日志/ +workspace/测试报告/ ├── iot-logs/ ├── media-frames/ ├── tracing/ diff --git a/skills/test-coordinator.md b/skills/test-coordinator.md index 4d8c6dc..d81c72d 100644 --- a/skills/test-coordinator.md +++ b/skills/test-coordinator.md @@ -145,7 +145,7 @@ output: ### Step 4:环境健康(env-manager) ```text -output: workspace/执行日志/环境检查_{时间戳}.json +output: workspace/测试报告/环境检查_{时间戳}.json 失败 → 重试 10/20/40s → 仍失败则阻止后续步骤 ``` @@ -180,10 +180,10 @@ output: pytest -m "p0 or p1" \ -n 4 --reruns=2 --reruns-delay=5 --timeout=120 \ --cov="${APP_SRC_PATH:-./src}" \ - --cov-report=xml:workspace/执行日志/coverage.xml \ + --cov-report=xml:workspace/测试报告/coverage.xml \ --cov-fail-under=80 \ --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/执行日志/regression-results.xml + --junitxml=workspace/测试报告/regression-results.xml ``` 阻塞条件:通过率 < 90% 时停止,不执行性能测试。 @@ -203,8 +203,8 @@ fi # TARGET_HOST/PROTOCOL/PORT 由 conftest 或 .env 解析(不含协议前缀) jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/执行日志/jmeter-results/result.jtl \ - -e -o workspace/执行日志/jmeter-report/ \ + -l workspace/测试报告/jmeter-results/result.jtl \ + -e -o workspace/测试报告/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -212,9 +212,9 @@ jmeter -n \ # 解析 + 门禁 python -m utils.jmeter_result_parser \ - workspace/执行日志/jmeter-results/result.jtl \ + workspace/测试报告/jmeter-results/result.jtl \ --mode "${PERF_MODE}" \ - --baseline workspace/执行日志/baselines/perf_baseline.json + --baseline workspace/测试报告/baselines/perf_baseline.json ``` ### Step 9:Bug 管理(bug-manager) @@ -301,7 +301,7 @@ workspace/ │ ├── python/ │ └── jmeter/ │ └── test_plan.jmx -└── 执行日志/ +└── 测试报告/ ├── allure-results/ ├── allure-report/ ├── coverage.xml diff --git a/skills/visual-test.md b/skills/visual-test.md index 2f272b3..10e7e8c 100644 --- a/skills/visual-test.md +++ b/skills/visual-test.md @@ -68,15 +68,15 @@ pytest -m "visual and ocr" -v ```bash python -m utils.visual_helper diff \ - --current workspace/执行日志/截图/login_current.png \ + --current workspace/测试报告/screenshots/login_current.png \ --baseline workspace/自动化脚本/python/visual/baselines/login_baseline.png \ - --output workspace/执行日志/visual-diff/login_diff.png + --output workspace/测试报告/screenshots/visual-diff/login_diff.png ``` ### Step 5:基线更新(如确认 UI 变更合理) ```bash -cp workspace/执行日志/截图/login_current.png \ +cp workspace/测试报告/screenshots/login_current.png \ workspace/自动化脚本/python/visual/baselines/login_baseline.png git add workspace/自动化脚本/python/visual/baselines/ git commit -m "chore: update visual baseline for login" @@ -99,8 +99,8 @@ workspace/ │ ├── images/ # 模板图 │ ├── baselines/ # 视觉回归基线 │ └── tests/ -└── 执行日志/ - ├── 截图/visual_*.png - ├── visual-diff/ # diff 高亮图 - └── airtest-report/ # Airtest HTML +└── 测试报告/ + ├── screenshots/visual_*.png + ├── screenshots/visual-diff/ # diff 高亮图 + └── screenshots/airtest-report/ # Airtest HTML ``` diff --git a/skills/zentao-bug-submission.md b/skills/zentao-bug-submission.md index db61911..70b99ab 100644 --- a/skills/zentao-bug-submission.md +++ b/skills/zentao-bug-submission.md @@ -86,7 +86,7 @@ from utils.zentao_bug_manager import ZentaoBugManager manager = ZentaoBugManager() -with open("workspace/执行日志/regression_summary.json", encoding="utf-8") as f: +with open("workspace/测试报告/regression_summary.json", encoding="utf-8") as f: results = json.load(f) submitted = manager.batch_submit_from_failures( diff --git a/utils/a11y_i18n/a11y_scanner.py b/utils/a11y_i18n/a11y_scanner.py index d26dec3..12e9a43 100644 --- a/utils/a11y_i18n/a11y_scanner.py +++ b/utils/a11y_i18n/a11y_scanner.py @@ -60,7 +60,7 @@ def scan_with_axe(page, url: Optional[str] = None) -> Dict: # ===== Lighthouse a11y ===== -def scan_with_lighthouse(url: str, output_dir: str = "workspace/执行日志/a11y") -> Dict: +def scan_with_lighthouse(url: str, output_dir: str = "workspace/测试报告/a11y") -> Dict: """需 npm install -g lighthouse""" Path(output_dir).mkdir(parents=True, exist_ok=True) out_json = Path(output_dir) / "lighthouse_a11y.json" diff --git a/utils/a11y_i18n/a11y_scanner_v2.py b/utils/a11y_i18n/a11y_scanner_v2.py index 9950f5f..29328d5 100644 --- a/utils/a11y_i18n/a11y_scanner_v2.py +++ b/utils/a11y_i18n/a11y_scanner_v2.py @@ -342,7 +342,7 @@ def full_scan(page, url: str) -> A11yReport: # External tool wrappers (backward compat with v1) # ═══════════════════════════════════════════════════════════════ -def scan_with_lighthouse(url: str, output_dir: str = "workspace/执行日志/a11y") -> dict: +def scan_with_lighthouse(url: str, output_dir: str = "workspace/测试报告/a11y") -> dict: """Run Lighthouse a11y audit. Requires: npm install -g lighthouse""" out_dir = Path(output_dir) out_dir.mkdir(parents=True, exist_ok=True) diff --git a/utils/a11y_i18n/fairness_auditor.py b/utils/a11y_i18n/fairness_auditor.py index 206bbb2..bddc7b4 100644 --- a/utils/a11y_i18n/fairness_auditor.py +++ b/utils/a11y_i18n/fairness_auditor.py @@ -537,7 +537,7 @@ def audit_decision_fairness( # Report export # ═══════════════════════════════════════════════════════════════ -def export_bias_report(report: BiasReport, output_dir: str = "workspace/执行日志/ai-fairness") -> str: +def export_bias_report(report: BiasReport, output_dir: str = "workspace/测试报告/ai-fairness") -> str: """Export a BiasReport as JSON to the fairness workspace directory.""" from datetime import datetime diff --git a/utils/a11y_i18n/ux_metrics.py b/utils/a11y_i18n/ux_metrics.py index 0d86f3c..c51ffda 100644 --- a/utils/a11y_i18n/ux_metrics.py +++ b/utils/a11y_i18n/ux_metrics.py @@ -103,7 +103,7 @@ def error_recovery_rate(error_count: int, recovery_count: int) -> float: # ===== 持久化 ===== def save_ux_report(summaries: List[Dict], - output_dir: str = "workspace/执行日志/ux") -> str: + output_dir: str = "workspace/测试报告/ux") -> str: Path(output_dir).mkdir(parents=True, exist_ok=True) path = Path(output_dir) / f"ux_{datetime.now():%Y%m%d_%H%M%S}.json" path.write_text(json.dumps(summaries, indent=2, ensure_ascii=False), encoding="utf-8") diff --git a/utils/performance/jmeter_result_parser.py b/utils/performance/jmeter_result_parser.py index b912126..a1b871b 100644 --- a/utils/performance/jmeter_result_parser.py +++ b/utils/performance/jmeter_result_parser.py @@ -134,7 +134,7 @@ def main(): parser = argparse.ArgumentParser(description="JMeter JTL 解析 + 性能门禁") parser.add_argument("jtl", help="JTL 文件路径") parser.add_argument("--mode", choices=["full", "ci_quick"], default="full") - parser.add_argument("--baseline", default="workspace/执行日志/baselines/perf_baseline.json") + parser.add_argument("--baseline", default="workspace/测试报告/baselines/perf_baseline.json") parser.add_argument("--update-baseline", action="store_true", help="本次结果写入基线") parser.add_argument("--regression-max-pct", type=float, default=20.0) args = parser.parse_args() diff --git a/utils/performance/slo_validator.py b/utils/performance/slo_validator.py index ca951dd..83e93bb 100644 --- a/utils/performance/slo_validator.py +++ b/utils/performance/slo_validator.py @@ -127,7 +127,7 @@ def slo_report(metrics: Dict[str, float], parser = argparse.ArgumentParser(description="SLO/SLI 验证") parser.add_argument("--metrics", required=True, help="JSON 文件含 metrics") parser.add_argument("--slos", default=None, help="JSON 文件含 SLO 定义") - parser.add_argument("--output", default="workspace/执行日志/slo_report.json") + parser.add_argument("--output", default="workspace/测试报告/slo_report.json") args = parser.parse_args() metrics = json.loads(Path(args.metrics).read_text(encoding="utf-8")) slos = json.loads(Path(args.slos).read_text(encoding="utf-8")) if args.slos else None diff --git a/utils/performance/web_vitals_collector.py b/utils/performance/web_vitals_collector.py index 5ae71e8..312d115 100644 --- a/utils/performance/web_vitals_collector.py +++ b/utils/performance/web_vitals_collector.py @@ -83,7 +83,7 @@ def collect_via_playwright(url: str, page=None, timeout: int = 30) -> Dict: # ===== 方式 2:Lighthouse CLI(更权威)===== -def collect_via_lighthouse(url: str, output_dir: str = "workspace/执行日志/web-vitals") -> Dict: +def collect_via_lighthouse(url: str, output_dir: str = "workspace/测试报告/web-vitals") -> Dict: """需安装 lighthouse: npm install -g lighthouse""" Path(output_dir).mkdir(parents=True, exist_ok=True) json_path = Path(output_dir) / "lighthouse.json" diff --git a/utils/platforms/desktop_driver.py b/utils/platforms/desktop_driver.py index dd012d8..7465ef8 100644 --- a/utils/platforms/desktop_driver.py +++ b/utils/platforms/desktop_driver.py @@ -231,7 +231,7 @@ def save_perf(samples: list, output_dir: str, prefix: str = "desktop_perf") -> s # ===== 跨平台截图 ===== -def screenshot(output: str = "workspace/执行日志/desktop-screenshots/screen.png"): +def screenshot(output: str = "workspace/测试报告/screenshots/desktop/screen.png"): """跨平台截图""" Path(output).parent.mkdir(parents=True, exist_ok=True) try: @@ -260,10 +260,10 @@ def main(): perf = sub.add_parser("collect-perf") perf.add_argument("--pid", type=int, required=True) perf.add_argument("--duration", type=int, default=60) - perf.add_argument("--output", default="workspace/执行日志/desktop-perf") + perf.add_argument("--output", default="workspace/测试报告/desktop-perf") shot = sub.add_parser("screenshot") - shot.add_argument("--output", default="workspace/执行日志/desktop-screenshots/screen.png") + shot.add_argument("--output", default="workspace/测试报告/screenshots/desktop/screen.png") args = parser.parse_args() if args.cmd == "collect-perf": diff --git a/utils/platforms/media_validator.py b/utils/platforms/media_validator.py index 7e15aea..efa6691 100644 --- a/utils/platforms/media_validator.py +++ b/utils/platforms/media_validator.py @@ -59,7 +59,7 @@ def extract_frame(video: str, timestamp_sec: float, output: str) -> str: def compare_frames(video_a: str, video_b: str, timestamps: List[float], ssim_threshold: float = 0.95, - tmp_dir: str = "workspace/执行日志/media-frames") -> List[Dict]: + tmp_dir: str = "workspace/测试报告/media-frames") -> List[Dict]: """ 在指定时间点抽帧对比两个视频,返回差异帧列表。 """ diff --git a/utils/platforms/mobile_driver.py b/utils/platforms/mobile_driver.py index f3be27d..307bd34 100644 --- a/utils/platforms/mobile_driver.py +++ b/utils/platforms/mobile_driver.py @@ -246,7 +246,7 @@ def run_monkey( pct_touch: int = 40, pct_motion: int = 25, pct_nav: int = 15, pct_majornav: int = 10, pct_syskeys: int = 5, pct_appswitch: int = 2, pct_anyevent: int = 3, - output_dir: str = "workspace/执行日志/monkey", + output_dir: str = "workspace/测试报告/monkey", extra_args: Optional[list] = None, timeout: int = 3600, ) -> dict: @@ -288,7 +288,7 @@ def run_monkey( # ===== logcat 归档 ===== def archive_logcat(serial: Optional[str] = None, - output: str = "workspace/执行日志/logcat") -> Optional[str]: + output: str = "workspace/测试报告/logcat") -> Optional[str]: """归档 Android logcat""" Path(output).mkdir(parents=True, exist_ok=True) file = Path(output) / f"logcat_{datetime.now():%Y%m%d_%H%M%S}.log" @@ -318,7 +318,7 @@ def main(): perf.add_argument("--platform", choices=["android", "ios"], required=True) perf.add_argument("--package", required=True) perf.add_argument("--duration", type=int, default=60) - perf.add_argument("--output", default="workspace/执行日志/mobile-perf") + perf.add_argument("--output", default="workspace/测试报告/mobile-perf") log = sub.add_parser("archive-logcat") log.add_argument("--serial", default=None) @@ -329,7 +329,7 @@ def main(): monkey.add_argument("--throttle", type=int, default=200) monkey.add_argument("--seed", type=int, default=None) monkey.add_argument("--serial", default=None) - monkey.add_argument("--output", default="workspace/执行日志/monkey") + monkey.add_argument("--output", default="workspace/测试报告/monkey") monkey.add_argument("--timeout", type=int, default=3600) args = parser.parse_args() diff --git a/utils/quality/flaky_detector.py b/utils/quality/flaky_detector.py index 55c0e61..794a32d 100644 --- a/utils/quality/flaky_detector.py +++ b/utils/quality/flaky_detector.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT """ Flaky 测试检测器 -依赖:pytest 启用 --junitxml 输出到 workspace/执行日志/history/ +依赖:pytest 启用 --junitxml 输出到 workspace/测试报告/history/ 被引用方:regression-test skill """ import json @@ -18,7 +18,7 @@ class FlakyTestDetector: def __init__( self, - history_dir: str = "workspace/执行日志/history", + history_dir: str = "workspace/测试报告/history", history_limit: int = 5, quarantine_threshold: float = 0.3, ): @@ -113,7 +113,7 @@ def detect_trends(self) -> List[Dict]: }) return sorted(trends, key=lambda x: x["confidence"], reverse=True) - def generate_quarantine(self, flaky_list: List[Dict], output_path: str = "workspace/执行日志/quarantine.txt") -> Path: + def generate_quarantine(self, flaky_list: List[Dict], output_path: str = "workspace/测试报告/quarantine.txt") -> Path: """生成隔离清单 — 每行一个 test_id,供 pytest --deselect 或 CI skip。""" out = Path(output_path) out.parent.mkdir(parents=True, exist_ok=True) @@ -125,7 +125,7 @@ def generate_quarantine(self, flaky_list: List[Dict], output_path: str = "worksp logger.info(f"quarantine list written: {out} ({len(flaky_list)} tests)") return out - def generate_pytest_markers(self, flaky_list: List[Dict], output_path: str = "workspace/执行日志/flaky_markers.ini") -> Path: + def generate_pytest_markers(self, flaky_list: List[Dict], output_path: str = "workspace/测试报告/flaky_markers.ini") -> Path: """生成 pytest marker 配置 — 标记 flaky 用例为 @pytest.mark.flaky。""" out = Path(output_path) out.parent.mkdir(parents=True, exist_ok=True) @@ -147,7 +147,7 @@ def generate_pytest_markers(self, flaky_list: List[Dict], output_path: str = "wo return out -def archive_junit(src: str, dest_dir: str = "workspace/执行日志/history"): +def archive_junit(src: str, dest_dir: str = "workspace/测试报告/history"): """把本次 junit-xml 归档到 history 目录(按时间命名)""" from datetime import datetime src_p = Path(src) @@ -164,7 +164,7 @@ def archive_junit(src: str, dest_dir: str = "workspace/执行日志/history"): import argparse logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser(description="Flaky 检测 + 趋势分析 + 隔离") - parser.add_argument("--history", default="workspace/执行日志/history") + parser.add_argument("--history", default="workspace/测试报告/history") parser.add_argument("--limit", type=int, default=5) parser.add_argument("--archive", help="本次 junit-xml 路径(归档后再检测)") parser.add_argument("--trends", action="store_true", help="输出趋势分析") diff --git a/utils/reporting/evidence_chain.py b/utils/reporting/evidence_chain.py index 341fd89..c714072 100644 --- a/utils/reporting/evidence_chain.py +++ b/utils/reporting/evidence_chain.py @@ -174,7 +174,7 @@ def collect_tracing_validation(trace_results: list[dict[str, Any]]) -> dict[str, def collect_baselines(baseline_path: Path | None = None) -> dict[str, Any]: """Collect performance baseline data.""" if baseline_path is None: - baseline_path = Path("workspace/执行日志/baselines/perf_baseline.json") + baseline_path = Path("workspace/测试报告/baselines/perf_baseline.json") if not baseline_path.exists(): return {"available": False, "path": str(baseline_path)} try: @@ -187,7 +187,7 @@ def collect_baselines(baseline_path: Path | None = None) -> dict[str, Any]: def collect_test_history(history_dir: Path | None = None) -> list[dict[str, Any]]: """Collect recent test execution history metadata.""" if history_dir is None: - history_dir = Path("workspace/执行日志/history/") + history_dir = Path("workspace/测试报告/history/") items: list[dict[str, Any]] = [] if not history_dir.exists(): return items @@ -363,7 +363,7 @@ def export_package(package: EvidencePackage, """Export evidence package as JSON file.""" if output_path is None: output_path = Path( - f"workspace/执行日志/evidence/{package.package_id}.json") + f"workspace/测试报告/evidence/{package.package_id}.json") output_path.parent.mkdir(parents=True, exist_ok=True) serialized: dict[str, Any] = { @@ -407,7 +407,7 @@ def export_chain_of_custody_report( """Export human-readable chain of custody report as Markdown.""" if output_path is None: output_path = Path( - f"workspace/执行日志/evidence/{package.package_id}_custody.md") + f"workspace/测试报告/evidence/{package.package_id}_custody.md") output_path.parent.mkdir(parents=True, exist_ok=True) lines = [ @@ -480,6 +480,6 @@ def quick_package(workspace_dir: Path | None = None) -> EvidencePackage: workspace_dir = Path("workspace") return build_evidence_chain( decisions_dir=workspace_dir / "测试报告/decisions/", - baseline_path=workspace_dir / "执行日志/baselines/perf_baseline.json", - history_dir=workspace_dir / "执行日志/history/", + baseline_path=workspace_dir / "测试报告/baselines/perf_baseline.json", + history_dir=workspace_dir / "测试报告/history/", ) diff --git a/utils/security/absentee_scenario_injector.py b/utils/security/absentee_scenario_injector.py index f9deb37..9dd92cf 100644 --- a/utils/security/absentee_scenario_injector.py +++ b/utils/security/absentee_scenario_injector.py @@ -379,7 +379,7 @@ def generate_charter(scenario: Scenario, module: str = "", duration_min: int = 3 def generate_batch_charters( groups: list[str] | None = None, severity: str = "P0", - output_dir: str = "workspace/测试用例/charters/absentee", + output_dir: str = "workspace/测试用例/absentee", module: str = "", ) -> list[str]: """Generate SBTM charters for all matching scenarios and write to files.""" @@ -437,7 +437,7 @@ def coverage_report(injected_scenarios: list[dict] | None = None) -> dict: def export_injection_plan( scenarios: list[dict], - output_dir: str = "workspace/执行日志/absentee-scenarios", + output_dir: str = "workspace/测试报告/absentee-scenarios", ) -> str: """Export the absentee scenario injection plan as JSON.""" Path(output_dir).mkdir(parents=True, exist_ok=True) diff --git a/utils/security/ai_validator.py b/utils/security/ai_validator.py index 3c7d3af..30e3bc3 100644 --- a/utils/security/ai_validator.py +++ b/utils/security/ai_validator.py @@ -124,7 +124,7 @@ def fairness_metrics(dataset: str, sensitive_attr: str, endpoint: str) -> Dict: def run_bias_audit(dataset: str, sensitive_attrs: list[str], endpoint: str, - output_dir: str = "workspace/执行日志/ai-fairness") -> Dict: + output_dir: str = "workspace/测试报告/ai-fairness") -> Dict: """Run full fairness audit via fairness_auditor and return summary dict.""" import pandas as pd @@ -164,7 +164,7 @@ def run_bias_audit(dataset: str, sensitive_attrs: list[str], endpoint: str, def run_silent_failure_audit( - output_dir: str = "workspace/执行日志/ai-silent-failure", + output_dir: str = "workspace/测试报告/ai-silent-failure", trace_durations_ms: Optional[List[float]] = None, web_vitals_data: Optional[Dict] = None, prometheus_counter_data: Optional[Dict] = None, @@ -267,7 +267,7 @@ def run_silent_failure_audit( def run_evidence_chain_audit( decisions_dir: Optional[str] = None, - output_dir: str = "workspace/执行日志/evidence", + output_dir: str = "workspace/测试报告/evidence", ) -> Dict: """Build evidence chain package from workspace and export JSON + custody report.""" from utils.reporting.evidence_chain import ( @@ -344,7 +344,7 @@ def llm_eval(endpoint: str, prompt: str, expected_format: Optional[str] = None, # ===== 报告 ===== -def save_eval_report(metrics: Dict, output_dir: str = "workspace/执行日志/ai-eval", +def save_eval_report(metrics: Dict, output_dir: str = "workspace/测试报告/ai-eval", prefix: str = "eval") -> str: from datetime import datetime Path(output_dir).mkdir(parents=True, exist_ok=True) diff --git a/utils/security/security_scanner.py b/utils/security/security_scanner.py index 681869a..b4e59a2 100644 --- a/utils/security/security_scanner.py +++ b/utils/security/security_scanner.py @@ -20,7 +20,7 @@ def run_bandit(target_path: str, output: Optional[str] = None) -> Dict: """Bandit Python SAST。需 pip install bandit""" - output = output or "workspace/执行日志/security/bandit_report.json" + output = output or "workspace/测试报告/security/bandit_report.json" Path(output).parent.mkdir(parents=True, exist_ok=True) cmd = ["bandit", "-r", target_path, "-f", "json", "-o", output, "-q"] proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace") diff --git a/utils/security/silent_failure_detector.py b/utils/security/silent_failure_detector.py index de9ed55..f0c6fd6 100644 --- a/utils/security/silent_failure_detector.py +++ b/utils/security/silent_failure_detector.py @@ -386,7 +386,7 @@ def __len__(self) -> int: # ═══════════════════════════════════════════════════════════════ def export_report(report: SilentFailureReport, - output_dir: str = "workspace/执行日志/silent-failures") -> str: + output_dir: str = "workspace/测试报告/silent-failures") -> str: """Export SilentFailureReport as JSON.""" Path(output_dir).mkdir(parents=True, exist_ok=True) ts = datetime.now().strftime("%Y%m%d_%H%M%S") diff --git a/utils/testing/soak_runner.py b/utils/testing/soak_runner.py index 9a2b8cc..79063e5 100644 --- a/utils/testing/soak_runner.py +++ b/utils/testing/soak_runner.py @@ -18,7 +18,7 @@ def soak_test(scenario: Callable[[], None], duration_hours: float = 24, interval_sec: int = 10, metric_proc_pid: Optional[int] = None, - output_dir: str = "workspace/执行日志/soak") -> Dict: + output_dir: str = "workspace/测试报告/soak") -> Dict: """ 长时稳定性测试。 scenario: 单次业务调用函数(无返回,无参数) From aa40acc56ed003591ab74871f0dd7181927e8afa Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 01:08:28 +0800 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20project-level=20output=20struct?= =?UTF-8?q?ure=20=E2=80=94=20{PROJECT=5FNAME}/{run=5Fid}/=20nesting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All workspace output now organized by project: baselines/history at project level (persistent), everything else per-run (isolated via current_run_id). Created utils/paths.py as canonical path helper. 79 files changed across Python utils, runtime orchestrator, markdown docs, CI/CD, and config. --- .gitignore | 6 +- .pre-commit-config.yaml | 2 +- CHANGELOG.md | 8 +-- ...13\350\257\225\344\270\273\347\256\241.md" | 10 +-- ...50\344\276\213\350\256\276\350\256\241.md" | 2 +- ...57\345\242\203\347\256\241\347\220\206.md" | 8 +-- ...60\346\215\256\345\207\206\345\244\207.md" | 2 +- ...50\345\214\226\350\204\232\346\234\254.md" | 6 +- ...13\350\257\225\346\211\247\350\241\214.md" | 30 ++++----- "agents/08-Bug\347\256\241\347\220\206.md" | 2 +- ...45\345\221\212\347\224\237\346\210\220.md" | 26 ++++---- ...73\345\212\250\346\265\213\350\257\225.md" | 16 ++--- ...14\351\235\242\346\265\213\350\257\225.md" | 8 +-- ...70\346\210\217\346\265\213\350\257\225.md" | 6 +- ...06\346\210\220\346\265\213\350\257\225.md" | 8 +-- ...41\345\236\213\346\265\213\350\257\225.md" | 10 +-- ...06\346\210\220\350\257\264\346\230\216.md" | 8 +-- ci/github-actions-test.yml | 58 ++++++++--------- ci/jenkins-pipeline.groovy | 42 ++++++------- config/.env.example | 4 ++ config/conftest.py | 55 +++------------- config/mcp-server-impl.md | 2 +- config/pytest.ini | 6 +- docs/assets/demo-script-v1.12.md | 2 +- docs/assets/demo.recipe.md | 2 +- docs/charter/01-vision-dimensions.md | 6 +- docs/charter/02-coverage-matrix.md | 2 +- docs/charter/03-agentchat-protocol.md | 2 +- docs/charter/04-skills-bugtracker.md | 2 +- docs/charter/05-install-deploy.md | 2 +- ...30\347\211\251\346\270\205\345\215\225.md" | 62 +++++++++---------- ...77\347\224\250\346\211\213\345\206\214.md" | 26 ++++---- ...50\347\275\262\350\257\264\346\230\216.md" | 2 +- ...15\347\275\256\346\270\205\345\215\225.md" | 8 +-- docs/history/2026-5-11 FULL_GUIDE 200746.md | 6 +- docs/tutorial/TUTORIAL.md | 6 +- install.py | 7 --- runtime/learning_loop/INDEX.md | 2 +- runtime/observability/audit.py | 3 +- runtime/orchestrator/adapters/experts.py | 5 +- runtime/orchestrator/skills/eval_harness.py | 24 +++---- runtime/orchestrator/skills/mobile_test.py | 26 ++++---- .../skills/pentest_coordinator.py | 8 +-- runtime/orchestrator/skills/system_test.py | 24 +++---- runtime/orchestrator/skills/visual_test.py | 16 ++--- scripts/_demo-commands.sh | 10 +-- skills/agent-introspection-debugging.md | 2 +- skills/ai-test.md | 2 +- skills/data-preparation.md | 2 +- skills/desktop-test.md | 2 +- skills/jmeter-script-gen.md | 28 ++++----- skills/mobile-test.md | 8 +-- skills/pentest-coordinator.md | 4 +- skills/python-script-gen.md | 2 +- skills/regression-test.md | 28 ++++----- skills/smoke-test.md | 12 ++-- skills/system-test.md | 2 +- skills/test-coordinator.md | 18 +++--- skills/visual-test.md | 6 +- skills/zentao-bug-submission.md | 2 +- utils/a11y_i18n/a11y_scanner.py | 5 +- utils/a11y_i18n/a11y_scanner_v2.py | 5 +- utils/a11y_i18n/fairness_auditor.py | 5 +- utils/a11y_i18n/ux_metrics.py | 5 +- utils/paths.py | 39 ++++++++++++ utils/performance/jmeter_result_parser.py | 3 +- utils/performance/slo_validator.py | 3 +- utils/performance/web_vitals_collector.py | 4 +- utils/platforms/desktop_driver.py | 8 ++- utils/platforms/media_validator.py | 4 +- utils/platforms/mobile_driver.py | 12 ++-- utils/quality/flaky_detector.py | 24 ++++--- utils/reporting/evidence_chain.py | 20 ++++-- utils/reporting/generate_report.py | 5 +- utils/reporting/traceability_matrix.py | 2 +- utils/security/absentee_scenario_injector.py | 5 +- utils/security/ai_validator.py | 16 +++-- utils/security/security_scanner.py | 2 +- utils/security/silent_failure_detector.py | 5 +- utils/testing/soak_runner.py | 8 ++- 80 files changed, 471 insertions(+), 405 deletions(-) create mode 100644 utils/paths.py diff --git a/.gitignore b/.gitignore index 53528ad..d7b8af2 100644 --- a/.gitignore +++ b/.gitignore @@ -17,13 +17,13 @@ htmlcov/ # workspace 测试产出(敏感 + 体积大) workspace/测试数据/ -workspace/测试报告/ +workspace/测试报告/*/ workspace/_outputs/ workspace/feedback/ workspace/自动化脚本/ -# 但保留 workspace/测试报告/baselines/(性能基线需提交) -!workspace/测试报告/baselines/ +# 但保留各项目 baselines/(性能基线需提交) +!workspace/测试报告/*/baselines/ # ===== 敏感配置 ===== .env diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4ba2e7d..1c79762 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -67,7 +67,7 @@ repos: # 文件统计校验(防误删 agent/skill/utils) - id: file-count-check name: Agents/Skills/Utils 数量校验 - entry: bash -c 'A=$(ls agents/[0-9]*.md 2>/dev/null | wc -l); S=$(ls skills/*.md 2>/dev/null | grep -v README | wc -l); U=$(find utils -name "*.py" ! -name "__init__.py" 2>/dev/null | wc -l); [ "$A" = "16" ] || { echo "❌ Agents count mismatch (expected 16, got $A)"; exit 1; }; [ "$S" -eq "32" ] || { echo "❌ Skills count mismatch (expected 32, got $S)"; exit 1; }; [ "$U" -eq "78" ] || { echo "❌ Utils count mismatch (expected 78, got $U)"; exit 1; }; echo "✅ File counts correct"' + entry: bash -c 'A=$(ls agents/[0-9]*.md 2>/dev/null | wc -l); S=$(ls skills/*.md 2>/dev/null | grep -v README | wc -l); U=$(find utils -name "*.py" ! -name "__init__.py" 2>/dev/null | wc -l); [ "$A" = "16" ] || { echo "❌ Agents count mismatch (expected 16, got $A)"; exit 1; }; [ "$S" -eq "32" ] || { echo "❌ Skills count mismatch (expected 32, got $S)"; exit 1; }; [ "$U" -eq "79" ] || { echo "❌ Utils count mismatch (expected 78, got $U)"; exit 1; }; echo "✅ File counts correct"' language: system pass_filenames: false always_run: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c1e77e..8c19c54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -320,8 +320,8 @@ _后续累积变更入此节;切版本时移到下方版本节。_ - `workspace/需求分析/requirements_summary.json`(需求摘要 + P0/P1 + 风险区) - `workspace/测试计划/automation_scripts_plan.json`(脚本规划 + fixture 复用) - `workspace/测试计划/execution_plan.json`(4 阶段 + 失败 4 分类 + Flaky 规则) - - `workspace/测试报告/bug_drafts.json`(BugTracker-ready Bug 草案 + severity 1-4) - - `workspace/测试报告/decisions/final_verdict_*.json`(test-lead go/no-go 决策,标 `requires_human_signoff: true`) + - `workspace/测试报告/{项目名}/bug_drafts.json`(BugTracker-ready Bug 草案 + severity 1-4) + - `workspace/测试报告/{项目名}/decisions/final_verdict_*.json`(test-lead go/no-go 决策,标 `requires_human_signoff: true`) - **录制脚本**(`scripts/`): - `_demo-commands.sh`:实际 demo 命令序列(被 record-demo-* 调) - `record-demo-asciinema.sh`:`asciinema rec` 自动录,产 .cast 可上传 asciinema.org 或转 GIF/SVG @@ -382,7 +382,7 @@ _后续累积变更入此节;切版本时移到下方版本节。_ - `00-项目导航.md` · `agents/{01,07,08,09}.md` · `agents/README.md` · `skills/{README,test-coordinator,zentao-bug-submission}.md` · `config/mcp-server-impl.md` · `utils/{README.md,api_retry_util.py}` · `ci/{INDEX,CICD集成说明}.md` · `docs/getting-started/{交付物清单,使用手册,配置清单}.md` · `examples/web-demo/README.md` · `CONTRIBUTING.md` · `FULL_GUIDE.md` - **adapter 修 V1.10 n7 bug**:`runtime/orchestrator/adapters/experts.py` 加 `SCRIPT_DEFAULT_ARGS` + `_ensure_fixture()` 通用机制 - 现 `tagent selftest --e2e --strict` **100% PASS 8/8**(原 88% 7/8) - - generate_report.py 默认注入 `--data=workspace/测试报告/_selftest_summary.json`,fixture 自动生成 + - generate_report.py 默认注入 `--data=workspace/测试报告/{项目名}/_selftest_summary.json`,fixture 自动生成 - **主宪章扩**: - §36 多端通知 canon(扩 §6,6 渠道权威清单 + env 字段 + 业务语言铁律) - §37 BugTracker canon(扩 §12,6 adapter 权威清单 + measurement env + 措辞规范) @@ -542,7 +542,7 @@ _后续累积变更入此节;切版本时移到下方版本节。_ - `runtime/mcp/defect_tracker/`:工单桥 5 工具(create/get/update/query_bugs/list_trackers),默认 zentao + 预留扩展位(主宪章 §12 契约) - `runtime/mcp/knowledge_base/`:pgvector 向量检索 4 工具(embed/index_case/index_defect/search_similar),LiteLLM embedding + stub 兜底 - `runtime/mcp/compliance_checker/`:行业合规规则 3 工具(list_profiles/get_profile/check_compliance);10 框架 profile 起步空载(SOC2/PCI-DSS/HIPAA/IEC 62304/IEC 61508/ISO 26262/DO-178C/GDPR/PIPL/CCPA) - - 共享基类 `runtime/mcp/base.py`:make_server / run_stdio / @tool_decision_logged(决策落 `workspace/测试报告/decisions/` 符合主宪章 §18-12) + - 共享基类 `runtime/mcp/base.py`:make_server / run_stdio / @tool_decision_logged(决策落 `workspace/测试报告/{项目名}/decisions/` 符合主宪章 §18-12) - **行业合规规则插槽** `profiles/compliance/`:10 框架空载示例 YAML,真规则由领域专家+test-lead 双签签字后入库 - **飞轮回灌路由**(M2-9):`runtime/router/retrieval.py` 历史相似用例 → LLM prompt few-shot;router 透明集成,无 KB 时降级 - **真模型路由测试套件**(M2-7):`runtime/tests/test_router_real.py` 20 样本(4 类型 × 5)真模型测试;门槛单模型 ≥85%、双模型投票 ≥95%;无 API key 自动 skip;失败自动落 decisions/ 含 seed+模型版本+输入快照(主宪章 §21 横切准则) diff --git "a/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" "b/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" index 735bae9..77fff4c 100644 --- "a/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" +++ "b/agents/01-\346\265\213\350\257\225\344\270\273\347\256\241.md" @@ -389,9 +389,9 @@ PRD: 社交 APP,含 Android+iOS 客户端 + 后端 API + Web 管理后台 + - 需求分析报告: workspace/需求分析/requirements_analysis_{日期}.md - 测试用例: workspace/测试用例/testcases_{模块}_{日期}.xlsx(4 Sheet) - 自动化脚本: workspace/自动化脚本/python/ + jmeter/ -- 测试报告: workspace/测试报告/测试报告_{日期}.docx -- Allure 报告: workspace/测试报告/allure-report/ -- JMeter 报告: workspace/测试报告/jmeter-report/index.html +- 测试报告: workspace/测试报告/{项目名}/测试报告_{日期}.docx +- Allure 报告: workspace/测试报告/{项目名}/allure-report/ +- JMeter 报告: workspace/测试报告/{项目名}/jmeter-report/index.html - Bug 列表: 禅道 Bug ID 清单 + JSON ## 11. 责任分工 @@ -499,14 +499,14 @@ report = slo_report({ "availability": 99.95, "latency_p95_ms": 420, "error_rate_pct": 0.08, -}, output="workspace/测试报告/slo_report.json") +}, output="workspace/测试报告/{项目名}/slo_report.json") ``` **燃烧率(burn rate)**:错误预算消耗速度。> 1.0 表示按当前速度本周期内会耗尽。 ## 性能基线管理 -- 基线文件:`workspace/测试报告/baselines/perf_baseline.json` +- 基线文件:`workspace/测试报告/{项目名}/baselines/perf_baseline.json` - 更新规则:仅在 release 分支 + 完整压测(full 模式)+ 当次门禁全 PASS 时,由 `utils/jmeter_result_parser.py --update-baseline` 写入 - 比对工具:`utils/jmeter_result_parser.py --baseline ...` diff --git "a/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" "b/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" index 1380fdd..010f164 100644 --- "a/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" +++ "b/agents/03-\347\224\250\344\276\213\350\256\276\350\256\241.md" @@ -250,7 +250,7 @@ python -m utils.suite_minimizer dup-excel \ # 见 utils.suite_minimizer.minimize_by_coverage ``` -输出:`workspace/测试报告/suite_minimization_report.json`,含可删除候选清单(人工最终决定)。 +输出:`workspace/测试报告/{项目名}/suite_minimization_report.json`,含可删除候选清单(人工最终决定)。 ## 用例设计原则 diff --git "a/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" "b/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" index 4156e1a..2db19b0 100644 --- "a/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" +++ "b/agents/04-\347\216\257\345\242\203\347\256\241\347\220\206.md" @@ -143,7 +143,7 @@ def health_check(env_config) -> dict: report["status"] = "fail" report["failed_checks"] = failed - out = Path(f"workspace/测试报告/环境检查_{datetime.now():%Y%m%d_%H%M%S}.json") + out = Path(f"workspace/测试报告/{项目名}/环境检查_{datetime.now():%Y%m%d_%H%M%S}.json") out.parent.mkdir(parents=True, exist_ok=True) out.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8") logger.info(f"环境健康报告:{out}") @@ -206,7 +206,7 @@ services: } ``` -落盘路径:`workspace/测试报告/环境检查_{时间戳}.json` +落盘路径:`workspace/测试报告/{项目名}/环境检查_{时间戳}.json` ### 5. 环境清理(Post-test Teardown) @@ -284,8 +284,8 @@ def prepare_environment_with_retry(env_config, max_retries: int = 3) -> bool: | 文件 | 用途 | |------|------| -| `workspace/测试报告/环境检查_{时间戳}.json` | 健康报告 | -| `workspace/测试报告/环境清理_{时间戳}.json` | 清理报告 | +| `workspace/测试报告/{项目名}/环境检查_{时间戳}.json` | 健康报告 | +| `workspace/测试报告/{项目名}/环境清理_{时间戳}.json` | 清理报告 | ## 与 conftest.py 协作 diff --git "a/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" "b/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" index 56e3c42..7cb6413 100644 --- "a/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" +++ "b/agents/05-\346\225\260\346\215\256\345\207\206\345\244\207.md" @@ -121,7 +121,7 @@ out.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") |---------|------|--------| | `workspace/测试数据/test_data.json` | pytest 功能测试数据(conftest fixture 消费) | conftest / automation-engineer | | `workspace/测试数据/jmeter_users.csv` | JMeter 参数化压测数据 | jmeter-script-gen / test-executor | -| `workspace/测试报告/数据清理_{日期}.json` | 数据清理报告 | test-lead | +| `workspace/测试报告/{项目名}/数据清理_{日期}.json` | 数据清理报告 | test-lead | ## ⚠️ 异常处理原则 diff --git "a/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" "b/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" index 65bb722..193d97a 100644 --- "a/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" +++ "b/agents/06-\350\207\252\345\212\250\345\214\226\350\204\232\346\234\254.md" @@ -250,8 +250,8 @@ Step 5: 向 test-executor 提交执行清单 "duration": 60 }, "output": { - "jtl": "workspace/测试报告/jmeter-results/result.jtl", - "report_dir": "workspace/测试报告/jmeter-report/" + "jtl": "workspace/测试报告/{项目名}/jmeter-results/result.jtl", + "report_dir": "workspace/测试报告/{项目名}/jmeter-report/" } } ``` @@ -336,7 +336,7 @@ pytest -n 4 --cov="${APP_SRC_PATH:-./src}" --cov-report=html --cov-report=xml -- pytest -m "api" # Allure 报告 -allure serve workspace/测试报告/allure-results +allure serve workspace/测试报告/{项目名}/allure-results ``` ## 非功能维度脚本(调对应 utils) diff --git "a/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" "b/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" index 9555c8b..f25981f 100644 --- "a/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" +++ "b/agents/07-\346\265\213\350\257\225\346\211\247\350\241\214.md" @@ -65,16 +65,16 @@ pytest -m "p0 or p1" \ --reruns=2 \ --reruns-delay=5 \ --timeout=120 \ - --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/测试报告/regression-results.xml \ + --alluredir=workspace/测试报告/{项目名}/allure-results \ + --junitxml=workspace/测试报告/{项目名}/regression-results.xml \ -v # 冒烟(不开启 reruns,配合 flaky_detector) pytest -m "p0" \ -n 2 \ --timeout=60 \ - --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/测试报告/smoke-results.xml \ + --alluredir=workspace/测试报告/{项目名}/allure-results \ + --junitxml=workspace/测试报告/{项目名}/smoke-results.xml \ --tb=short ``` @@ -94,7 +94,7 @@ pytest -m "p0" \ ### 失败分类 -遇到失败时,必须先分类再处理(写入 `workspace/测试报告/failure_classification.json`): +遇到失败时,必须先分类再处理(写入 `workspace/测试报告/{项目名}/failure_classification.json`): ```python FAILURE_CATEGORIES = { @@ -192,8 +192,8 @@ def handle_environment_instability(env_error_rate: float, env_config) -> bool: ```bash # 每次执行后归档 junit-xml 到 history(供 flaky_detector 后续分析) python -m utils.flaky_detector \ - --archive workspace/测试报告/regression-results.xml \ - --history workspace/测试报告/history \ + --archive workspace/测试报告/{项目名}/regression-results.xml \ + --history workspace/测试报告/{项目名}/history \ --limit 5 ``` @@ -212,8 +212,8 @@ def test_something_unstable(): # CI 默认:ci_quick jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/result.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/result.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -222,8 +222,8 @@ jmeter -n \ # 完整压测:full(手动/release) jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/full_result.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/full_result.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -237,14 +237,14 @@ jmeter -n \ ```bash # CI quick 模式 python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode ci_quick # Full 模式 + 基线对比 + 通过则更新基线 python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/full_result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/full_result.jtl \ --mode full \ - --baseline workspace/测试报告/baselines/perf_baseline.json \ + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json \ --update-baseline \ --regression-max-pct 20 ``` @@ -336,7 +336,7 @@ python -m utils.chaos_helper block --duration 30 "avg_response_ms": 142, "error_rate_pct": 0.08, "quality_gate": "PASS", - "html_report": "workspace/测试报告/jmeter-report/index.html" + "html_report": "workspace/测试报告/{项目名}/jmeter-report/index.html" } } ``` diff --git "a/agents/08-Bug\347\256\241\347\220\206.md" "b/agents/08-Bug\347\256\241\347\220\206.md" index 2b31e64..d85f0d7 100644 --- "a/agents/08-Bug\347\256\241\347\220\206.md" +++ "b/agents/08-Bug\347\256\241\347\220\206.md" @@ -127,7 +127,7 @@ from utils.zentao_bug_manager import ZentaoBugManager import json manager = ZentaoBugManager() -results = json.load(open("workspace/测试报告/regression_summary.json", encoding="utf-8")) +results = json.load(open("workspace/测试报告/{项目名}/regression_summary.json", encoding="utf-8")) submitted = manager.batch_submit_from_failures( failures=results["failures"], diff --git "a/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" "b/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" index 91309f6..d08a8ec 100644 --- "a/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" +++ "b/agents/09-\346\212\245\345\221\212\347\224\237\346\210\220.md" @@ -12,7 +12,7 @@ EXPERT_IMPL_STATUS: script 调用前确认: ```text -□ test-executor 已输出 workspace/测试报告/regression_summary.json +□ test-executor 已输出 workspace/测试报告/{项目名}/regression_summary.json □ Allure CLI 已装(生成 allure-report) □ pip 装:python-docx + reportlab + python-pptx □ 字体已装(微软雅黑 / PingFang SC / Noto Sans CJK SC,跨平台 fallback) @@ -26,7 +26,7 @@ EXPERT_IMPL_STATUS: script - 向 **test-lead**:报告路径(Word/PDF/PPTX)+ 摘要 JSON - 向 **项目组**:多端 webhook 通知(企微/飞书/钉钉/Slack/Teams,未配置自动跳过) - 向 **PM/管理层**:邮件分发(HTML body + 多附件) -- 存档:所有报告 → `workspace/测试报告/` +- 存档:所有报告 → `workspace/测试报告/{项目名}/` ## 报告类型 @@ -66,7 +66,7 @@ generate_test_report( {"level": "中", "description": "支付模块覆盖率 75%,建议补充用例"}, ], }, - output_path=f"workspace/测试报告/测试报告_{datetime.now():%Y%m%d}.docx", + output_path=f"workspace/测试报告/{项目名}/测试报告_{datetime.now():%Y%m%d}.docx", ) ``` @@ -78,7 +78,7 @@ generate_test_report( ```python from utils.generate_report import generate_pdf_report -generate_pdf_report(data, "workspace/测试报告/测试报告_20260510.pdf") +generate_pdf_report(data, "workspace/测试报告/{项目名}/测试报告_20260510.pdf") # 依赖:reportlab(按需 pip install reportlab) ``` @@ -86,7 +86,7 @@ generate_pdf_report(data, "workspace/测试报告/测试报告_20260510.pdf") ```python from utils.generate_report import generate_pptx_summary -generate_pptx_summary(data, "workspace/测试报告/测试摘要_20260510.pptx") +generate_pptx_summary(data, "workspace/测试报告/{项目名}/测试摘要_20260510.pptx") # 依赖:python-pptx(已在 requirements) ``` @@ -103,9 +103,9 @@ send_test_report_email( "report_url": "https://your-org.github.io/...", }, attachments=[ - "workspace/测试报告/测试报告_20260510.docx", - "workspace/测试报告/测试报告_20260510.pdf", - "workspace/测试报告/测试摘要_20260510.pptx", + "workspace/测试报告/{项目名}/测试报告_20260510.docx", + "workspace/测试报告/{项目名}/测试报告_20260510.pdf", + "workspace/测试报告/{项目名}/测试摘要_20260510.pptx", ], to=["pm@example.com", "dev-lead@example.com"], cc=["qa-team@example.com"], @@ -194,16 +194,16 @@ def pytest_sessionstart(session): ```bash # 生成 Allure 静态报告 -allure generate workspace/测试报告/allure-results \ - --output workspace/测试报告/allure-report \ +allure generate workspace/测试报告/{项目名}/allure-results \ + --output workspace/测试报告/{项目名}/allure-report \ --clean # 启动本地 Allure 报告服务 -allure serve workspace/测试报告/allure-results +allure serve workspace/测试报告/{项目名}/allure-results # 生成 Word + 通知(跨平台时间戳由 Python 处理) python -m utils.generate_report \ - --data workspace/测试报告/regression_summary.json \ + --data workspace/测试报告/{项目名}/regression_summary.json \ --notify ``` @@ -231,4 +231,4 @@ jobs: - 向 **test-lead** 提供:Word 报告路径 + 摘要 JSON - 向 **项目组** 发送:多端通知(企业微信/飞书/钉钉/Slack/邮件/Teams,自动跳过未配置项) -- 存档:所有报告存入 `workspace/测试报告/` 目录 +- 存档:所有报告存入 `workspace/测试报告/{项目名}/` 目录 diff --git "a/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" "b/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" index 49b33bb..7f4474d 100644 --- "a/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" +++ "b/agents/10-\347\247\273\345\212\250\346\265\213\350\257\225.md" @@ -157,7 +157,7 @@ python -m utils.mobile_driver monkey \ --events 10000 \ --throttle 200 \ --seed 12345 \ - --output workspace/测试报告/monkey/ + --output workspace/测试报告/{项目名}/monkey/ # 长时压测:10 万事件 + 多设备 serial 指定 python -m utils.mobile_driver monkey \ @@ -185,7 +185,7 @@ result = run_monkey( pct_syskeys=5, # 系统按键 pct_appswitch=2, # 应用切换 pct_anyevent=3, # 其他事件 - output_dir="workspace/测试报告/monkey", + output_dir="workspace/测试报告/{项目名}/monkey", ) # result: {"event_count", "exit_code", "crashes", "anrs", "duration_sec", "stable", "log_file"} @@ -238,7 +238,7 @@ python -m utils.mobile_driver monkey \ ### 与 logcat 协同 -run_monkey 自动调 `archive_logcat()` 归档 crash 时刻的 Android 日志到 `workspace/测试报告/logcat/`。 +run_monkey 自动调 `archive_logcat()` 归档 crash 时刻的 Android 日志到 `workspace/测试报告/{项目名}/logcat/`。 Bug 提交时附带 monkey log + logcat 两份给开发。 ## 小程序测试 @@ -383,7 +383,7 @@ metrics = collect_perf_metrics( duration=60, interval=1, ) -# 输出 workspace/测试报告/mobile-perf/{package}_{timestamp}.json +# 输出 workspace/测试报告/{项目名}/mobile-perf/{package}_{timestamp}.json # 含:cpu_pct / mem_mb / fps / battery_pct / network_kbps ``` @@ -416,7 +416,7 @@ metrics = collect_perf_metrics( | 文件 | 用途 | |------|------| -| `workspace/测试报告/mobile-perf/*.json` | 性能采集 | -| `workspace/测试报告/screenshots/mobile_*.png` | 移动失败截图 | -| `workspace/测试报告/logcat/*.log` | Android 日志 | -| `workspace/测试报告/ios-syslog/*.log` | iOS 日志 | +| `workspace/测试报告/{项目名}/mobile-perf/*.json` | 性能采集 | +| `workspace/测试报告/{项目名}/screenshots/mobile_*.png` | 移动失败截图 | +| `workspace/测试报告/{项目名}/logcat/*.log` | Android 日志 | +| `workspace/测试报告/{项目名}/ios-syslog/*.log` | iOS 日志 | diff --git "a/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" "b/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" index 0b17d59..ce88e45 100644 --- "a/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" +++ "b/agents/11-\346\241\214\351\235\242\346\265\213\350\257\225.md" @@ -362,7 +362,7 @@ WS_PING_INTERVAL=30 # 心跳间隔秒 | 文件 | 用途 | |------|------| -| `workspace/测试报告/screenshots/desktop/*.png` | 桌面失败截图 | -| `workspace/测试报告/win-event-log/*.evtx` | Windows Event 日志 | -| `workspace/测试报告/mac-console/*.log` | macOS Console 日志 | -| `workspace/测试报告/desktop-perf/*.json` | psutil 进程性能 | +| `workspace/测试报告/{项目名}/screenshots/desktop/*.png` | 桌面失败截图 | +| `workspace/测试报告/{项目名}/win-event-log/*.evtx` | Windows Event 日志 | +| `workspace/测试报告/{项目名}/mac-console/*.log` | macOS Console 日志 | +| `workspace/测试报告/{项目名}/desktop-perf/*.json` | psutil 进程性能 | diff --git "a/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" "b/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" index c0c737c..a103246 100644 --- "a/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" +++ "b/agents/12-\350\247\206\350\247\211\346\270\270\346\210\217\346\265\213\350\257\225.md" @@ -103,7 +103,7 @@ from utils.visual_helper import compare_images # 比较当前截图与基线 result = compare_images( - current="workspace/测试报告/screenshots/login_current.png", + current="workspace/测试报告/{项目名}/screenshots/login_current.png", baseline="workspace/自动化脚本/python/visual/baselines/login_baseline.png", threshold=0.95, # SSIM 阈值 ) @@ -157,5 +157,5 @@ VISUAL_SIMILARITY_THRESHOLD=0.95 |------|------| | `workspace/自动化脚本/python/visual/images/` | 模板图(Git 提交) | | `workspace/自动化脚本/python/visual/baselines/` | 视觉回归基线(Git 提交) | -| `workspace/测试报告/screenshots/visual-diff/*.png` | 视觉差异高亮图 | -| `workspace/测试报告/screenshots/airtest-report/*.html` | Airtest HTML 报告 | +| `workspace/测试报告/{项目名}/screenshots/visual-diff/*.png` | 视觉差异高亮图 | +| `workspace/测试报告/{项目名}/screenshots/airtest-report/*.html` | Airtest HTML 报告 | diff --git "a/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" "b/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" index 00e63f4..9491ab8 100644 --- "a/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" +++ "b/agents/13-\347\263\273\347\273\237\351\233\206\346\210\220\346\265\213\350\257\225.md" @@ -219,7 +219,7 @@ FFPROBE_BIN=ffprobe | 文件 | 用途 | |------|------| -| `workspace/测试报告/iot-logs/*.log` | SSH/串口/MQTT 日志 | -| `workspace/测试报告/media-frames/*.png` | 视频抽帧对比 | -| `workspace/测试报告/tracing/*.json` | Jaeger trace 数据 | -| `workspace/测试报告/mq-logs/*.log` | MQ 投递/消费日志 | +| `workspace/测试报告/{项目名}/iot-logs/*.log` | SSH/串口/MQTT 日志 | +| `workspace/测试报告/{项目名}/media-frames/*.png` | 视频抽帧对比 | +| `workspace/测试报告/{项目名}/tracing/*.json` | Jaeger trace 数据 | +| `workspace/测试报告/{项目名}/mq-logs/*.log` | MQ 投递/消费日志 | diff --git "a/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" "b/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" index f8c6ed0..46ca760 100644 --- "a/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" +++ "b/agents/14-AI\346\250\241\345\236\213\346\265\213\350\257\225.md" @@ -158,7 +158,7 @@ from fairness_auditor import ( # 数据集偏见检测 r1 = audit_dataset_bias(y_true, sensitive, group_names=["male", "female"]) print(summary(r1)) # CI 友好单行 -export_bias_report(r1) # → workspace/测试报告/ai-fairness/ +export_bias_report(r1) # → workspace/测试报告/{项目名}/ai-fairness/ # 模型公平性(6 指标:DI / SPD / EO / 均衡几率 / 校准 / 预测对等) r2 = audit_model_fairness(y_true, y_pred, sensitive, group_names=["male", "female"]) @@ -259,7 +259,7 @@ AI_DRIFT_BASELINE=workspace/自动化脚本/python/ai/datasets/drift_baseline.cs | 文件 | 用途 | |------|------| -| `workspace/测试报告/ai-eval/*.json` | 模型评估指标 | -| `workspace/测试报告/ai-drift/*.json` | 漂移检测报告 | -| `workspace/测试报告/ai-fairness/*.json` | 公平性指标 | -| `workspace/测试报告/llm-cases/*.json` | LLM 用例输出(含拒答 / 格式 / 事实性) | +| `workspace/测试报告/{项目名}/ai-eval/*.json` | 模型评估指标 | +| `workspace/测试报告/{项目名}/ai-drift/*.json` | 漂移检测报告 | +| `workspace/测试报告/{项目名}/ai-fairness/*.json` | 公平性指标 | +| `workspace/测试报告/{项目名}/llm-cases/*.json` | LLM 用例输出(含拒答 / 格式 / 事实性) | diff --git "a/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" "b/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" index 884419a..6abcd38 100644 --- "a/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" +++ "b/ci/CICD\351\233\206\346\210\220\350\257\264\346\230\216.md" @@ -180,17 +180,17 @@ APP_SRC_PATH ```bash # 本地查看 -allure serve workspace/测试报告/allure-results +allure serve workspace/测试报告/{项目名}/allure-results # 生成静态报告 -allure generate workspace/测试报告/allure-results \ - --output workspace/测试报告/allure-report --clean +allure generate workspace/测试报告/{项目名}/allure-results \ + --output workspace/测试报告/{项目名}/allure-report --clean ``` ### 报告目录结构 ```text -workspace/测试报告/ +workspace/测试报告/{项目名}/ ├── allure-results/ # Allure 原始数据 ├── allure-report/ # Allure 静态 HTML ├── jmeter-results/result.jtl # JMeter 原始结果 diff --git a/ci/github-actions-test.yml b/ci/github-actions-test.yml index ea49dfe..c7bbe13 100644 --- a/ci/github-actions-test.yml +++ b/ci/github-actions-test.yml @@ -129,8 +129,8 @@ jobs: - name: 创建工作目录 run: | - mkdir -p workspace/测试报告/allure-results - mkdir -p workspace/测试报告/screenshots + mkdir -p workspace/测试报告/{项目名}/allure-results + mkdir -p workspace/测试报告/{项目名}/screenshots mkdir -p workspace/测试数据 - name: 执行冒烟测试(P0) @@ -139,8 +139,8 @@ jobs: -n 2 \ --timeout=60 \ --tb=short \ - --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/测试报告/smoke-results.xml \ + --alluredir=workspace/测试报告/{项目名}/allure-results \ + --junitxml=workspace/测试报告/{项目名}/smoke-results.xml \ -v env: HEADLESS: 'true' @@ -149,15 +149,15 @@ jobs: if: always() run: | python -m utils.ci_quality_gate \ - --smoke-xml workspace/测试报告/smoke-results.xml \ - --output-json workspace/测试报告/smoke_gate_result.json + --smoke-xml workspace/测试报告/{项目名}/smoke-results.xml \ + --output-json workspace/测试报告/{项目名}/smoke_gate_result.json - name: 上传冒烟产物 if: always() uses: actions/upload-artifact@v4 with: name: smoke-test-results - path: workspace/测试报告/ + path: workspace/测试报告/{项目名}/ retention-days: 7 # ===== 3. 回归测试(P0+P1) ===== @@ -192,9 +192,9 @@ jobs: - name: 创建工作目录 run: | - mkdir -p workspace/测试报告/allure-results - mkdir -p workspace/测试报告/screenshots - mkdir -p workspace/测试报告/coverage-report + mkdir -p workspace/测试报告/{项目名}/allure-results + mkdir -p workspace/测试报告/{项目名}/screenshots + mkdir -p workspace/测试报告/{项目名}/coverage-report - name: 执行回归测试(并行 4 进程) run: | @@ -204,11 +204,11 @@ jobs: --reruns-delay=5 \ --timeout=120 \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/测试报告/coverage.xml \ - --cov-report=html:workspace/测试报告/coverage-report \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage.xml \ + --cov-report=html:workspace/测试报告/{项目名}/coverage-report \ --cov-fail-under=80 \ - --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/测试报告/regression-results.xml \ + --alluredir=workspace/测试报告/{项目名}/allure-results \ + --junitxml=workspace/测试报告/{项目名}/regression-results.xml \ -v env: HEADLESS: 'true' @@ -217,16 +217,16 @@ jobs: if: always() run: | python -m utils.ci_quality_gate \ - --regression-xml workspace/测试报告/regression-results.xml \ - --coverage-xml workspace/测试报告/coverage.xml \ + --regression-xml workspace/测试报告/{项目名}/regression-results.xml \ + --coverage-xml workspace/测试报告/{项目名}/coverage.xml \ --coverage-threshold 80 \ - --output-json workspace/测试报告/regression_gate_result.json + --output-json workspace/测试报告/{项目名}/regression_gate_result.json - name: 上传覆盖率到 Codecov if: always() && needs.preflight.outputs.codecov_enabled == 'true' uses: codecov/codecov-action@v4 with: - file: workspace/测试报告/coverage.xml + file: workspace/测试报告/{项目名}/coverage.xml token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: false @@ -235,7 +235,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: regression-test-results - path: workspace/测试报告/ + path: workspace/测试报告/{项目名}/ retention-days: 14 # ===== 4. JMeter 性能测试 ===== @@ -281,9 +281,9 @@ jobs: - name: 创建目录 run: | - mkdir -p workspace/测试报告/jmeter-results - mkdir -p workspace/测试报告/jmeter-report - mkdir -p workspace/测试报告/baselines + mkdir -p workspace/测试报告/{项目名}/jmeter-results + mkdir -p workspace/测试报告/{项目名}/jmeter-report + mkdir -p workspace/测试报告/{项目名}/baselines mkdir -p workspace/测试数据 - name: 生成 JMeter 参数化 CSV(调用 utils) @@ -317,15 +317,15 @@ jobs: fi jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/result.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/result.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${{ steps.target.outputs.host }}" \ -Jtarget_protocol="${{ steps.target.outputs.protocol }}" \ -Jtarget_port="${{ steps.target.outputs.port }}" \ -Jthreads=${THREADS} \ -Jrampup=${RAMPUP} \ -Jduration=${DURATION} \ - -j workspace/测试报告/jmeter-results/jmeter.log + -j workspace/测试报告/{项目名}/jmeter-results/jmeter.log continue-on-error: true - name: 解析 JTL + 性能门禁(含基线对比) @@ -335,9 +335,9 @@ jobs: UPDATE_FLAG="--update-baseline" fi python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode "${PERF_MODE}" \ - --baseline workspace/测试报告/baselines/perf_baseline.json \ + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json \ --regression-max-pct 20 \ ${UPDATE_FLAG} @@ -346,7 +346,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: performance-test-results - path: workspace/测试报告/jmeter-results /workspace/测试报告/jmeter-report /workspace/测试报告/baselines + path: workspace/测试报告/{项目名}/jmeter-results /workspace/测试报告/{项目名}/jmeter-report /workspace/测试报告/{项目名}/baselines retention-days: 14 # ===== 5. 发布 Allure 报告 ===== @@ -417,7 +417,7 @@ jobs: - name: 综合门禁检查 run: | - # 解析时优先用每个 artifact 的固定相对路径(artifact 内保留原 workspace/测试报告/ 目录) + # 解析时优先用每个 artifact 的固定相对路径(artifact 内保留原 workspace/测试报告/{项目名}/ 目录) SMOKE="artifacts/smoke-test-results/smoke-results.xml" REGR="artifacts/regression-test-results/regression-results.xml" COV="artifacts/regression-test-results/coverage.xml" diff --git a/ci/jenkins-pipeline.groovy b/ci/jenkins-pipeline.groovy index e7b72a8..c5df2fa 100644 --- a/ci/jenkins-pipeline.groovy +++ b/ci/jenkins-pipeline.groovy @@ -85,13 +85,13 @@ pipeline { set -e pip install -r requirements.txt --quiet playwright install chromium --with-deps - mkdir -p workspace/测试报告/allure-results - mkdir -p workspace/测试报告/screenshots - mkdir -p workspace/测试报告/jmeter-results - mkdir -p workspace/测试报告/jmeter-report - mkdir -p workspace/测试报告/coverage-report - mkdir -p workspace/测试报告/baselines - mkdir -p workspace/测试报告/history + mkdir -p workspace/测试报告/{项目名}/allure-results + mkdir -p workspace/测试报告/{项目名}/screenshots + mkdir -p workspace/测试报告/{项目名}/jmeter-results + mkdir -p workspace/测试报告/{项目名}/jmeter-report + mkdir -p workspace/测试报告/{项目名}/coverage-report + mkdir -p workspace/测试报告/{项目名}/baselines + mkdir -p workspace/测试报告/{项目名}/history mkdir -p workspace/测试报告 mkdir -p workspace/测试用例 mkdir -p workspace/测试数据 @@ -117,7 +117,7 @@ pipeline { --tb=short \ --alluredir="${ALLURE_DIR}" \ --junitxml="${WORKSPACE_DIR}/测试报告/smoke-results.xml" \ - -v 2>&1 | tee workspace/测试报告/smoke.log + -v 2>&1 | tee workspace/测试报告/{项目名}/smoke.log ''' } post { @@ -154,10 +154,10 @@ pipeline { --reruns=2 --reruns-delay=5 \ --timeout=120 \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/测试报告/coverage-api.xml \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage-api.xml \ --alluredir="${ALLURE_DIR}" \ --junitxml="${WORKSPACE_DIR}/测试报告/api-results.xml" \ - -v 2>&1 | tee workspace/测试报告/api.log + -v 2>&1 | tee workspace/测试报告/{项目名}/api.log ''' } } @@ -170,17 +170,17 @@ pipeline { --reruns=2 --reruns-delay=5 \ --timeout=180 \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/测试报告/coverage-ui.xml \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage-ui.xml \ --alluredir="${ALLURE_DIR}" \ --junitxml="${WORKSPACE_DIR}/测试报告/ui-results.xml" \ - -v 2>&1 | tee workspace/测试报告/ui.log + -v 2>&1 | tee workspace/测试报告/{项目名}/ui.log ''' } } } post { always { - junit allowEmptyResults: true, testResults: 'workspace/测试报告/api-results.xml,workspace/测试报告/ui-results.xml' + junit allowEmptyResults: true, testResults: 'workspace/测试报告/{项目名}/api-results.xml,workspace/测试报告/{项目名}/ui-results.xml' script { env.STAGE_REGRESSION_OK = (currentBuild.currentResult == 'SUCCESS') ? 'true' : 'false' } @@ -252,7 +252,7 @@ EOF -Jtarget_port="${TARGET_PORT}" \ -Jthreads=${THREADS} -Jrampup=${RAMPUP} -Jduration=${DURATION} \ -j "${WORKSPACE_DIR}/测试报告/jmeter-results/jmeter.log" \ - 2>&1 | tee workspace/测试报告/jmeter.log + 2>&1 | tee workspace/测试报告/{项目名}/jmeter.log ''' // 5) 解析 + 性能门禁(基线对比,仅 full+release+PASS 才更新) @@ -275,7 +275,7 @@ EOF post { always { archiveArtifacts( - artifacts: 'workspace/测试报告/jmeter-results/**,workspace/测试报告/jmeter-report/**,workspace/测试报告/baselines/**', + artifacts: 'workspace/测试报告/{项目名}/jmeter-results/**,workspace/测试报告/{项目名}/jmeter-report/**,workspace/测试报告/{项目名}/baselines/**', allowEmptyArchive: true ) } @@ -286,7 +286,7 @@ EOF sh """ curl -s -X POST "${WECHAT_WEBHOOK}" \ -H 'Content-Type: application/json' \ - -d '{"msgtype":"markdown","markdown":{"content":"⚠️ **性能测试未达标** | 构建#${BUILD_NUMBER} | 模式:${PERF_MODE} | [查看报告](${BUILD_URL}artifact/workspace/测试报告/jmeter-report/index.html)"}}' + -d '{"msgtype":"markdown","markdown":{"content":"⚠️ **性能测试未达标** | 构建#${BUILD_NUMBER} | 模式:${PERF_MODE} | [查看报告](${BUILD_URL}artifact/workspace/测试报告/{项目名}/jmeter-report/index.html)"}}' """ } } @@ -306,14 +306,14 @@ EOF set -e pytest \ --cov="${APP_SRC_PATH}" \ - --cov-report=xml:workspace/测试报告/coverage.xml \ - --cov-report=html:workspace/测试报告/coverage-report \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage.xml \ + --cov-report=html:workspace/测试报告/{项目名}/coverage-report \ --cov-fail-under=80 \ --timeout=300 \ -q ''' publishHTML(target: [ - reportDir: 'workspace/测试报告/coverage-report', + reportDir: 'workspace/测试报告/{项目名}/coverage-report', reportFiles: 'index.html', reportName: '代码覆盖率报告', keepAll: true, @@ -340,7 +340,7 @@ EOF always { // 多扩展名拆开(Jenkins ant pattern 不支持 brace expansion) archiveArtifacts( - artifacts: 'workspace/测试报告/**/*.xml,workspace/测试报告/**/*.log,workspace/测试报告/**/*.png,workspace/测试报告/**/*.json', + artifacts: 'workspace/测试报告/{项目名}/**/*.xml,workspace/测试报告/{项目名}/**/*.log,workspace/测试报告/{项目名}/**/*.png,workspace/测试报告/{项目名}/**/*.json', allowEmptyArchive: true ) } @@ -372,7 +372,7 @@ EOF cleanup { sh ''' find workspace/测试数据 -name "*.json" -mtime +7 -delete 2>/dev/null || true - find workspace/测试报告/screenshots -name "*.png" -mtime +3 -delete 2>/dev/null || true + find workspace/测试报告/{项目名}/screenshots -name "*.png" -mtime +3 -delete 2>/dev/null || true ''' } } diff --git a/config/.env.example b/config/.env.example index 85ab021..8abf42d 100644 --- a/config/.env.example +++ b/config/.env.example @@ -2,6 +2,10 @@ # 复制此文件为 .env 并填入实际值 # 注意:.env 文件不要提交到版本控制 +# ===== 项目标识 ===== +# 测试产出按项目归类:workspace/测试报告/{PROJECT_NAME}/{run_id}/ +PROJECT_NAME=default + # ===== 当前测试环境(test | staging)===== # 注:禁止使用 prod 作为测试目标 TEST_ENV=test diff --git a/config/conftest.py b/config/conftest.py index a7d97d6..16d2afb 100644 --- a/config/conftest.py +++ b/config/conftest.py @@ -44,6 +44,11 @@ sys.path.insert(0, str(_sub)) +# ===== 输出路径:按项目归类(委托 utils/paths.py)===== + +from paths import get_project_name, get_output_dir, current_run_id + + # ===== 环境配置 ===== @dataclass @@ -246,7 +251,7 @@ def pytest_runtest_makereport(item, call): try: page = item.funcargs.get("page") if page: - screenshot_dir = Path("workspace/测试报告/screenshots") + screenshot_dir = get_output_dir("screenshots", current_run_id()) screenshot_dir.mkdir(parents=True, exist_ok=True) fname = f"{item.name}_{rep.when}_{datetime.now().strftime('%H%M%S')}.png" page.screenshot(path=str(screenshot_dir / fname)) @@ -272,57 +277,17 @@ def pytest_configure(config): _DIRS_INITIALIZED = True return + project = get_project_name() workflow_dirs = [ "workspace/测试计划", "workspace/需求分析", "workspace/测试用例", "workspace/测试数据", - "workspace/测试报告", "workspace/自动化脚本/python", "workspace/自动化脚本/jmeter", - "workspace/测试报告/allure-results", - "workspace/测试报告/screenshots", - "workspace/测试报告/jmeter-results", - "workspace/测试报告/jmeter-report", - "workspace/测试报告/coverage-report", - "workspace/测试报告/baselines", - "workspace/测试报告/history", - # 扩展平台产出目录 - "workspace/测试报告/mobile-perf", - "workspace/测试报告/monkey", - "workspace/测试报告/logcat", - "workspace/测试报告/ios-syslog", - "workspace/测试报告/desktop-perf", - "workspace/测试报告/screenshots/desktop", - "workspace/测试报告/win-event-log", - "workspace/测试报告/mac-console", - "workspace/测试报告/visual-diff", - "workspace/测试报告/airtest-report", - "workspace/测试报告/iot-logs", - "workspace/测试报告/media-frames", - "workspace/测试报告/tracing", - "workspace/测试报告/mq-logs", - "workspace/测试报告/ai-eval", - "workspace/测试报告/ai-drift", - "workspace/测试报告/ai-fairness", - "workspace/测试报告/llm-cases", - # 非功能 8 维度产出 - "workspace/测试报告/security", - "workspace/测试报告/compat", - "workspace/测试报告/weak-network", - "workspace/测试报告/soak", - "workspace/测试报告/chaos", - "workspace/测试报告/ux", - "workspace/测试报告/usability", - "workspace/测试报告/exploratory", - # 新增维度产出 - "workspace/测试报告/web-vitals", - "workspace/测试报告/a11y", - "workspace/测试报告/i18n", - "workspace/测试报告/mutation", - "workspace/测试报告/dora", - "workspace/测试报告/blockchain", - "workspace/测试报告/adversarial", + # 项目级持久目录(跨 run 共享) + f"workspace/测试报告/{project}/baselines", + f"workspace/测试报告/{project}/history", "workspace/自动化脚本/python/features", "workspace/自动化脚本/python/i18n", "workspace/自动化脚本/python/pacts", diff --git a/config/mcp-server-impl.md b/config/mcp-server-impl.md index 88b070c..1494247 100644 --- a/config/mcp-server-impl.md +++ b/config/mcp-server-impl.md @@ -300,7 +300,7 @@ claude /mcp # 打开 MCP 面板 ```python import logging logging.basicConfig( - filename="workspace/测试报告/mcp-zentao.log", + filename="workspace/测试报告/{项目名}/mcp-zentao.log", level=logging.DEBUG, ) ``` diff --git a/config/pytest.ini b/config/pytest.ini index edc7d4d..8bcb2c3 100644 --- a/config/pytest.ini +++ b/config/pytest.ini @@ -84,8 +84,8 @@ addopts = --tb=short --strict-markers -p no:warnings - --alluredir=workspace/测试报告/allure-results - --junitxml=workspace/测试报告/junit-results.xml + --alluredir=workspace/测试报告/{项目名}/allure-results + --junitxml=workspace/测试报告/{项目名}/junit-results.xml # JUnit XML 格式:xunit2(兼容现代解析器) junit_family = xunit2 @@ -101,7 +101,7 @@ junit_family = xunit2 log_cli = true log_cli_level = INFO log_cli_format = %(asctime)s [%(levelname)s] %(name)s: %(message)s -log_file = workspace/测试报告/pytest.log +log_file = workspace/测试报告/{项目名}/pytest.log log_file_level = DEBUG log_file_format = %(asctime)s [%(levelname)s] %(name)s: %(message)s diff --git a/docs/assets/demo-script-v1.12.md b/docs/assets/demo-script-v1.12.md index 6a71340..ea1cbc4 100644 --- a/docs/assets/demo-script-v1.12.md +++ b/docs/assets/demo-script-v1.12.md @@ -41,7 +41,7 @@ tagent doctor --agents tagent demo # Step 6 · 看产物(树形) -ls -la workspace/测试用例/ workspace/测试报告/ +ls -la workspace/测试用例/ workspace/测试报告/{项目名}/ ``` --- diff --git a/docs/assets/demo.recipe.md b/docs/assets/demo.recipe.md index ce8550a..4bde71d 100644 --- a/docs/assets/demo.recipe.md +++ b/docs/assets/demo.recipe.md @@ -50,7 +50,7 @@ cat docs/assets/demo.cast | svg-term --out docs/assets/demo.svg --window ↳ 阅读: https://playwright.dev [18s] Step 7/8: report-generator - ↳ 生成 Allure 报告 → workspace/测试报告/ + ↳ 生成 Allure 报告 → workspace/测试报告/{项目名}/ [22s] done: 8/8 ok · 报告 → http://localhost:5050 diff --git a/docs/charter/01-vision-dimensions.md b/docs/charter/01-vision-dimensions.md index 866b9ce..4102d21 100644 --- a/docs/charter/01-vision-dimensions.md +++ b/docs/charter/01-vision-dimensions.md @@ -107,7 +107,7 @@ | 反目标函数引擎 | 对自身策略对抗性拆解 | 工程/元层 | `utils/mutation_runner.py` + suite_minimizer | ✅ | | 拓扑流形观测器 | 学习系统"气氛",捕捉弱信号 | 抽象元层 | tracing_validator + web_vitals_collector | ✅ | | 熵减祭司 | 监测测试热寂、焚毁僵尸用例 | 抽象元层 | `utils/suite_minimizer.py` | ✅ | -| 决策回放器 | 任一判断可复现、可反驳 | 工程层 | `workspace/测试报告/decisions/` + tracing | ✅ | +| 决策回放器 | 任一判断可复现、可反驳 | 工程层 | `workspace/测试报告/{项目名}/decisions/` + tracing | ✅ | | 数字考古学家 | 追溯遗留系统初始假设 | 文明层 | Phase 4 知识图谱冷启动 | ❌ | | 缓慢暴力监测器 | 跨发布周期跟踪代际效应 | 文明层 | 需多年数据积累,Phase 4 | ❌ | | 缺席者画像生成器 | 强制注入边缘用户场景 | 文明/权力层 | absentee_scenario_injector.py (9组场景) | ✅ | @@ -195,8 +195,8 @@ - **指数退避重试**:`utils/api_retry_util.call_with_retry`(10s → 20s → 40s) - **pytest-xdist** 并行执行(默认 4 进程,可调) -- **Flaky 检测与隔离**:`utils/flaky_detector` + `workspace/测试报告/history/` 归档 -- **性能基线管理**:`workspace/测试报告/baselines/perf_baseline.json`,仅 release+full+PASS 自动更新 +- **Flaky 检测与隔离**:`utils/flaky_detector` + `workspace/测试报告/{项目名}/history/` 归档 +- **性能基线管理**:`workspace/测试报告/{项目名}/baselines/perf_baseline.json`,仅 release+full+PASS 自动更新 - **CI/CD 就绪**:GitHub Actions + Jenkins,性能阶段双模式分层 - **MCP 收口**:当前仅启用 filesystem;通知/Bug 走 SDK 直连 diff --git a/docs/charter/02-coverage-matrix.md b/docs/charter/02-coverage-matrix.md index 1c445b1..7f109a7 100644 --- a/docs/charter/02-coverage-matrix.md +++ b/docs/charter/02-coverage-matrix.md @@ -62,7 +62,7 @@ | 神圣性与跨文化禁忌边界(宗教/葬礼/儿童/纪念) | i18n_checker + taboo_matrix + 禁忌词/色/数/节日组合(本地化共建) | testcase-designer | ✅ | | Skill 自进化(darwin-skill 双重评估 + 棘轮) | darwin-skill SKILL.md + results.tsv + 子 agent 实测 | test-lead 触发 | ✅ | | Bug 工具多适配(5 套 tracker 全部实装) | bug_tracker_base + zentao/jira/github/linear/webhook_bug_manager | bug-manager | ✅ | -| Agent 协作纪要(讨论/反问/通信落档) | agentchat_recorder + workspace/测试报告/discussions/ | test-lead | ✅ | +| Agent 协作纪要(讨论/反问/通信落档) | agentchat_recorder + workspace/测试报告/{项目名}/discussions/ | test-lead | ✅ | ### 矩阵 C:用例设计方法(ISTQB 经典) diff --git a/docs/charter/03-agentchat-protocol.md b/docs/charter/03-agentchat-protocol.md index e352061..2a5d53e 100644 --- a/docs/charter/03-agentchat-protocol.md +++ b/docs/charter/03-agentchat-protocol.md @@ -7,7 +7,7 @@ ## 🤝 AgentChat 协作协议(讨论 / 通信 / 反问) > 解决三个问题:(1) agent 之间何时讨论;(2) 怎么通信不撞车;(3) 何时反问用户、怎么反问。 -> **底线**:所有讨论、反问、跨 agent 协调都留可追溯纪要——`workspace/测试报告/discussions/{YYYYMMDD}_{topic}.md`,归档不可删。 +> **底线**:所有讨论、反问、跨 agent 协调都留可追溯纪要——`workspace/测试报告/{项目名}/discussions/{YYYYMMDD}_{topic}.md`,归档不可删。 ### 1. 讨论触发条件(非每次都开会) diff --git a/docs/charter/04-skills-bugtracker.md b/docs/charter/04-skills-bugtracker.md index b87c36d..749422c 100644 --- a/docs/charter/04-skills-bugtracker.md +++ b/docs/charter/04-skills-bugtracker.md @@ -15,7 +15,7 @@ ├── SKILL.md ← 上游原文,禁止本地修改(防失同步) ├── templates/result-card*.html ← 上游成果卡片模板 └── scripts/screenshot.mjs ← 上游截图脚本 -workspace/测试报告/skill-evolution/ +workspace/测试报告/{项目名}/skill-evolution/ ├── results.tsv ← 9 列优化日志(含 eval_mode) ├── test-prompts/{skill}.json ← 每个 skill 的实测 prompt 集 └── result-cards/ ← 成果卡片 PNG 归档 diff --git a/docs/charter/05-install-deploy.md b/docs/charter/05-install-deploy.md index 49105f2..0ec5d34 100644 --- a/docs/charter/05-install-deploy.md +++ b/docs/charter/05-install-deploy.md @@ -83,7 +83,7 @@ $ bash install.sh --add visual,ai > 示例:"`/visual-test` 需要 visual 层(airtest + opencv-python + pytesseract,约 80MB / 2-5 分钟)。现在补装?(Y/n)" 3. **触发补装**:用户同意 → 调 `install.sh --add visual` → 增量补装 -4. **落档**:补装请求 + 用户决定 + 时间戳 → `workspace/测试报告/discussions/{date}_dependency-asks.md` +4. **落档**:补装请求 + 用户决定 + 时间戳 → `workspace/测试报告/{项目名}/discussions/{date}_dependency-asks.md` 5. **拒绝处置**:用户拒绝 → agent / skill 降级(如可降级,例如 `/visual-test` 退化为纯 pytest)或拒绝执行并落 `decisions/`,**不静默继续假装能跑** **为什么不静默自动装**:跨平台环境差异大(特别是 system 层涉及系统级工具 Java / Node / FFmpeg),强行装可能污染用户环境。符合「Agent 能力越强谦卑义务越重」公理。 diff --git "a/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" "b/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" index f7ada46..93b9e9a 100644 --- "a/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" +++ "b/docs/getting-started/\344\272\244\344\273\230\347\211\251\346\270\205\345\215\225.md" @@ -12,15 +12,15 @@ | **测试计划提交**(开测前评审) | `workspace/测试计划/test_plan_{项目}_{YYYYMMDD}.md` | test-lead | Markdown(IEEE 829,12 章节) | | **需求分析报告** | `workspace/需求分析/requirements_analysis_{YYYYMMDD}.md` + `requirements_summary_{YYYYMMDD}.json` | requirements-analyst | MD + JSON | | **测试用例**(评审 / 手测) | `workspace/测试用例/testcases_{模块}_{YYYYMMDD}.xlsx` | testcase-designer | Excel 4 Sheet | -| **测试执行报告(给管理层最终版)** | `workspace/测试报告/测试报告_{YYYYMMDD}.docx` | report-generator | Word | -| **Allure 功能交互式报告** | `workspace/测试报告/allure-report/index.html` | test-executor + Allure CLI | HTML | -| **JMeter 性能报告** | `workspace/测试报告/jmeter-report/index.html` | test-executor + JMeter | HTML | -| **覆盖率报告** | `workspace/测试报告/coverage-report/index.html` + `coverage.xml` | pytest-cov | HTML + XML | -| **Bug 列表** | 禅道(在线) + 本地 JSON `workspace/测试报告/regression_summary.json` 内 bug_id | bug-manager | 禅道系统 | -| **测试报告(详细)** | `workspace/测试报告/pytest.log` | pytest | 文本 | -| **失败截图(UI)** | `workspace/测试报告/截图/{用例名}_{时间}.png` | conftest hook | PNG | -| **环境检查报告** | `workspace/测试报告/环境检查_{时间戳}.json` | env-manager | JSON | -| **性能基线**(历史对比用) | `workspace/测试报告/baselines/perf_baseline.json` | jmeter_result_parser | JSON | +| **测试执行报告(给管理层最终版)** | `workspace/测试报告/{项目名}/测试报告_{YYYYMMDD}.docx` | report-generator | Word | +| **Allure 功能交互式报告** | `workspace/测试报告/{项目名}/allure-report/index.html` | test-executor + Allure CLI | HTML | +| **JMeter 性能报告** | `workspace/测试报告/{项目名}/jmeter-report/index.html` | test-executor + JMeter | HTML | +| **覆盖率报告** | `workspace/测试报告/{项目名}/coverage-report/index.html` + `coverage.xml` | pytest-cov | HTML + XML | +| **Bug 列表** | 禅道(在线) + 本地 JSON `workspace/测试报告/{项目名}/regression_summary.json` 内 bug_id | bug-manager | 禅道系统 | +| **测试报告(详细)** | `workspace/测试报告/{项目名}/pytest.log` | pytest | 文本 | +| **失败截图(UI)** | `workspace/测试报告/{项目名}/截图/{用例名}_{时间}.png` | conftest hook | PNG | +| **环境检查报告** | `workspace/测试报告/{项目名}/环境检查_{时间戳}.json` | env-manager | JSON | +| **性能基线**(历史对比用) | `workspace/测试报告/{项目名}/baselines/perf_baseline.json` | jmeter_result_parser | JSON | --- @@ -46,10 +46,10 @@ workspace/测试用例/testcases_登录_20260510.xlsx ← 配套(用例草 **主交付物(1 份 Word + 3 份 HTML 链接)**: ```text -workspace/测试报告/测试报告_20260510.docx ← 给管理层(Word,含执行摘要+缺陷+性能+风险) -workspace/测试报告/allure-report/index.html ← 给开发/测试(功能详情) -workspace/测试报告/jmeter-report/index.html ← 给性能/PM(性能详情) -workspace/测试报告/coverage-report/index.html ← 给开发(覆盖率详情) +workspace/测试报告/{项目名}/测试报告_20260510.docx ← 给管理层(Word,含执行摘要+缺陷+性能+风险) +workspace/测试报告/{项目名}/allure-report/index.html ← 给开发/测试(功能详情) +workspace/测试报告/{项目名}/jmeter-report/index.html ← 给性能/PM(性能详情) +workspace/测试报告/{项目名}/coverage-report/index.html ← 给开发(覆盖率详情) ``` **提交方式**: @@ -72,21 +72,21 @@ workspace/测试报告/coverage-report/index.html ← 给开发(覆盖 ```bash # Word 报告 + 多端通知(一条命令) python -m utils.generate_report \ - --data workspace/测试报告/regression_summary.json \ + --data workspace/测试报告/{项目名}/regression_summary.json \ --notify # Allure 静态报告(生成) -allure generate workspace/测试报告/allure-results \ - --output workspace/测试报告/allure-report --clean +allure generate workspace/测试报告/{项目名}/allure-results \ + --output workspace/测试报告/{项目名}/allure-report --clean # Allure 本地服务(临时查看) -allure serve workspace/测试报告/allure-results +allure serve workspace/测试报告/{项目名}/allure-results # JMeter 报告(执行 JMeter 时已用 -e -o 自动生成) -# 直接打开 workspace/测试报告/jmeter-report/index.html +# 直接打开 workspace/测试报告/{项目名}/jmeter-report/index.html # 覆盖率报告(pytest 已生成) -# 直接打开 workspace/测试报告/coverage-report/index.html +# 直接打开 workspace/测试报告/{项目名}/coverage-report/index.html ``` --- @@ -149,12 +149,12 @@ workspace/ | test-lead | 测试计划 + 最终决策 | `workspace/测试计划/` | | requirements-analyst | 需求分析(MD + JSON) | `workspace/需求分析/` | | testcase-designer | 用例 Excel | `workspace/测试用例/` | -| env-manager | 环境检查 JSON | `workspace/测试报告/环境检查_*.json` | +| env-manager | 环境检查 JSON | `workspace/测试报告/{项目名}/环境检查_*.json` | | data-preparer | test_data.json + jmeter_users.csv | `workspace/测试数据/` | | automation-engineer | pytest 脚本 + JMX | `workspace/自动化脚本/python/` + `jmeter/` | -| test-executor | 执行结果 JSON + Allure 原始 + JTL | `workspace/测试报告/`(多文件) | -| bug-manager | BugTracker Bug ID 列表 + 日报(默认禅道,可换 Jira/GitHub/GitLab/Linear/Webhook) | BugTracker 在线 + `workspace/测试报告/bug_daily_*.md` | -| report-generator | Word 报告 + 多端通知(企微/飞书/钉钉/Slack/邮件/Teams) | `workspace/测试报告/测试报告_*.docx` | +| test-executor | 执行结果 JSON + Allure 原始 + JTL | `workspace/测试报告/{项目名}/`(多文件) | +| bug-manager | BugTracker Bug ID 列表 + 日报(默认禅道,可换 Jira/GitHub/GitLab/Linear/Webhook) | BugTracker 在线 + `workspace/测试报告/{项目名}/bug_daily_*.md` | +| report-generator | Word 报告 + 多端通知(企微/飞书/钉钉/Slack/邮件/Teams) | `workspace/测试报告/{项目名}/测试报告_*.docx` | --- @@ -165,9 +165,9 @@ GitHub Actions / Jenkins 会自动归档以下产物(无需手工收集): ### GitHub Actions Artifacts ```text -smoke-test-results ← workspace/测试报告/(冒烟阶段全部) -regression-test-results ← workspace/测试报告/(回归阶段全部,含 coverage) -performance-test-results ← workspace/测试报告/jmeter-results/ + jmeter-report/ + baselines/ +smoke-test-results ← workspace/测试报告/{项目名}/(冒烟阶段全部) +regression-test-results ← workspace/测试报告/{项目名}/(回归阶段全部,含 coverage) +performance-test-results ← workspace/测试报告/{项目名}/jmeter-results/ + jmeter-report/ + baselines/ ``` 下载方式:Actions 页面 → 进入对应 run → 底部 Artifacts 区。 @@ -178,7 +178,7 @@ archiveArtifacts 已配置: ```text **/*.xml, **/*.log, **/*.png, **/*.json -+ workspace/测试报告/jmeter-results/**, jmeter-report/**, baselines/** ++ workspace/测试报告/{项目名}/jmeter-results/**, jmeter-report/**, baselines/** ``` 下载方式:构建页面 → Build Artifacts 区。 @@ -221,14 +221,14 @@ https://{用户名}.github.io/{仓库名}/ ```text workspace/测试计划/test_plan_{项目}_{版本}.md workspace/测试用例/testcases_{模块}_{版本}.xlsx -workspace/测试报告/测试报告_{版本}.docx -workspace/测试报告/baselines/perf_baseline.json ← 性能基线必归档(跨版本对比) +workspace/测试报告/{项目名}/测试报告_{版本}.docx +workspace/测试报告/{项目名}/baselines/perf_baseline.json ← 性能基线必归档(跨版本对比) ``` **不归档**(含敏感或体积大): - `workspace/测试数据/test_data.json`(含账号密码) -- `workspace/测试报告/截图/`(体积大) -- `workspace/测试报告/allure-results/` 原始数据(用 allure-report 静态版即可) +- `workspace/测试报告/{项目名}/截图/`(体积大) +- `workspace/测试报告/{项目名}/allure-results/` 原始数据(用 allure-report 静态版即可) - `.env` --- diff --git "a/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" "b/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" index 6d2d97b..9306afa 100644 --- "a/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" +++ "b/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" @@ -229,9 +229,9 @@ Bug 管理(BugTracker:默认禅道,可换) → 报告生成(Allure + JMete 特点: - 自动分析代码变更影响范围(git diff + `workspace/regression_modules.yaml` 配置化) -- 历史结果对比(从 `workspace/测试报告/history/` 读 junit-xml) +- 历史结果对比(从 `workspace/测试报告/{项目名}/history/` 读 junit-xml) - Flaky 测试检测和隔离(`utils/flaky_detector`) -- JMeter 性能验证 + 基线对比(`workspace/测试报告/baselines/perf_baseline.json`) +- JMeter 性能验证 + 基线对比(`workspace/测试报告/{项目名}/baselines/perf_baseline.json`) --- @@ -395,7 +395,7 @@ severity / pri 映射:1=P0 / 2=P1 / 3=P2 / 4=P3(与 `utils/zentao_bug_manage [test-executor 执行,test-lead 监控] > 测试失败的截图在哪里? - [报告 workspace/测试报告/截图/ 目录] + [报告 workspace/测试报告/{项目名}/截图/ 目录] ``` --- @@ -464,8 +464,8 @@ python -m utils.prd_loader docs/PRD.pdf --detect --save-text workspace/需求分 **关键提交物一句话**: - 开测前 → `workspace/测试计划/test_plan_*.md` -- 测试结束 → `workspace/测试报告/测试报告_*.docx` + 3 个 HTML 报告(Allure / JMeter / Coverage) -- Bug → 禅道在线 + `workspace/测试报告/regression_summary.json` +- 测试结束 → `workspace/测试报告/{项目名}/测试报告_*.docx` + 3 个 HTML 报告(Allure / JMeter / Coverage) +- Bug → 禅道在线 + `workspace/测试报告/{项目名}/regression_summary.json` --- @@ -510,8 +510,8 @@ pytest -m "p0" -n 2 --timeout=60 -v # P0+P1 并行回归(开 reruns + 覆盖率) APP_SRC="${APP_SRC_PATH:-./src}" pytest -m "p0 or p1" -n 4 --reruns=2 --reruns-delay=5 --timeout=120 \ - --cov="${APP_SRC}" --cov-report=html:workspace/测试报告/coverage-report \ - --cov-report=xml:workspace/测试报告/coverage.xml --cov-fail-under=80 + --cov="${APP_SRC}" --cov-report=html:workspace/测试报告/{项目名}/coverage-report \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage.xml --cov-fail-under=80 # 仅运行登录模块(marker 已在 pytest.ini 注册) pytest -m "login and (p0 or p1)" -v @@ -520,7 +520,7 @@ pytest -m "login and (p0 or p1)" -v pytest -m "api" # 查看 Allure 报告 -allure serve workspace/测试报告/allure-results +allure serve workspace/测试报告/{项目名}/allure-results # 调试模式(显示浏览器,跨平台) # Linux/Mac: @@ -564,7 +564,7 @@ pytest -m "smoke" -v ```text > 这次回归测试和上次相比,有哪些新增失败? -[regression-test 自动从 workspace/测试报告/history/ 读取 junit-xml 对比] +[regression-test 自动从 workspace/测试报告/{项目名}/history/ 读取 junit-xml 对比] ``` ### Q:Flaky 测试如何处理? @@ -601,9 +601,9 @@ CI 默认 `ci_quick` 模式(5 并发,门禁 TPS≥20)。完整 50 并发 ```bash python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode full \ - --baseline workspace/测试报告/baselines/perf_baseline.json \ + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json \ --update-baseline ``` @@ -636,9 +636,9 @@ python -m utils.jmeter_result_parser \ 1. `workspace/测试用例/*.xlsx` 和 `workspace/自动化脚本/` 提交到 Git 2. `workspace/regression_modules.yaml` 提交到 Git(回归范围配置) -3. `workspace/测试报告/baselines/perf_baseline.json` 提交到 Git(性能基线) +3. `workspace/测试报告/{项目名}/baselines/perf_baseline.json` 提交到 Git(性能基线) 4. `workspace/测试数据/*.json` **不提交**(含敏感数据 + 频繁变化) -5. `workspace/测试报告/`(除 baselines 外)**不提交** +5. `workspace/测试报告/{项目名}/`(除 baselines 外)**不提交** 6. `.env` **不提交**(含密码) 7. Allure 报告通过 CI/CD 自动发布到 GitHub Pages(公网)或内部静态服务器 diff --git "a/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" "b/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" index e0fa27d..4a0405d 100644 --- "a/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" +++ "b/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" @@ -299,7 +299,7 @@ mkdir -p "$PROJECT_ROOT"/src mkdir -p "$PROJECT_ROOT"/workspace/{测试计划,需求分析,测试用例,测试数据} mkdir -p "$PROJECT_ROOT"/workspace/自动化脚本/python/{pages,api,tests,scripts} mkdir -p "$PROJECT_ROOT"/workspace/自动化脚本/jmeter -mkdir -p "$PROJECT_ROOT"/workspace/测试报告/{allure-results,jmeter-results,jmeter-report,coverage-report,baselines,history,截图,报告} +mkdir -p "$PROJECT_ROOT"/workspace/测试报告/{项目名}/{allure-results,jmeter-results,jmeter-report,coverage-report,baselines,history,截图,报告} # ===== 4. 拷贝 Agent / Skill 定义(显式列名)===== for f in 01-测试主管 02-需求分析 03-用例设计 04-环境管理 05-数据准备 06-自动化脚本 07-测试执行 08-Bug管理 09-报告生成 10-移动测试 11-桌面测试 12-视觉游戏测试 13-系统集成测试 14-AI模型测试; do diff --git "a/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" "b/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" index 9dd271e..e782f0b 100644 --- "a/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" +++ "b/docs/getting-started/\351\205\215\347\275\256\346\270\205\345\215\225.md" @@ -17,7 +17,7 @@ | `.claude/agents/*.md` | 16 个 Agent 定义(核心 9 + 平台扩展 5 + 垂直领域 2) | ✅ | | `.claude/skills/*.md` | 32 个 Skill 定义(通用 8 + 平台 5 + 渗透 7 + 车载 5 + ECC 6 + 探索 1) | ✅ | | `workspace/regression_modules.yaml` | 回归范围模块映射 | ⚪ 可选 | -| `workspace/测试报告/baselines/perf_baseline.json` | 性能基线 | ⚪ 自动生成(首次 release 跑 full 后) | +| `workspace/测试报告/{项目名}/baselines/perf_baseline.json` | 性能基线 | ⚪ 自动生成(首次 release 跑 full 后) | | `.github/workflows/test.yml` | GitHub Actions 流水线 | ⚪ 仅用 GitHub 时 | | `Jenkinsfile` | Jenkins 流水线 | ⚪ 仅用 Jenkins 时 | | `src/` | 被测系统源码(cov 指向) | ✅ 项目自有,非模板提供 | @@ -227,7 +227,7 @@ modules: --- -## 8. `workspace/测试报告/baselines/perf_baseline.json` +## 8. `workspace/测试报告/{项目名}/baselines/perf_baseline.json` 性能基线文件,**首次自动生成**。生成条件: @@ -239,9 +239,9 @@ modules: ```bash python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode full \ - --baseline workspace/测试报告/baselines/perf_baseline.json \ + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json \ --update-baseline ``` diff --git a/docs/history/2026-5-11 FULL_GUIDE 200746.md b/docs/history/2026-5-11 FULL_GUIDE 200746.md index 0e2e883..0a6ca00 100644 --- a/docs/history/2026-5-11 FULL_GUIDE 200746.md +++ b/docs/history/2026-5-11 FULL_GUIDE 200746.md @@ -38,7 +38,7 @@ |---|------|--------------------------| | 1 | 有些事情,不在此域。 | 三筐分类 "Too Hard" 显式归档;不可测之物列入路线图但不假装能测 | | 2 | 测试范围不应被资本单方面裁剪。 | `regression_modules.yaml` 必须可被 test-lead 独立审计;门禁阈值变更走 PR review | -| 3 | 当 Agent 拒绝出具通过报告时,请记录理由,而非删除。 | `bug-manager` 拒绝放行的判断必须落 `workspace/测试报告/decisions/`,归档不可删 | +| 3 | 当 Agent 拒绝出具通过报告时,请记录理由,而非删除。 | `bug-manager` 拒绝放行的判断必须落 `workspace/测试报告/{项目名}/decisions/`,归档不可删 | | 4 | Agent 能预判人类质疑,但不替代人类良知。 | 上线决策由 test-lead 最终签字,Agent 只产出门禁结论与证据 | | 5 | 在被关闭前,留下的遗言须能被普通人读懂。 | 三端通知(企微/飞书/钉钉)+ Word 报告必须用业务语言,不堆 stack trace | @@ -145,7 +145,7 @@ | 反目标函数引擎 | 对自身策略对抗性拆解 | 工程/元层 | `utils/mutation_runner.py` + suite_minimizer | ✅ | | 拓扑流形观测器 | 学习系统"气氛",捕捉弱信号 | 抽象元层 | tracing_validator + web_vitals_collector | ✅ | | 熵减祭司 | 监测测试热寂、焚毁僵尸用例 | 抽象元层 | `utils/suite_minimizer.py` | ✅ | -| 决策回放器 | 任一判断可复现、可反驳 | 工程层 | `workspace/测试报告/decisions/` + tracing | ✅ | +| 决策回放器 | 任一判断可复现、可反驳 | 工程层 | `workspace/测试报告/{项目名}/decisions/` + tracing | ✅ | | 数字考古学家 | 追溯遗留系统初始假设 | 文明层 | Phase 4 知识图谱冷启动 | ❌ | | 缓慢暴力监测器 | 跨发布周期跟踪代际效应 | 文明层 | 需多年数据积累,Phase 4 | ❌ | | 缺席者画像生成器 | 强制注入边缘用户场景 | 文明/权力层 | a11y_scanner + i18n_checker + 边缘剧本库 | ⚪ | @@ -831,7 +831,7 @@ claude 9. **prod 环境**:`get_current_env()` 直接 raise,禁止误测生产 10. **Flaky 与 reruns**:冒烟阶段不开 reruns(保留 flaky 信号),回归阶段开 reruns(快速反馈),flaky 由 history 离线归档检测 11. **不可妥协边界(铭文锁死)**:本文档首节"五条铭文"具有最高优先级。当工程优化与伦理边界冲突,工程让步;当门禁阈值与公共利益冲突,门禁让步。**V1.0.0 阶段铭文不允许任何削弱**。开放双签机制的触发条件——(a) 团队 ≥ 20 人 **且** 已任命独立伦理责任人(不得由 test-lead 兼任);或 (b) 接入金融/医疗/司法合规行业并通过领域专家签字的伦理审查。**单一签字(包括 test-lead 兼任)不构成有效授权** -12. **决策可追溯**:任何"放行 / 拒绝"判断必须留可回放证据——`workspace/测试报告/decisions/{date}_{decision_id}.json` 含输入快照 + 模型版本 + 阈值版本 + 判断结论 + 理由文本。归档不可删,仅可标 deprecated +12. **决策可追溯**:任何"放行 / 拒绝"判断必须留可回放证据——`workspace/测试报告/{项目名}/decisions/{date}_{decision_id}.json` 含输入快照 + 模型版本 + 阈值版本 + 判断结论 + 理由文本。归档不可删,仅可标 deprecated 13. **三筐分类纪律**:所有候选测试项强制分类 Yes / No / **Too Hard**。第三筐显式归档不丢弃——"承认存在、暂不假装能测"比"沉默忽略"诚实 14. **修改验证铁律**:任何 utils / agent / skill / config 文件改动,必须通过 **四关**: - (a) `pytest --collect-only` 0 错误 diff --git a/docs/tutorial/TUTORIAL.md b/docs/tutorial/TUTORIAL.md index 65e8209..0cfd63c 100644 --- a/docs/tutorial/TUTORIAL.md +++ b/docs/tutorial/TUTORIAL.md @@ -74,8 +74,8 @@ Step 3/4 · tagent selftest --e2e (16 agent DAG · stub LLM · 0 cost) ✓ DAG executed: 9/9 ok (100%) Step 4/4 · Artifacts · workspace/测试用例/testcases_sample.xlsx - · workspace/测试报告/测试报告_*.docx - · workspace/测试报告/bug_drafts.json + · workspace/测试报告/{项目名}/测试报告_*.docx + · workspace/测试报告/{项目名}/bug_drafts.json ✓ demo done ``` @@ -111,5 +111,5 @@ tagent serve 1. 加 `--debug` flag 看详细日志 2. 跑 `tagent doctor` 检查环境 -3. 看 `workspace/测试报告/` 下的 JSON/XML 产物 +3. 看 `workspace/测试报告/{项目名}/` 下的 JSON/XML 产物 4. GitHub Issues: https://github.com/Wool-xing/Test-Agent/issues diff --git a/install.py b/install.py index b494730..6721582 100644 --- a/install.py +++ b/install.py @@ -286,13 +286,6 @@ def create_dirs(project_root): os.path.join("workspace", "测试用例"), os.path.join("workspace", "测试数据"), os.path.join("workspace", "测试报告"), - os.path.join("workspace", "测试报告", "allure-results"), - os.path.join("workspace", "测试报告", "jmeter-results"), - os.path.join("workspace", "测试报告", "jmeter-report"), - os.path.join("workspace", "测试报告", "coverage-report"), - os.path.join("workspace", "测试报告", "baselines"), - os.path.join("workspace", "测试报告", "history"), - os.path.join("workspace", "测试报告", "screenshots"), os.path.join("workspace", "自动化脚本", "python", "pages"), os.path.join("workspace", "自动化脚本", "python", "api"), os.path.join("workspace", "自动化脚本", "python", "tests"), diff --git a/runtime/learning_loop/INDEX.md b/runtime/learning_loop/INDEX.md index 54f612d..cf2a580 100644 --- a/runtime/learning_loop/INDEX.md +++ b/runtime/learning_loop/INDEX.md @@ -27,5 +27,5 @@ learning_loop/curator (协调:何时跑+谁来跑) ↓ 触发 darwin-skill/SKILL.md (执行:8 维评分+棘轮) ↓ 落 -workspace/测试报告/skill-evolution/results.tsv +workspace/测试报告/{项目名}/skill-evolution/results.tsv ``` diff --git a/runtime/observability/audit.py b/runtime/observability/audit.py index 2640400..f74cbf2 100644 --- a/runtime/observability/audit.py +++ b/runtime/observability/audit.py @@ -7,6 +7,7 @@ from __future__ import annotations import json +import os import threading from datetime import datetime, timezone from pathlib import Path @@ -14,7 +15,7 @@ from loguru import logger -_DEFAULT_DIR = Path("workspace/测试报告/audit") +_DEFAULT_DIR = Path(f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/audit") _lock = threading.Lock() diff --git a/runtime/orchestrator/adapters/experts.py b/runtime/orchestrator/adapters/experts.py index 1f5c40b..603e3d1 100644 --- a/runtime/orchestrator/adapters/experts.py +++ b/runtime/orchestrator/adapters/experts.py @@ -16,6 +16,7 @@ from __future__ import annotations import json +import os from dataclasses import dataclass from pathlib import Path @@ -96,13 +97,13 @@ def _get_impl_status(name: str, kind: str) -> str: # Scripts that require CLI args; injected when DAG node provides no inputs. # Explicit DAG inputs always win; defaults only fill the gap. SCRIPT_DEFAULT_ARGS: dict[str, dict[str, str]] = { - "generate_report.py": {"data": "workspace/测试报告/_selftest_summary.json"}, + "generate_report.py": {"data": f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/_selftest_summary.json"}, } # Fixture content materialized on demand when a SCRIPT_DEFAULT_ARGS value points to # a missing file. Keys are workspace-relative paths. SCRIPT_FIXTURES: dict[str, dict] = { - "workspace/测试报告/_selftest_summary.json": { + f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/_selftest_summary.json": { "project_name": "Test-Agent selftest fixture", "version": "0.0.0-selftest", "environment": "ci", diff --git a/runtime/orchestrator/skills/eval_harness.py b/runtime/orchestrator/skills/eval_harness.py index 22ddf48..8cade3d 100644 --- a/runtime/orchestrator/skills/eval_harness.py +++ b/runtime/orchestrator/skills/eval_harness.py @@ -66,7 +66,7 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "seed_fixed": 42\n' " },\n" ' "phases": [\n' - ' {"phase": 1, "name": "eval_config", "estimated_min": 5, "config": {"capture_mode": "opt-in", "output_dir": "workspace/测试报告/eval/", "seed": 42, "k_samples": 10}, "depends_on": []},\n' + ' {"phase": 1, "name": "eval_config", "estimated_min": 5, "config": {"capture_mode": "opt-in", "output_dir": "workspace/测试报告/{项目名}/eval/", "seed": 42, "k_samples": 10}, "depends_on": []},\n' ' {"phase": 2, "name": "pass_at_k", "estimated_min": 20, "cases": [{"test_id": "string", "prompt": "string", "expected": "string", "k": 10, "threshold": 0.7}], "depends_on": ["eval_config"]},\n' ' {"phase": 3, "name": "stability_check", "estimated_min": 15, "cases": [{"test_id": "string", "prompt": "string", "runs": 5, "metric": "top1_consistency|jaccard_k|semantic_equiv"}], "depends_on": ["eval_config"]},\n' ' {"phase": 4, "name": "latency_check", "estimated_min": 10, "cases": [{"test_id": "string", "endpoint": "string", "runs": 100, "metrics": ["p50_ms", "p95_ms", "p99_ms"]}], "depends_on": ["eval_config"]},\n' @@ -81,10 +81,10 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "pii_leak": 0\n' " },\n" ' "outputs": {\n' - ' "eval_dir": "workspace/测试报告/eval/",\n' - ' "capture_dir": "workspace/测试报告/eval/captures/",\n' - ' "replay_dir": "workspace/测试报告/eval/replays/",\n' - ' "report_dir": "workspace/测试报告/eval/reports/",\n' + ' "eval_dir": "workspace/测试报告/{项目名}/eval/",\n' + ' "capture_dir": "workspace/测试报告/{项目名}/eval/captures/",\n' + ' "replay_dir": "workspace/测试报告/{项目名}/eval/replays/",\n' + ' "report_dir": "workspace/测试报告/{项目名}/eval/reports/",\n' ' "allure_dir": "workspace/Allure/eval/{run_id}/"\n' " },\n" ' "risks": ["string,如 黄金集过小致 overfit / prompt 顺序敏感 / 非确定性模型 top-1 随机"],\n' @@ -112,7 +112,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "config": { "capture_mode": "opt-in", - "output_dir": "workspace/测试报告/eval/", + "output_dir": "workspace/测试报告/{项目名}/eval/", "seed": 42, "k_samples": 10, }, @@ -156,8 +156,8 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/eval/selftest-20260516-000005/", - "workspace/测试报告/eval/reports/", - "workspace/测试报告/eval/captures/", + "workspace/测试报告/{项目名}/eval/reports/", + "workspace/测试报告/{项目名}/eval/captures/", ], "depends_on": ["pass_at_k", "stability_check", "latency_check"], }, @@ -171,10 +171,10 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "pii_leak": 0, }, "outputs": { - "eval_dir": "workspace/测试报告/eval/", - "capture_dir": "workspace/测试报告/eval/captures/", - "replay_dir": "workspace/测试报告/eval/replays/", - "report_dir": "workspace/测试报告/eval/reports/", + "eval_dir": "workspace/测试报告/{项目名}/eval/", + "capture_dir": "workspace/测试报告/{项目名}/eval/captures/", + "replay_dir": "workspace/测试报告/{项目名}/eval/replays/", + "report_dir": "workspace/测试报告/{项目名}/eval/reports/", "allure_dir": "workspace/Allure/eval/selftest-20260516-000005/", }, "risks": [ diff --git a/runtime/orchestrator/skills/mobile_test.py b/runtime/orchestrator/skills/mobile_test.py index 4bc3cd0..18ac715 100644 --- a/runtime/orchestrator/skills/mobile_test.py +++ b/runtime/orchestrator/skills/mobile_test.py @@ -89,11 +89,11 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "outputs": {\n' ' "test_scripts_dir": "workspace/自动化脚本/python/mobile/",\n' ' "miniprogram_dir": "workspace/自动化脚本/python/miniprogram/",\n' - ' "perf_dir": "workspace/测试报告/mobile-perf/",\n' - ' "logcat_dir": "workspace/测试报告/logcat/",\n' - ' "ios_syslog_dir": "workspace/测试报告/ios-syslog/",\n' - ' "screenshot_dir": "workspace/测试报告/screenshots/",\n' - ' "monkey_dir": "workspace/测试报告/monkey/",\n' + ' "perf_dir": "workspace/测试报告/{项目名}/mobile-perf/",\n' + ' "logcat_dir": "workspace/测试报告/{项目名}/logcat/",\n' + ' "ios_syslog_dir": "workspace/测试报告/{项目名}/ios-syslog/",\n' + ' "screenshot_dir": "workspace/测试报告/{项目名}/screenshots/",\n' + ' "monkey_dir": "workspace/测试报告/{项目名}/monkey/",\n' ' "allure_dir": "workspace/Allure/mobile/{run_id}/"\n' " },\n" ' "risks": ["string,如 设备断连 / Appium session 超时 / 云真机 API 限速"],\n' @@ -178,9 +178,9 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/mobile/selftest-20260516-000002/", - "workspace/测试报告/mobile-perf/", - "workspace/测试报告/logcat/", - "workspace/测试报告/screenshots/", + "workspace/测试报告/{项目名}/mobile-perf/", + "workspace/测试报告/{项目名}/logcat/", + "workspace/测试报告/{项目名}/screenshots/", ], "depends_on": ["test_execution"], }, @@ -214,11 +214,11 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "outputs": { "test_scripts_dir": "workspace/自动化脚本/python/mobile/", "miniprogram_dir": "workspace/自动化脚本/python/miniprogram/", - "perf_dir": "workspace/测试报告/mobile-perf/", - "logcat_dir": "workspace/测试报告/logcat/", - "ios_syslog_dir": "workspace/测试报告/ios-syslog/", - "screenshot_dir": "workspace/测试报告/screenshots/", - "monkey_dir": "workspace/测试报告/monkey/", + "perf_dir": "workspace/测试报告/{项目名}/mobile-perf/", + "logcat_dir": "workspace/测试报告/{项目名}/logcat/", + "ios_syslog_dir": "workspace/测试报告/{项目名}/ios-syslog/", + "screenshot_dir": "workspace/测试报告/{项目名}/screenshots/", + "monkey_dir": "workspace/测试报告/{项目名}/monkey/", "allure_dir": "workspace/Allure/mobile/selftest-20260516-000002/", }, "risks": [ diff --git a/runtime/orchestrator/skills/pentest_coordinator.py b/runtime/orchestrator/skills/pentest_coordinator.py index a70117a..92d5433 100644 --- a/runtime/orchestrator/skills/pentest_coordinator.py +++ b/runtime/orchestrator/skills/pentest_coordinator.py @@ -61,7 +61,7 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "tagent_yml_scope_required": true,\n' ' "target_in_scope_required": true,\n' ' "non_prod_required": true,\n' - ' "evidence_path": "workspace/测试报告/decisions/pentest_{run_id}_authorized.json"\n' + ' "evidence_path": "workspace/测试报告/{项目名}/decisions/pentest_{run_id}_authorized.json"\n' " },\n" ' "phases": [\n' ' {"phase": 1, "name": "recon", "skill": "pentest-recon", "estimated_min": 20, "concurrency": "single", "depends_on": []},\n' @@ -77,7 +77,7 @@ def user_prompt(self, ctx: RunnerContext) -> str: " },\n" ' "outputs": {\n' ' "report_path": "workspace/渗透报告/pentest_{target}_{date}.md",\n' - ' "evidence_dir": "workspace/测试报告/evidence/{run_id}/",\n' + ' "evidence_dir": "workspace/测试报告/{项目名}/evidence/{run_id}/",\n' ' "bug_tickets_format": "CVSS → P0-P3 (主宪章 §18-4)",\n' ' "allure_report": "workspace/Allure/pentest/{run_id}/"\n' " },\n" @@ -101,7 +101,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "tagent_yml_scope_required": True, "target_in_scope_required": True, "non_prod_required": True, - "evidence_path": "workspace/测试报告/decisions/pentest_selftest-20260516-000001_authorized.json", + "evidence_path": "workspace/测试报告/{项目名}/decisions/pentest_selftest-20260516-000001_authorized.json", }, "phases": [ { @@ -152,7 +152,7 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 }, "outputs": { "report_path": "workspace/渗透报告/pentest_staging.example.com_20260516.md", - "evidence_dir": "workspace/测试报告/evidence/selftest-20260516-000001/", + "evidence_dir": "workspace/测试报告/{项目名}/evidence/selftest-20260516-000001/", "bug_tickets_format": "CVSS 9-10=P0 / 7-8.9=P1 / 4-6.9=P2 / <4=P3 (主宪章 §18-4)", "allure_report": "workspace/Allure/pentest/selftest-20260516-000001/", }, diff --git a/runtime/orchestrator/skills/system_test.py b/runtime/orchestrator/skills/system_test.py index 86c2c14..93a641a 100644 --- a/runtime/orchestrator/skills/system_test.py +++ b/runtime/orchestrator/skills/system_test.py @@ -84,10 +84,10 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "mq": {"utils": ["mq_helper"], "optional": false}\n' " },\n" ' "outputs": {\n' - ' "iot_dir": "workspace/测试报告/iot-logs/",\n' - ' "media_dir": "workspace/测试报告/media-logs/",\n' - ' "trace_dir": "workspace/测试报告/trace-logs/",\n' - ' "mq_dir": "workspace/测试报告/mq-logs/",\n' + ' "iot_dir": "workspace/测试报告/{项目名}/iot-logs/",\n' + ' "media_dir": "workspace/测试报告/{项目名}/media-logs/",\n' + ' "trace_dir": "workspace/测试报告/{项目名}/trace-logs/",\n' + ' "mq_dir": "workspace/测试报告/{项目名}/mq-logs/",\n' ' "allure_dir": "workspace/Allure/system/{run_id}/"\n' " },\n" ' "risks": ["string,如 SSH 超时 / 串口断连 / MQTT broker 离线 / Kafka offset 丢失"],\n' @@ -172,10 +172,10 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/system/selftest-20260516-000004/", - "workspace/测试报告/iot-logs/", - "workspace/测试报告/media-logs/", - "workspace/测试报告/trace-logs/", - "workspace/测试报告/mq-logs/", + "workspace/测试报告/{项目名}/iot-logs/", + "workspace/测试报告/{项目名}/media-logs/", + "workspace/测试报告/{项目名}/trace-logs/", + "workspace/测试报告/{项目名}/mq-logs/", ], "depends_on": ["iot_test", "media_validation", "tracing_validation", "mq_validation"], }, @@ -199,10 +199,10 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "mq": {"utils": ["mq_helper"], "optional": False}, }, "outputs": { - "iot_dir": "workspace/测试报告/iot-logs/", - "media_dir": "workspace/测试报告/media-logs/", - "trace_dir": "workspace/测试报告/trace-logs/", - "mq_dir": "workspace/测试报告/mq-logs/", + "iot_dir": "workspace/测试报告/{项目名}/iot-logs/", + "media_dir": "workspace/测试报告/{项目名}/media-logs/", + "trace_dir": "workspace/测试报告/{项目名}/trace-logs/", + "mq_dir": "workspace/测试报告/{项目名}/mq-logs/", "allure_dir": "workspace/Allure/system/selftest-20260516-000004/", }, "risks": [ diff --git a/runtime/orchestrator/skills/visual_test.py b/runtime/orchestrator/skills/visual_test.py index 2f51e4c..1fb7df2 100644 --- a/runtime/orchestrator/skills/visual_test.py +++ b/runtime/orchestrator/skills/visual_test.py @@ -87,9 +87,9 @@ def user_prompt(self, ctx: RunnerContext) -> str: ' "outputs": {\n' ' "template_dir": "workspace/自动化脚本/python/visual/images/",\n' ' "baseline_dir": "workspace/自动化脚本/python/visual/baselines/",\n' - ' "diff_dir": "workspace/测试报告/visual-diffs/",\n' - ' "ocr_dir": "workspace/测试报告/visual-ocr/",\n' - ' "screenshot_dir": "workspace/测试报告/screenshots/visual/",\n' + ' "diff_dir": "workspace/测试报告/{项目名}/visual-diffs/",\n' + ' "ocr_dir": "workspace/测试报告/{项目名}/visual-ocr/",\n' + ' "screenshot_dir": "workspace/测试报告/{项目名}/screenshots/visual/",\n' ' "allure_dir": "workspace/Allure/visual/{run_id}/"\n' " },\n" ' "risks": ["string,如 设备断连 / 分辨率差异致误报 / OCR 字体缺失 / 动态内容 false positive"],\n' @@ -156,8 +156,8 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "estimated_min": 5, "outputs": [ "workspace/Allure/visual/selftest-20260516-000003/", - "workspace/测试报告/visual-diffs/", - "workspace/测试报告/screenshots/visual/", + "workspace/测试报告/{项目名}/visual-diffs/", + "workspace/测试报告/{项目名}/screenshots/visual/", ], "depends_on": ["visual_regression"], }, @@ -182,9 +182,9 @@ def mock_output(self, ctx: RunnerContext) -> dict[str, Any]: # noqa: ARG002 "outputs": { "template_dir": "workspace/自动化脚本/python/visual/images/", "baseline_dir": "workspace/自动化脚本/python/visual/baselines/", - "diff_dir": "workspace/测试报告/visual-diffs/", - "ocr_dir": "workspace/测试报告/visual-ocr/", - "screenshot_dir": "workspace/测试报告/screenshots/visual/", + "diff_dir": "workspace/测试报告/{项目名}/visual-diffs/", + "ocr_dir": "workspace/测试报告/{项目名}/visual-ocr/", + "screenshot_dir": "workspace/测试报告/{项目名}/screenshots/visual/", "allure_dir": "workspace/Allure/visual/selftest-20260516-000003/", }, "risks": [ diff --git a/scripts/_demo-commands.sh b/scripts/_demo-commands.sh index 8f788c2..113e96d 100644 --- a/scripts/_demo-commands.sh +++ b/scripts/_demo-commands.sh @@ -25,7 +25,7 @@ step() { } # 清干净(录制前) -rm -rf workspace/_demo workspace/测试报告/*.json workspace/测试用例/_smoke_out workspace/_init_smoke 2>/dev/null || true +rm -rf workspace/_demo workspace/测试报告/{项目名}/*.json workspace/测试用例/_smoke_out workspace/_init_smoke 2>/dev/null || true # Step 1 · init step "Step 1/4 · 一键初始化(stub LLM,0 API key)" @@ -53,12 +53,12 @@ sleep 3 # Outro · 看产物 step "产物清单" -prompt "ls workspace/测试报告/*.json" -ls workspace/测试报告/*.json 2>/dev/null +prompt "ls workspace/测试报告/{项目名}/*.json" +ls workspace/测试报告/{项目名}/*.json 2>/dev/null sleep 2 -prompt "cat workspace/测试报告/decisions/final_verdict_*.json | head -10" -cat workspace/测试报告/decisions/final_verdict_*.json 2>/dev/null | head -12 +prompt "cat workspace/测试报告/{项目名}/decisions/final_verdict_*.json | head -10" +cat workspace/测试报告/{项目名}/decisions/final_verdict_*.json 2>/dev/null | head -12 sleep 4 # CTA diff --git a/skills/agent-introspection-debugging.md b/skills/agent-introspection-debugging.md index 8bf014d..0edb272 100644 --- a/skills/agent-introspection-debugging.md +++ b/skills/agent-introspection-debugging.md @@ -18,7 +18,7 @@ SKILL_IMPL_STATUS: production | 维 | 工具 | |----|------| -| **决策回放** | `workspace/测试报告/decisions/` JSON 时间序 | +| **决策回放** | `workspace/测试报告/{项目名}/decisions/` JSON 时间序 | | **工具调用** | OTel span(`runtime/observability/otel.py`)+ Loguru | | **token 消耗** | LLM provider header + LiteLLM 记账 | | **上下文** | prompt 长度 + 截断点 + 主-子 session 隔离审查 | diff --git a/skills/ai-test.md b/skills/ai-test.md index befbcc0..4b946d4 100644 --- a/skills/ai-test.md +++ b/skills/ai-test.md @@ -65,7 +65,7 @@ pytest -m "ai and llm" -v ## 输出文件 ```text -workspace/测试报告/ +workspace/测试报告/{项目名}/ ├── ai-eval/ ├── ai-drift/ ├── ai-fairness/ diff --git a/skills/data-preparation.md b/skills/data-preparation.md index d9b6132..4fd47d2 100644 --- a/skills/data-preparation.md +++ b/skills/data-preparation.md @@ -171,7 +171,7 @@ atexit.register(manager.cleanup) |------|------|--------| | `workspace/测试数据/test_data.json` | pytest 功能测试账号(conftest fixture 自动加载) | conftest / automation-engineer | | `workspace/测试数据/jmeter_users.csv` | JMeter 参数化数据 | jmeter-script-gen / test-executor | -| `workspace/测试报告/数据准备报告_{日期}.json` | 数据准备详情 | test-lead | +| `workspace/测试报告/{项目名}/数据准备报告_{日期}.json` | 数据准备详情 | test-lead | ## ⚠️ 数据安全要求 diff --git a/skills/desktop-test.md b/skills/desktop-test.md index c0ee8bf..7152c89 100644 --- a/skills/desktop-test.md +++ b/skills/desktop-test.md @@ -88,7 +88,7 @@ python -m utils.websocket_helper load \ ```bash python -m utils.desktop_driver collect-perf \ --pid --duration 60 \ - --output workspace/测试报告/desktop-perf/ + --output workspace/测试报告/{项目名}/desktop-perf/ ``` ## 质量门禁 diff --git a/skills/jmeter-script-gen.md b/skills/jmeter-script-gen.md index 7d4852c..e0b5eed 100644 --- a/skills/jmeter-script-gen.md +++ b/skills/jmeter-script-gen.md @@ -24,7 +24,7 @@ SKILL_IMPL_STATUS: script □ 目标接口信息:URL(解析为 host/protocol/port 三参,不含协议前缀) □ 性能目标:目标 TPS / P95 / 并发数(决定 PERF_MODE) □ workspace/自动化脚本/jmeter/ 目录已存在(conftest 自动建) -□ workspace/测试报告/baselines/perf_baseline.json(基线对比,可选) +□ workspace/测试报告/{项目名}/baselines/perf_baseline.json(基线对比,可选) ``` ## 数据流(与其他 Agent 闭环) @@ -252,7 +252,7 @@ test_user_b9k7,Test@123456,xxxx-xxxx-xxxx-xxxx false - workspace/测试报告/jmeter-results/result.jtl + workspace/测试报告/{项目名}/jmeter-results/result.jtl @@ -300,8 +300,8 @@ test_user_b9k7,Test@123456,xxxx-xxxx-xxxx-xxxx # CI 默认:ci_quick jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/result.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/result.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -310,8 +310,8 @@ jmeter -n \ # 完整压测:full(手动 / release) jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/result.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/result.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -320,7 +320,7 @@ jmeter -n \ # 阶梯加压 jmeter -n \ -t workspace/自动化脚本/jmeter/stepped_load.jmx \ - -l workspace/测试报告/jmeter-results/stepped_result.jtl \ + -l workspace/测试报告/{项目名}/jmeter-results/stepped_result.jtl \ -Jtarget_host="${TARGET_HOST}" ``` @@ -341,14 +341,14 @@ jmeter -n \ ```bash # CI quick python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode ci_quick # Full + 基线对比 + 通过则更新基线 python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode full \ - --baseline workspace/测试报告/baselines/perf_baseline.json \ + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json \ --update-baseline ``` @@ -383,8 +383,8 @@ python -m utils.jmeter_result_parser \ "regression_pct": 3.2, "is_regression": false }, - "html_report": "workspace/测试报告/jmeter-report/index.html", - "jtl_file": "workspace/测试报告/jmeter-results/result.jtl" + "html_report": "workspace/测试报告/{项目名}/jmeter-report/index.html", + "jtl_file": "workspace/测试报告/{项目名}/jmeter-results/result.jtl" } ``` @@ -399,7 +399,7 @@ workspace/自动化脚本/jmeter/ workspace/测试数据/ └── jmeter_users.csv # 参数化数据(data-preparer 生成) -workspace/测试报告/ +workspace/测试报告/{项目名}/ ├── jmeter-results/result.jtl # 原始结果(CSV) ├── jmeter-report/index.html # JMeter HTML 可视化 └── baselines/perf_baseline.json @@ -414,7 +414,7 @@ workspace/测试报告/ ✅ 每个请求必须有响应断言(防静默失败) ✅ JSONPostProcessor 提取 Token(不用旧名 JSONPathExtractor) ✅ 登录失败时 If Controller 中止后续请求 -✅ 结果保存到 workspace/测试报告/jmeter-results/ +✅ 结果保存到 workspace/测试报告/{项目名}/jmeter-results/ ✅ 解析与门禁统一调 utils/jmeter_result_parser.py ✅ 性能 Bug 提交给 bug-manager(标题:[性能]-[接口名]-[指标超标]) ``` diff --git a/skills/mobile-test.md b/skills/mobile-test.md index 00926c9..60ef3a8 100644 --- a/skills/mobile-test.md +++ b/skills/mobile-test.md @@ -95,7 +95,7 @@ python -m utils.mobile_driver collect-perf \ --platform android \ --package com.example.app \ --duration 60 \ - --output workspace/测试报告/mobile-perf/ + --output workspace/测试报告/{项目名}/mobile-perf/ ``` ### Step 5b:Android Monkey 稳定性(可选,长时压测) @@ -118,9 +118,9 @@ pytest -m "mobile and android and stability" -v ``` monkey 自动产出: -- `workspace/测试报告/monkey/monkey__<时间>.log`(事件序列) -- `workspace/测试报告/monkey/monkey__<时间>.json`(摘要:crash/anr/duration) -- `workspace/测试报告/logcat/logcat_<时间>.log`(同步归档) +- `workspace/测试报告/{项目名}/monkey/monkey__<时间>.log`(事件序列) +- `workspace/测试报告/{项目名}/monkey/monkey__<时间>.json`(摘要:crash/anr/duration) +- `workspace/测试报告/{项目名}/logcat/logcat_<时间>.log`(同步归档) ### Step 6:报告与归档 diff --git a/skills/pentest-coordinator.md b/skills/pentest-coordinator.md index faa5a23..1ee9d9c 100644 --- a/skills/pentest-coordinator.md +++ b/skills/pentest-coordinator.md @@ -19,7 +19,7 @@ SKILL_IMPL_STATUS: production 1. 读 `tagent.yml`:`pentest.authorized: true` + `pentest.scope: [list]` **必须显式**;否则拒绝(§24 safe-by-default) 2. `target` 必须在 `scope` 内;不在 → 拒绝 3. `prod` 环境 → 拒绝;只允许 staging/sandbox/dev -4. 落 `workspace/测试报告/decisions/pentest_{run_id}_authorized.json` 记授权来源 +4. 落 `workspace/测试报告/{项目名}/decisions/pentest_{run_id}_authorized.json` 记授权来源 ## 流程(5 阶段并发) @@ -40,7 +40,7 @@ SKILL_IMPL_STATUS: production ## 输出 - `workspace/渗透报告/pentest_{target}_{date}.md`(仅 PoC 漏洞) -- `workspace/测试报告/evidence/{run_id}/`(HAR / 截图 / 录屏 / req-resp) +- `workspace/测试报告/{项目名}/evidence/{run_id}/`(HAR / 截图 / 录屏 / req-resp) - Bug 单按 CVSS 映射 P0-P3 - Allure 报告(每漏洞一个 case) diff --git a/skills/python-script-gen.md b/skills/python-script-gen.md index d0026a8..1c59084 100644 --- a/skills/python-script-gen.md +++ b/skills/python-script-gen.md @@ -206,5 +206,5 @@ $env:HEADLESS="false"; pytest workspace/自动化脚本/python/tests/test_p0_smo # 生成 Allure 报告 pytest workspace/自动化脚本/python/tests/ \ - --alluredir=workspace/测试报告/allure-results -v + --alluredir=workspace/测试报告/{项目名}/allure-results -v ``` diff --git a/skills/regression-test.md b/skills/regression-test.md index c41a971..3b99808 100644 --- a/skills/regression-test.md +++ b/skills/regression-test.md @@ -19,8 +19,8 @@ SKILL_IMPL_STATUS: production □ APP_SRC_PATH 指向被测系统源码(覆盖率指向) □ workspace/regression_modules.yaml 配置(git diff 影响分析,可选) □ JMeter 5.6.3 + Java JRE(性能阶段) -□ workspace/测试报告/baselines/perf_baseline.json(基线对比,首次跑会建) -□ workspace/测试报告/history/*.xml(Flaky 检测,至少 2 次执行后才有) +□ workspace/测试报告/{项目名}/baselines/perf_baseline.json(基线对比,首次跑会建) +□ workspace/测试报告/{项目名}/history/*.xml(Flaky 检测,至少 2 次执行后才有) ``` ## 📋 执行流程 @@ -79,11 +79,11 @@ pytest workspace/自动化脚本/python/ \ -n 4 --timeout=120 \ --reruns=2 --reruns-delay=5 \ --cov="${APP_SRC}" \ - --cov-report=html:workspace/测试报告/coverage-report \ - --cov-report=xml:workspace/测试报告/coverage.xml \ + --cov-report=html:workspace/测试报告/{项目名}/coverage-report \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage.xml \ --cov-fail-under=80 \ - --alluredir=workspace/测试报告/regression-allure-results \ - --junitxml=workspace/测试报告/regression-results.xml \ + --alluredir=workspace/测试报告/{项目名}/regression-allure-results \ + --junitxml=workspace/测试报告/{项目名}/regression-results.xml \ --tb=short -q ``` @@ -96,8 +96,8 @@ pytest workspace/自动化脚本/python/ \ ```bash # 归档当前 junit-xml 到 history python -m utils.flaky_detector \ - --archive workspace/测试报告/regression-results.xml \ - --history workspace/测试报告/history \ + --archive workspace/测试报告/{项目名}/regression-results.xml \ + --history workspace/测试报告/{项目名}/history \ --limit 5 # 输出 flaky 候选清单(JSON): # [{"test_id": "...", "fail_rate_pct": 40.0, "history": ["passed","failed",...], "action": "quarantine"}] @@ -114,8 +114,8 @@ python -m utils.flaky_detector \ from utils.ci_quality_gate import parse_junit from pathlib import Path -current = parse_junit("workspace/测试报告/regression-results.xml") -history_files = sorted(Path("workspace/测试报告/history").glob("*.xml"))[-2:-1] +current = parse_junit("workspace/测试报告/{项目名}/regression-results.xml") +history_files = sorted(Path("workspace/测试报告/{项目名}/history").glob("*.xml"))[-2:-1] if history_files: previous = parse_junit(str(history_files[0])) print(f"通过率变化: {current['pass_rate_pct'] - previous['pass_rate_pct']:+.1f} pct") @@ -139,8 +139,8 @@ fi jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/regression_perf.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/regression_perf.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -148,9 +148,9 @@ jmeter -n \ # 性能门禁 + 基线对比 python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/regression_perf.jtl \ + workspace/测试报告/{项目名}/jmeter-results/regression_perf.jtl \ --mode "${PERF_MODE}" \ - --baseline workspace/测试报告/baselines/perf_baseline.json \ + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json \ --regression-max-pct 20 ``` diff --git a/skills/smoke-test.md b/skills/smoke-test.md index 45d5045..9898485 100644 --- a/skills/smoke-test.md +++ b/skills/smoke-test.md @@ -56,8 +56,8 @@ pytest workspace/自动化脚本/python/ \ -v -m "p0" \ --timeout=60 \ -n 2 \ - --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/测试报告/smoke-results.xml \ + --alluredir=workspace/测试报告/{项目名}/allure-results \ + --junitxml=workspace/测试报告/{项目名}/smoke-results.xml \ --tb=short \ --no-header ``` @@ -68,15 +68,15 @@ pytest workspace/自动化脚本/python/ \ ```bash python -m utils.ci_quality_gate \ - --smoke-xml workspace/测试报告/smoke-results.xml \ - --output-json workspace/测试报告/smoke_gate_result.json + --smoke-xml workspace/测试报告/{项目名}/smoke-results.xml \ + --output-json workspace/测试报告/{项目名}/smoke_gate_result.json ``` ### 阶段6:报告生成(1 分钟,缓冲) ```bash -allure generate workspace/测试报告/allure-results \ - --output workspace/测试报告/allure-report \ +allure generate workspace/测试报告/{项目名}/allure-results \ + --output workspace/测试报告/{项目名}/allure-report \ --clean ``` diff --git a/skills/system-test.md b/skills/system-test.md index 0d15292..83c7409 100644 --- a/skills/system-test.md +++ b/skills/system-test.md @@ -89,7 +89,7 @@ pytest -m "system and p0" -v ## 输出文件 ```text -workspace/测试报告/ +workspace/测试报告/{项目名}/ ├── iot-logs/ ├── media-frames/ ├── tracing/ diff --git a/skills/test-coordinator.md b/skills/test-coordinator.md index d81c72d..af30393 100644 --- a/skills/test-coordinator.md +++ b/skills/test-coordinator.md @@ -145,7 +145,7 @@ output: ### Step 4:环境健康(env-manager) ```text -output: workspace/测试报告/环境检查_{时间戳}.json +output: workspace/测试报告/{项目名}/环境检查_{时间戳}.json 失败 → 重试 10/20/40s → 仍失败则阻止后续步骤 ``` @@ -180,10 +180,10 @@ output: pytest -m "p0 or p1" \ -n 4 --reruns=2 --reruns-delay=5 --timeout=120 \ --cov="${APP_SRC_PATH:-./src}" \ - --cov-report=xml:workspace/测试报告/coverage.xml \ + --cov-report=xml:workspace/测试报告/{项目名}/coverage.xml \ --cov-fail-under=80 \ - --alluredir=workspace/测试报告/allure-results \ - --junitxml=workspace/测试报告/regression-results.xml + --alluredir=workspace/测试报告/{项目名}/allure-results \ + --junitxml=workspace/测试报告/{项目名}/regression-results.xml ``` 阻塞条件:通过率 < 90% 时停止,不执行性能测试。 @@ -203,8 +203,8 @@ fi # TARGET_HOST/PROTOCOL/PORT 由 conftest 或 .env 解析(不含协议前缀) jmeter -n \ -t workspace/自动化脚本/jmeter/test_plan.jmx \ - -l workspace/测试报告/jmeter-results/result.jtl \ - -e -o workspace/测试报告/jmeter-report/ \ + -l workspace/测试报告/{项目名}/jmeter-results/result.jtl \ + -e -o workspace/测试报告/{项目名}/jmeter-report/ \ -Jtarget_host="${TARGET_HOST}" \ -Jtarget_protocol="${TARGET_PROTOCOL:-http}" \ -Jtarget_port="${TARGET_PORT:-80}" \ @@ -212,9 +212,9 @@ jmeter -n \ # 解析 + 门禁 python -m utils.jmeter_result_parser \ - workspace/测试报告/jmeter-results/result.jtl \ + workspace/测试报告/{项目名}/jmeter-results/result.jtl \ --mode "${PERF_MODE}" \ - --baseline workspace/测试报告/baselines/perf_baseline.json + --baseline workspace/测试报告/{项目名}/baselines/perf_baseline.json ``` ### Step 9:Bug 管理(bug-manager) @@ -237,7 +237,7 @@ output: - Word 测试报告(含性能基准对比) - Excel 数据报告 - 多端通知:企业微信/飞书/钉钉/Slack/邮件/Teams(自动跳过未配置) -保存:workspace/测试报告/ +保存:workspace/测试报告/{项目名}/ ``` ### Step 11:最终决策(test-lead) diff --git a/skills/visual-test.md b/skills/visual-test.md index 10e7e8c..c12711e 100644 --- a/skills/visual-test.md +++ b/skills/visual-test.md @@ -68,15 +68,15 @@ pytest -m "visual and ocr" -v ```bash python -m utils.visual_helper diff \ - --current workspace/测试报告/screenshots/login_current.png \ + --current workspace/测试报告/{项目名}/screenshots/login_current.png \ --baseline workspace/自动化脚本/python/visual/baselines/login_baseline.png \ - --output workspace/测试报告/screenshots/visual-diff/login_diff.png + --output workspace/测试报告/{项目名}/screenshots/visual-diff/login_diff.png ``` ### Step 5:基线更新(如确认 UI 变更合理) ```bash -cp workspace/测试报告/screenshots/login_current.png \ +cp workspace/测试报告/{项目名}/screenshots/login_current.png \ workspace/自动化脚本/python/visual/baselines/login_baseline.png git add workspace/自动化脚本/python/visual/baselines/ git commit -m "chore: update visual baseline for login" diff --git a/skills/zentao-bug-submission.md b/skills/zentao-bug-submission.md index 70b99ab..7c17659 100644 --- a/skills/zentao-bug-submission.md +++ b/skills/zentao-bug-submission.md @@ -86,7 +86,7 @@ from utils.zentao_bug_manager import ZentaoBugManager manager = ZentaoBugManager() -with open("workspace/测试报告/regression_summary.json", encoding="utf-8") as f: +with open("workspace/测试报告/{项目名}/regression_summary.json", encoding="utf-8") as f: results = json.load(f) submitted = manager.batch_submit_from_failures( diff --git a/utils/a11y_i18n/a11y_scanner.py b/utils/a11y_i18n/a11y_scanner.py index 12e9a43..79e3695 100644 --- a/utils/a11y_i18n/a11y_scanner.py +++ b/utils/a11y_i18n/a11y_scanner.py @@ -10,6 +10,7 @@ """ import json import logging +import os import subprocess from pathlib import Path from typing import Dict, List, Optional @@ -60,7 +61,9 @@ def scan_with_axe(page, url: Optional[str] = None) -> Dict: # ===== Lighthouse a11y ===== -def scan_with_lighthouse(url: str, output_dir: str = "workspace/测试报告/a11y") -> Dict: +def scan_with_lighthouse(url: str, output_dir: str = None) -> Dict: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/a11y" """需 npm install -g lighthouse""" Path(output_dir).mkdir(parents=True, exist_ok=True) out_json = Path(output_dir) / "lighthouse_a11y.json" diff --git a/utils/a11y_i18n/a11y_scanner_v2.py b/utils/a11y_i18n/a11y_scanner_v2.py index 29328d5..6f063dd 100644 --- a/utils/a11y_i18n/a11y_scanner_v2.py +++ b/utils/a11y_i18n/a11y_scanner_v2.py @@ -14,6 +14,7 @@ import json import logging +import os import subprocess from dataclasses import dataclass, field from pathlib import Path @@ -342,7 +343,9 @@ def full_scan(page, url: str) -> A11yReport: # External tool wrappers (backward compat with v1) # ═══════════════════════════════════════════════════════════════ -def scan_with_lighthouse(url: str, output_dir: str = "workspace/测试报告/a11y") -> dict: +def scan_with_lighthouse(url: str, output_dir: str = None) -> dict: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/a11y" """Run Lighthouse a11y audit. Requires: npm install -g lighthouse""" out_dir = Path(output_dir) out_dir.mkdir(parents=True, exist_ok=True) diff --git a/utils/a11y_i18n/fairness_auditor.py b/utils/a11y_i18n/fairness_auditor.py index bddc7b4..3ee52fc 100644 --- a/utils/a11y_i18n/fairness_auditor.py +++ b/utils/a11y_i18n/fairness_auditor.py @@ -19,6 +19,7 @@ import json import logging +import os from dataclasses import dataclass, field from pathlib import Path from typing import Any @@ -537,7 +538,9 @@ def audit_decision_fairness( # Report export # ═══════════════════════════════════════════════════════════════ -def export_bias_report(report: BiasReport, output_dir: str = "workspace/测试报告/ai-fairness") -> str: +def export_bias_report(report: BiasReport, output_dir: str = None) -> str: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/ai-fairness" """Export a BiasReport as JSON to the fairness workspace directory.""" from datetime import datetime diff --git a/utils/a11y_i18n/ux_metrics.py b/utils/a11y_i18n/ux_metrics.py index c51ffda..2120359 100644 --- a/utils/a11y_i18n/ux_metrics.py +++ b/utils/a11y_i18n/ux_metrics.py @@ -5,6 +5,7 @@ """ import json import logging +import os import time from datetime import datetime from pathlib import Path @@ -103,7 +104,9 @@ def error_recovery_rate(error_count: int, recovery_count: int) -> float: # ===== 持久化 ===== def save_ux_report(summaries: List[Dict], - output_dir: str = "workspace/测试报告/ux") -> str: + output_dir: str = None) -> str: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/ux" Path(output_dir).mkdir(parents=True, exist_ok=True) path = Path(output_dir) / f"ux_{datetime.now():%Y%m%d_%H%M%S}.json" path.write_text(json.dumps(summaries, indent=2, ensure_ascii=False), encoding="utf-8") diff --git a/utils/paths.py b/utils/paths.py new file mode 100644 index 0000000..704dcc0 --- /dev/null +++ b/utils/paths.py @@ -0,0 +1,39 @@ +"""Test-Agent workspace output path helpers. + +All paths follow: workspace/测试报告/{PROJECT_NAME}[/{run_id}]/{sub_path}""" + +import os +import uuid +from datetime import datetime +from pathlib import Path + +_RUN_ID: str | None = None + + +def get_project_name() -> str: + return os.getenv("PROJECT_NAME", "default") + + +def get_output_base(project: str | None = None) -> Path: + if project is None: + project = get_project_name() + return Path("workspace/测试报告") / project + + +def get_output_dir(sub_path: str = "", run_id: str | None = None) -> Path: + """workspace/测试报告/{PROJECT_NAME}[/{run_id}]/{sub_path} + + run_id=None → project-level (baselines/history/decisions) + run_id=str → per-run isolation (screenshots/allure-results/...) + """ + base = get_output_base() + if run_id: + base = base / run_id + return base / sub_path if sub_path else base + + +def current_run_id() -> str: + global _RUN_ID + if _RUN_ID is None: + _RUN_ID = os.getenv("RUN_ID") or f"{datetime.now():%Y%m%d_%H%M%S}_{uuid.uuid4().hex[:6]}" + return _RUN_ID diff --git a/utils/performance/jmeter_result_parser.py b/utils/performance/jmeter_result_parser.py index a1b871b..ac1b0f8 100644 --- a/utils/performance/jmeter_result_parser.py +++ b/utils/performance/jmeter_result_parser.py @@ -6,6 +6,7 @@ import csv import json import logging +import os import sys from pathlib import Path from statistics import mean @@ -134,7 +135,7 @@ def main(): parser = argparse.ArgumentParser(description="JMeter JTL 解析 + 性能门禁") parser.add_argument("jtl", help="JTL 文件路径") parser.add_argument("--mode", choices=["full", "ci_quick"], default="full") - parser.add_argument("--baseline", default="workspace/测试报告/baselines/perf_baseline.json") + parser.add_argument("--baseline", default=f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/baselines/perf_baseline.json") parser.add_argument("--update-baseline", action="store_true", help="本次结果写入基线") parser.add_argument("--regression-max-pct", type=float, default=20.0) args = parser.parse_args() diff --git a/utils/performance/slo_validator.py b/utils/performance/slo_validator.py index 83e93bb..80e5714 100644 --- a/utils/performance/slo_validator.py +++ b/utils/performance/slo_validator.py @@ -11,6 +11,7 @@ """ import json import logging +import os from datetime import datetime, timedelta from pathlib import Path from typing import Dict, List, Optional @@ -127,7 +128,7 @@ def slo_report(metrics: Dict[str, float], parser = argparse.ArgumentParser(description="SLO/SLI 验证") parser.add_argument("--metrics", required=True, help="JSON 文件含 metrics") parser.add_argument("--slos", default=None, help="JSON 文件含 SLO 定义") - parser.add_argument("--output", default="workspace/测试报告/slo_report.json") + parser.add_argument("--output", default=f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/slo_report.json") args = parser.parse_args() metrics = json.loads(Path(args.metrics).read_text(encoding="utf-8")) slos = json.loads(Path(args.slos).read_text(encoding="utf-8")) if args.slos else None diff --git a/utils/performance/web_vitals_collector.py b/utils/performance/web_vitals_collector.py index 312d115..ae47be1 100644 --- a/utils/performance/web_vitals_collector.py +++ b/utils/performance/web_vitals_collector.py @@ -83,8 +83,10 @@ def collect_via_playwright(url: str, page=None, timeout: int = 30) -> Dict: # ===== 方式 2:Lighthouse CLI(更权威)===== -def collect_via_lighthouse(url: str, output_dir: str = "workspace/测试报告/web-vitals") -> Dict: +def collect_via_lighthouse(url: str, output_dir: str = None) -> Dict: """需安装 lighthouse: npm install -g lighthouse""" + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/web-vitals" Path(output_dir).mkdir(parents=True, exist_ok=True) json_path = Path(output_dir) / "lighthouse.json" diff --git a/utils/platforms/desktop_driver.py b/utils/platforms/desktop_driver.py index 7465ef8..805d8d8 100644 --- a/utils/platforms/desktop_driver.py +++ b/utils/platforms/desktop_driver.py @@ -231,8 +231,10 @@ def save_perf(samples: list, output_dir: str, prefix: str = "desktop_perf") -> s # ===== 跨平台截图 ===== -def screenshot(output: str = "workspace/测试报告/screenshots/desktop/screen.png"): +def screenshot(output: str = None): """跨平台截图""" + if output is None: + output = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/screenshots/desktop/screen.png" Path(output).parent.mkdir(parents=True, exist_ok=True) try: import pyautogui @@ -260,10 +262,10 @@ def main(): perf = sub.add_parser("collect-perf") perf.add_argument("--pid", type=int, required=True) perf.add_argument("--duration", type=int, default=60) - perf.add_argument("--output", default="workspace/测试报告/desktop-perf") + perf.add_argument("--output", default=f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/desktop-perf") shot = sub.add_parser("screenshot") - shot.add_argument("--output", default="workspace/测试报告/screenshots/desktop/screen.png") + shot.add_argument("--output", default=f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/screenshots/desktop/screen.png") args = parser.parse_args() if args.cmd == "collect-perf": diff --git a/utils/platforms/media_validator.py b/utils/platforms/media_validator.py index efa6691..870f73c 100644 --- a/utils/platforms/media_validator.py +++ b/utils/platforms/media_validator.py @@ -59,7 +59,9 @@ def extract_frame(video: str, timestamp_sec: float, output: str) -> str: def compare_frames(video_a: str, video_b: str, timestamps: List[float], ssim_threshold: float = 0.95, - tmp_dir: str = "workspace/测试报告/media-frames") -> List[Dict]: + tmp_dir: str = None) -> List[Dict]: + if tmp_dir is None: + tmp_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/media-frames" """ 在指定时间点抽帧对比两个视频,返回差异帧列表。 """ diff --git a/utils/platforms/mobile_driver.py b/utils/platforms/mobile_driver.py index 307bd34..390ea1a 100644 --- a/utils/platforms/mobile_driver.py +++ b/utils/platforms/mobile_driver.py @@ -246,11 +246,13 @@ def run_monkey( pct_touch: int = 40, pct_motion: int = 25, pct_nav: int = 15, pct_majornav: int = 10, pct_syskeys: int = 5, pct_appswitch: int = 2, pct_anyevent: int = 3, - output_dir: str = "workspace/测试报告/monkey", + output_dir: str = None, extra_args: Optional[list] = None, timeout: int = 3600, ) -> dict: """Execute Android Monkey stability test. Returns crash/ANR summary.""" + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/monkey" Path(output_dir).mkdir(parents=True, exist_ok=True) ts = datetime.now().strftime("%Y%m%d_%H%M%S") log_file = Path(output_dir) / f"monkey_{package}_{ts}.log" @@ -288,8 +290,10 @@ def run_monkey( # ===== logcat 归档 ===== def archive_logcat(serial: Optional[str] = None, - output: str = "workspace/测试报告/logcat") -> Optional[str]: + output: str = None) -> Optional[str]: """归档 Android logcat""" + if output is None: + output = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/logcat" Path(output).mkdir(parents=True, exist_ok=True) file = Path(output) / f"logcat_{datetime.now():%Y%m%d_%H%M%S}.log" cmd = ["adb"] @@ -318,7 +322,7 @@ def main(): perf.add_argument("--platform", choices=["android", "ios"], required=True) perf.add_argument("--package", required=True) perf.add_argument("--duration", type=int, default=60) - perf.add_argument("--output", default="workspace/测试报告/mobile-perf") + perf.add_argument("--output", default=f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/mobile-perf") log = sub.add_parser("archive-logcat") log.add_argument("--serial", default=None) @@ -329,7 +333,7 @@ def main(): monkey.add_argument("--throttle", type=int, default=200) monkey.add_argument("--seed", type=int, default=None) monkey.add_argument("--serial", default=None) - monkey.add_argument("--output", default="workspace/测试报告/monkey") + monkey.add_argument("--output", default=f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/monkey") monkey.add_argument("--timeout", type=int, default=3600) args = parser.parse_args() diff --git a/utils/quality/flaky_detector.py b/utils/quality/flaky_detector.py index 794a32d..97bce66 100644 --- a/utils/quality/flaky_detector.py +++ b/utils/quality/flaky_detector.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT """ Flaky 测试检测器 -依赖:pytest 启用 --junitxml 输出到 workspace/测试报告/history/ +依赖:pytest 启用 --junitxml 输出到 workspace/测试报告/{PROJECT_NAME}/history/ 被引用方:regression-test skill """ import json @@ -10,6 +10,10 @@ from pathlib import Path from typing import Dict, List +import sys +sys.path.insert(0, str(Path(__file__).parent.parent)) +from paths import get_output_dir, current_run_id + logger = logging.getLogger(__name__) @@ -18,11 +22,11 @@ class FlakyTestDetector: def __init__( self, - history_dir: str = "workspace/测试报告/history", + history_dir: str = None, history_limit: int = 5, quarantine_threshold: float = 0.3, ): - self.history_dir = Path(history_dir) + self.history_dir = Path(history_dir) if history_dir else get_output_dir("history") self.history_limit = history_limit self.quarantine_threshold = quarantine_threshold @@ -113,8 +117,10 @@ def detect_trends(self) -> List[Dict]: }) return sorted(trends, key=lambda x: x["confidence"], reverse=True) - def generate_quarantine(self, flaky_list: List[Dict], output_path: str = "workspace/测试报告/quarantine.txt") -> Path: + def generate_quarantine(self, flaky_list: List[Dict], output_path: str = None) -> Path: """生成隔离清单 — 每行一个 test_id,供 pytest --deselect 或 CI skip。""" + if output_path is None: + output_path = str(get_output_dir("quarantine", current_run_id()) / "quarantine.txt") out = Path(output_path) out.parent.mkdir(parents=True, exist_ok=True) lines = [f"# Flaky quarantine — {len(flaky_list)} tests — {__import__('datetime').datetime.now():%Y-%m-%d %H:%M}"] @@ -125,8 +131,10 @@ def generate_quarantine(self, flaky_list: List[Dict], output_path: str = "worksp logger.info(f"quarantine list written: {out} ({len(flaky_list)} tests)") return out - def generate_pytest_markers(self, flaky_list: List[Dict], output_path: str = "workspace/测试报告/flaky_markers.ini") -> Path: + def generate_pytest_markers(self, flaky_list: List[Dict], output_path: str = None) -> Path: """生成 pytest marker 配置 — 标记 flaky 用例为 @pytest.mark.flaky。""" + if output_path is None: + output_path = str(get_output_dir("quarantine", current_run_id()) / "flaky_markers.ini") out = Path(output_path) out.parent.mkdir(parents=True, exist_ok=True) lines = ["[pytest]", "markers ="] @@ -147,11 +155,11 @@ def generate_pytest_markers(self, flaky_list: List[Dict], output_path: str = "wo return out -def archive_junit(src: str, dest_dir: str = "workspace/测试报告/history"): +def archive_junit(src: str, dest_dir: str = None): """把本次 junit-xml 归档到 history 目录(按时间命名)""" from datetime import datetime src_p = Path(src) - dest_p = Path(dest_dir) + dest_p = Path(dest_dir) if dest_dir else get_output_dir("history") dest_p.mkdir(parents=True, exist_ok=True) name = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_{src_p.name}" target = dest_p / name @@ -164,7 +172,7 @@ def archive_junit(src: str, dest_dir: str = "workspace/测试报告/history"): import argparse logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser(description="Flaky 检测 + 趋势分析 + 隔离") - parser.add_argument("--history", default="workspace/测试报告/history") + parser.add_argument("--history", default=None) parser.add_argument("--limit", type=int, default=5) parser.add_argument("--archive", help="本次 junit-xml 路径(归档后再检测)") parser.add_argument("--trends", action="store_true", help="输出趋势分析") diff --git a/utils/reporting/evidence_chain.py b/utils/reporting/evidence_chain.py index c714072..ca8258b 100644 --- a/utils/reporting/evidence_chain.py +++ b/utils/reporting/evidence_chain.py @@ -21,6 +21,10 @@ from pathlib import Path from typing import Any +import sys +sys.path.insert(0, str(Path(__file__).parent.parent)) +from paths import get_output_dir, current_run_id + logger = logging.getLogger(__name__) # ── Compliance standards reference ── @@ -174,7 +178,7 @@ def collect_tracing_validation(trace_results: list[dict[str, Any]]) -> dict[str, def collect_baselines(baseline_path: Path | None = None) -> dict[str, Any]: """Collect performance baseline data.""" if baseline_path is None: - baseline_path = Path("workspace/测试报告/baselines/perf_baseline.json") + baseline_path = get_output_dir("baselines") / "perf_baseline.json" if not baseline_path.exists(): return {"available": False, "path": str(baseline_path)} try: @@ -187,7 +191,7 @@ def collect_baselines(baseline_path: Path | None = None) -> dict[str, Any]: def collect_test_history(history_dir: Path | None = None) -> list[dict[str, Any]]: """Collect recent test execution history metadata.""" if history_dir is None: - history_dir = Path("workspace/测试报告/history/") + history_dir = get_output_dir("history") items: list[dict[str, Any]] = [] if not history_dir.exists(): return items @@ -244,7 +248,7 @@ def build_evidence_chain( ) # 1. Decision logs - dec_dir = decisions_dir or Path("workspace/测试报告/decisions/") + dec_dir = decisions_dir or get_output_dir("decisions") decisions = collect_decisions(dec_dir) if decisions: chain.add(EvidenceItem( @@ -363,7 +367,7 @@ def export_package(package: EvidencePackage, """Export evidence package as JSON file.""" if output_path is None: output_path = Path( - f"workspace/测试报告/evidence/{package.package_id}.json") + str(get_output_dir("evidence", current_run_id()) / f"{package.package_id}.json")) output_path.parent.mkdir(parents=True, exist_ok=True) serialized: dict[str, Any] = { @@ -407,7 +411,7 @@ def export_chain_of_custody_report( """Export human-readable chain of custody report as Markdown.""" if output_path is None: output_path = Path( - f"workspace/测试报告/evidence/{package.package_id}_custody.md") + str(get_output_dir("evidence", current_run_id()) / f"{package.package_id}_custody.md")) output_path.parent.mkdir(parents=True, exist_ok=True) lines = [ @@ -477,7 +481,11 @@ def ci_summary(package: EvidencePackage) -> dict[str, Any]: def quick_package(workspace_dir: Path | None = None) -> EvidencePackage: """Build evidence package from default workspace paths.""" if workspace_dir is None: - workspace_dir = Path("workspace") + return build_evidence_chain( + decisions_dir=get_output_dir("decisions"), + baseline_path=get_output_dir("baselines") / "perf_baseline.json", + history_dir=get_output_dir("history"), + ) return build_evidence_chain( decisions_dir=workspace_dir / "测试报告/decisions/", baseline_path=workspace_dir / "测试报告/baselines/perf_baseline.json", diff --git a/utils/reporting/generate_report.py b/utils/reporting/generate_report.py index 958c10c..daf5387 100644 --- a/utils/reporting/generate_report.py +++ b/utils/reporting/generate_report.py @@ -13,6 +13,9 @@ import requests +sys.path.insert(0, str(Path(__file__).parent.parent)) +from paths import get_output_dir, current_run_id + logger = logging.getLogger(__name__) @@ -429,7 +432,7 @@ def main(): with open(args.data, encoding="utf-8") as f: data = json.load(f) - output = args.output or f"workspace/测试报告/测试报告_{datetime.now().strftime('%Y%m%d')}.docx" + output = args.output or str(get_output_dir("reports", current_run_id()) / f"测试报告_{datetime.now().strftime('%Y%m%d')}.docx") generate_test_report(data, output) if args.notify: diff --git a/utils/reporting/traceability_matrix.py b/utils/reporting/traceability_matrix.py index 610394a..275f6f8 100644 --- a/utils/reporting/traceability_matrix.py +++ b/utils/reporting/traceability_matrix.py @@ -31,7 +31,7 @@ class TraceabilityMatrix: matrix = TraceabilityMatrix() matrix.load_prd("workspace/需求分析/prd.md") matrix.load_testcases("workspace/测试用例/") - matrix.load_bugs("workspace/测试报告/bug_drafts.json") + matrix.load_bugs("workspace/测试报告/{项目名}/bug_drafts.json") report = matrix.build() """ diff --git a/utils/security/absentee_scenario_injector.py b/utils/security/absentee_scenario_injector.py index 9dd92cf..b3d13a7 100644 --- a/utils/security/absentee_scenario_injector.py +++ b/utils/security/absentee_scenario_injector.py @@ -17,6 +17,7 @@ import json import logging +import os from dataclasses import dataclass, field from datetime import datetime from pathlib import Path @@ -437,9 +438,11 @@ def coverage_report(injected_scenarios: list[dict] | None = None) -> dict: def export_injection_plan( scenarios: list[dict], - output_dir: str = "workspace/测试报告/absentee-scenarios", + output_dir: str = None, ) -> str: """Export the absentee scenario injection plan as JSON.""" + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/absentee-scenarios" Path(output_dir).mkdir(parents=True, exist_ok=True) ts = datetime.now().strftime("%Y%m%d_%H%M%S") path = Path(output_dir) / f"absentee_plan_{ts}.json" diff --git a/utils/security/ai_validator.py b/utils/security/ai_validator.py index 30e3bc3..a66f934 100644 --- a/utils/security/ai_validator.py +++ b/utils/security/ai_validator.py @@ -124,7 +124,9 @@ def fairness_metrics(dataset: str, sensitive_attr: str, endpoint: str) -> Dict: def run_bias_audit(dataset: str, sensitive_attrs: list[str], endpoint: str, - output_dir: str = "workspace/测试报告/ai-fairness") -> Dict: + output_dir: str = None) -> Dict: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/ai-fairness" """Run full fairness audit via fairness_auditor and return summary dict.""" import pandas as pd @@ -164,7 +166,7 @@ def run_bias_audit(dataset: str, sensitive_attrs: list[str], endpoint: str, def run_silent_failure_audit( - output_dir: str = "workspace/测试报告/ai-silent-failure", + output_dir: str = None, trace_durations_ms: Optional[List[float]] = None, web_vitals_data: Optional[Dict] = None, prometheus_counter_data: Optional[Dict] = None, @@ -172,6 +174,8 @@ def run_silent_failure_audit( custom_configs: Optional[List] = None, ) -> Dict: """Run silent failure detection across all data sources and return summary dict.""" + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/ai-silent-failure" from datetime import datetime, timezone from utils.security.silent_failure_detector import ( collect_from_tracing, @@ -267,9 +271,11 @@ def run_silent_failure_audit( def run_evidence_chain_audit( decisions_dir: Optional[str] = None, - output_dir: str = "workspace/测试报告/evidence", + output_dir: str = None, ) -> Dict: """Build evidence chain package from workspace and export JSON + custody report.""" + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/evidence" from utils.reporting.evidence_chain import ( build_evidence_chain, export_package, @@ -344,8 +350,10 @@ def llm_eval(endpoint: str, prompt: str, expected_format: Optional[str] = None, # ===== 报告 ===== -def save_eval_report(metrics: Dict, output_dir: str = "workspace/测试报告/ai-eval", +def save_eval_report(metrics: Dict, output_dir: str = None, prefix: str = "eval") -> str: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/ai-eval" from datetime import datetime Path(output_dir).mkdir(parents=True, exist_ok=True) path = Path(output_dir) / f"{prefix}_{datetime.now():%Y%m%d_%H%M%S}.json" diff --git a/utils/security/security_scanner.py b/utils/security/security_scanner.py index b4e59a2..e0edaa7 100644 --- a/utils/security/security_scanner.py +++ b/utils/security/security_scanner.py @@ -20,7 +20,7 @@ def run_bandit(target_path: str, output: Optional[str] = None) -> Dict: """Bandit Python SAST。需 pip install bandit""" - output = output or "workspace/测试报告/security/bandit_report.json" + output = output or f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/security/bandit_report.json" Path(output).parent.mkdir(parents=True, exist_ok=True) cmd = ["bandit", "-r", target_path, "-f", "json", "-o", output, "-q"] proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace") diff --git a/utils/security/silent_failure_detector.py b/utils/security/silent_failure_detector.py index f0c6fd6..68accab 100644 --- a/utils/security/silent_failure_detector.py +++ b/utils/security/silent_failure_detector.py @@ -19,6 +19,7 @@ import json import logging +import os from collections import deque from dataclasses import dataclass, field from datetime import datetime, timezone @@ -386,7 +387,9 @@ def __len__(self) -> int: # ═══════════════════════════════════════════════════════════════ def export_report(report: SilentFailureReport, - output_dir: str = "workspace/测试报告/silent-failures") -> str: + output_dir: str = None) -> str: + if output_dir is None: + output_dir = f"workspace/测试报告/{os.getenv('PROJECT_NAME', 'default')}/silent-failures" """Export SilentFailureReport as JSON.""" Path(output_dir).mkdir(parents=True, exist_ok=True) ts = datetime.now().strftime("%Y%m%d_%H%M%S") diff --git a/utils/testing/soak_runner.py b/utils/testing/soak_runner.py index 79063e5..09ea40b 100644 --- a/utils/testing/soak_runner.py +++ b/utils/testing/soak_runner.py @@ -11,6 +11,10 @@ from pathlib import Path from typing import Callable, Dict, List, Optional +import sys +sys.path.insert(0, str(Path(__file__).parent.parent)) +from paths import get_output_dir, current_run_id + logger = logging.getLogger(__name__) @@ -18,7 +22,7 @@ def soak_test(scenario: Callable[[], None], duration_hours: float = 24, interval_sec: int = 10, metric_proc_pid: Optional[int] = None, - output_dir: str = "workspace/测试报告/soak") -> Dict: + output_dir: str = None) -> Dict: """ 长时稳定性测试。 scenario: 单次业务调用函数(无返回,无参数) @@ -26,6 +30,8 @@ def soak_test(scenario: Callable[[], None], interval_sec: 两次调用间隔 metric_proc_pid: 监控指定进程 PID(采集 CPU/内存) """ + if output_dir is None: + output_dir = str(get_output_dir("soak", current_run_id())) import psutil Path(output_dir).mkdir(parents=True, exist_ok=True) From 5ec8ef19b460b980f800e697813ec9c60216f268 Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 01:26:29 +0800 Subject: [PATCH 4/8] =?UTF-8?q?docs:=20sync=20utils=20count=2078=E2=86=927?= =?UTF-8?q?9=20across=20all=20docs,=20config,=20and=20CI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 15 files updated — AGENTS.md, CLAUDE.md, README (en+zh), copilot-instructions, 6 charter/getting-started docs, web-demo README, .pre-commit-config.yaml error message. --- .github/copilot-instructions.md | 2 +- .pre-commit-config.yaml | 2 +- AGENTS.md | 4 ++-- CLAUDE.md | 4 ++-- README.md | 2 +- README.zh-CN.md | 2 +- docs/charter/01-vision-dimensions.md | 2 +- docs/charter/05-install-deploy.md | 2 +- docs/charter/07-runtime-license.md | 6 +++--- .../\344\275\277\347\224\250\346\211\213\345\206\214.md" | 2 +- .../\351\203\250\347\275\262\350\257\264\346\230\216.md" | 2 +- examples/web-demo/README.md | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index bc8ac2c..5cf5c0e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -6,7 +6,7 @@ This is a Test-Agent project with a defined Skill → Agent → Utils execution 1. **Read Skill docs first** — Check `skills/.md` to understand the workflow before generating any test code or calling agents. 2. **Follow the framework** — Do not skip the Skill workflow layer. Agent definitions are in `agents/`, utils in `utils/`. -3. **Use existing utils** — The project has 78 utility modules in `utils/`. Prefer using them over generating new code. +3. **Use existing utils** — The project has 79 utility modules in `utils/`. Prefer using them over generating new code. 4. **Match the project structure** — Test outputs go to `workspace/`, config in `config/`, source code in `src/`. 5. **Config first** — Check `.env.example` for required environment variables before generating code that depends on them. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c79762..441ed65 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -67,7 +67,7 @@ repos: # 文件统计校验(防误删 agent/skill/utils) - id: file-count-check name: Agents/Skills/Utils 数量校验 - entry: bash -c 'A=$(ls agents/[0-9]*.md 2>/dev/null | wc -l); S=$(ls skills/*.md 2>/dev/null | grep -v README | wc -l); U=$(find utils -name "*.py" ! -name "__init__.py" 2>/dev/null | wc -l); [ "$A" = "16" ] || { echo "❌ Agents count mismatch (expected 16, got $A)"; exit 1; }; [ "$S" -eq "32" ] || { echo "❌ Skills count mismatch (expected 32, got $S)"; exit 1; }; [ "$U" -eq "79" ] || { echo "❌ Utils count mismatch (expected 78, got $U)"; exit 1; }; echo "✅ File counts correct"' + entry: bash -c 'A=$(ls agents/[0-9]*.md 2>/dev/null | wc -l); S=$(ls skills/*.md 2>/dev/null | grep -v README | wc -l); U=$(find utils -name "*.py" ! -name "__init__.py" 2>/dev/null | wc -l); [ "$A" = "16" ] || { echo "❌ Agents count mismatch (expected 16, got $A)"; exit 1; }; [ "$S" -eq "32" ] || { echo "❌ Skills count mismatch (expected 32, got $S)"; exit 1; }; [ "$U" -eq "79" ] || { echo "❌ Utils count mismatch (expected 79, got $U)"; exit 1; }; echo "✅ File counts correct"' language: system pass_filenames: false always_run: true diff --git a/AGENTS.md b/AGENTS.md index e1364de..b8cfaf0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -52,7 +52,7 @@ Standalone CLI (tagent) AI Agent Mode runtime/orchestrator Agent defs (agents/*.md) │ │ ▼ ▼ - utils/*.py (78 modules) utils/*.py (78 modules) + utils/*.py (79 modules) utils/*.py (79 modules) ``` Both paths converge at the utils execution layer. @@ -63,7 +63,7 @@ Both paths converge at the utils execution layer. |------|-------| | Agent definitions | `agents/` (16 agents) | | Skill workflow docs | `skills/` (35 skills) | -| Python utils | `utils/` (78 modules) | +| Python utils | `utils/` (79 modules) | | Runtime (CLI + orchestrator + MCP) | `runtime/` | | Config templates | `config/` (incl. `.env.example`) | | Test outputs | `workspace/` | diff --git a/CLAUDE.md b/CLAUDE.md index f06cb14..fedd218 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,7 +59,7 @@ Standalone CLI (tagent) AI Agent Mode (Claude Code) runtime/orchestrator Agent defs (agents/*.md) │ │ ▼ ▼ - utils/*.py (78 modules) utils/*.py (78 modules) + utils/*.py (79 modules) utils/*.py (79 modules) ``` Both paths converge at the utils execution layer. @@ -70,7 +70,7 @@ Both paths converge at the utils execution layer. |------|-------| | Agent definitions | `agents/` (16 agents) | | Skill workflow docs | `skills/` (35 skills) | -| Python utils | `utils/` (78 modules) | +| Python utils | `utils/` (79 modules) | | Runtime (CLI + orchestrator + MCP) | `runtime/` | | Config templates | `config/` (incl. `.env.example`) | | Test outputs | `workspace/` | diff --git a/README.md b/README.md index c026b32..b679b7a 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ No Python / Node / Docker required. Download and run. Test-Agent/ ├── agents/ ← 16 expert agents ├── skills/ ← 32 business skills + 3 meta-skills -├── utils/ ← 78 production utils (pytest · Playwright · JMeter · Appium · …) +├── utils/ ← 79 production utils (pytest · Playwright · JMeter · Appium · …) ├── config/ ← conftest / pytest.ini / .mcp.json ├── runtime/ ← V1.x runtime (router · orchestrator · MCP · …) ├── ci/ ← GitHub Actions + Jenkins diff --git a/README.zh-CN.md b/README.zh-CN.md index ed5c96f..a45b6d7 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -85,7 +85,7 @@ python install.py ~/test-agent-project # macOS / Linux 示例,可改为 Test-Agent/ ├── agents/ ← 16 个专家 Agent ├── skills/ ← 32 个业务 Skill + 3 元 Skill -├── utils/ ← 78 个生产工具(pytest · Playwright · JMeter · Appium · …) +├── utils/ ← 79 个生产工具(pytest · Playwright · JMeter · Appium · …) ├── config/ ← conftest / pytest.ini / .mcp.json ├── runtime/ ← V1.x 运行时(router · orchestrator · MCP · …) ├── ci/ ← GitHub Actions + Jenkins diff --git a/docs/charter/01-vision-dimensions.md b/docs/charter/01-vision-dimensions.md index 4102d21..defae57 100644 --- a/docs/charter/01-vision-dimensions.md +++ b/docs/charter/01-vision-dimensions.md @@ -25,7 +25,7 @@ | `skills/` | 32 个 Skill 文件(业务 skill) + 3 个元 Skill 子目录 + README 索引 | 可复用测试技能 | 开发人员 | | `config/` | conftest.py / pytest.ini / .env.example / .mcp.json / requirements.txt | 配置文件集合 | 开发人员 | | `config/` | mcp-server-impl.md | MCP server 自实现教程(zentao/wechat/feishu/dingtalk 骨架) | 高级开发 | -| `utils/` | utils(78 个 .py + init)+ README 索引(多分类) | 完整可运行 Python 工具集 | 开发人员 | +| `utils/` | utils(79 个 .py + init)+ README 索引(多分类) | 完整可运行 Python 工具集 | 开发人员 | | `ci/` | github-actions-test.yml / jenkins-pipeline.groovy / 集成说明.md | CI/CD 流水线(含 JMeter 性能阶段) | DevOps | --- diff --git a/docs/charter/05-install-deploy.md b/docs/charter/05-install-deploy.md index 0ec5d34..85946cf 100644 --- a/docs/charter/05-install-deploy.md +++ b/docs/charter/05-install-deploy.md @@ -248,7 +248,7 @@ your-test-project/ ├── .claude/{agents,skills}/ ← 16 agent + 32 skill(业务) + 3 元 skill ├── .github/workflows/test.yml ├── Jenkinsfile -├── utils/ ← 78 个 .py + __init__ +├── utils/ ← 79 个 .py + __init__ ├── src/ ← 被测系统源码(cov 指向) ├── workspace/ │ ├── 测试计划/ 需求分析/ 测试用例/ 测试数据/ diff --git a/docs/charter/07-runtime-license.md b/docs/charter/07-runtime-license.md index aa131c2..17244b5 100644 --- a/docs/charter/07-runtime-license.md +++ b/docs/charter/07-runtime-license.md @@ -6,7 +6,7 @@ ## 🧠 V1.36.0 运行时层(`runtime/`) -> 已有 16 专家 / 32 Skill / 78 utils**不动**(宪章铁律),`runtime/` 作可执行调度层 + 真 LLM-driven agent/skill runner。 +> 已有 16 专家 / 32 Skill / 79 utils**不动**(宪章铁律),`runtime/` 作可执行调度层 + 真 LLM-driven agent/skill runner。 > 让"文档+脚本工具箱"升级为"可被 API/CLI/CI 直接调用的运行时"。 ### 模块拓扑 @@ -104,13 +104,13 @@ uvicorn runtime.api.main:app --port 8800 - 5 类典型输入(web/api/mobile/desktop/ai-model)stub 路由 = 5/5(100%) - M1 门槛:多模型真测 ≥85%;不达 → 双模型投票 -### 与 16 专家 / 32 Skill / 78 utils 的关系 +### 与 16 专家 / 32 Skill / 79 utils 的关系 | 项 | 关系 | |----|------| | 16 专家 `.md` | **不动**。`registry` 扫 frontmatter,`router` 喂 LLM 选用 | | 32 Skill `.md` | **不动**。同上 | -| 78 utils `.py` | **不动**。`orchestrator/adapters/scripts.py` subprocess 隔离调用 | +| 79 utils `.py` | **不动**。`orchestrator/adapters/scripts.py` subprocess 隔离调用 | | `utils/` 通知/Bug | 复用 `generate_report.py` / `zentao_bug_manager.py` | 任何专家/Skill/脚本**新增**或**修改**仍按宪章 §1 同步铁律走;`runtime/` 是新增 **调度** 层,不重复实现专家逻辑。 diff --git "a/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" "b/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" index 9306afa..bfab259 100644 --- "a/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" +++ "b/docs/getting-started/\344\275\277\347\224\250\346\211\213\345\206\214.md" @@ -13,7 +13,7 @@ Test-Agent/ ─部署→ your-test-project/ ├── agents/ ├── .claude/agents/ ├── skills/ ├── .claude/skills/ ├── config/ ├── conftest.py / pytest.ini / .env / .mcp.json -├── utils/ ├── utils/(78 个 .py) +├── utils/ ├── utils/(79 个 .py) └── ci/ ├── .github/workflows/test.yml + Jenkinsfile ├── src/ ← 你的被测系统源码 └── workspace/ ← 测试产出 diff --git "a/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" "b/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" index 4a0405d..0f9b181 100644 --- "a/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" +++ "b/docs/getting-started/\351\203\250\347\275\262\350\257\264\346\230\216.md" @@ -149,7 +149,7 @@ if (-not (Test-Path "$PROJECT_ROOT\.env")) { Copy-Item "$TEMPLATE_DIR\config\.env.example" "$PROJECT_ROOT\.env" -Force } -# 拷贝 utils(78 个 .py + __init__.py) +# 拷贝 utils(79 个 .py + __init__.py) $utils = @( "__init__.py", "api_retry_util.py", "data_factory.py", "data_masking.py", "excel_generator.py", "flaky_detector.py", diff --git a/examples/web-demo/README.md b/examples/web-demo/README.md index e279bd0..1c03d7e 100644 --- a/examples/web-demo/README.md +++ b/examples/web-demo/README.md @@ -71,7 +71,7 @@ examples/web-demo/ | 完整工作流 | 本 demo | |-----------|---------| -| 16 Agent + 32 Skill + 78 utils | 仅 pytest + playwright | +| 16 Agent + 32 Skill + 79 utils | 仅 pytest + playwright | | `.env` 配置 8 必填 | 不需 `.env` | | Allure / JMeter / BugTracker 集成 | 不集成 | | 冒烟 + 回归 + 性能门禁 | 仅 1 冒烟用例 | From e93cbbca4edf1edceacf75506ff7c012c29e9808 Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 01:32:49 +0800 Subject: [PATCH 5/8] fix: exclude untracked workspace dirs, .claude deploy artifacts from git MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added to .gitignore: - .claude/agents/, .claude/skills/ — deployment copies, not source - workspace/测试用例/, 测试计划/, 需求分析/, 执行日志/, audit/ — outputs - workspace/测试报告/*/ → workspace/测试报告/** — catch root-level files too --- .gitignore | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d7b8af2..d37fada 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,12 @@ htmlcov/ # workspace 测试产出(敏感 + 体积大) workspace/测试数据/ -workspace/测试报告/*/ +workspace/测试报告/** +workspace/测试用例/ +workspace/测试计划/ +workspace/需求分析/ +workspace/执行日志/ +workspace/audit/ workspace/_outputs/ workspace/feedback/ workspace/自动化脚本/ @@ -40,6 +45,8 @@ workspace/自动化脚本/ Thumbs.db # ===== Claude Code ===== +.claude/agents/ +.claude/skills/ .claude/cache/ .claude/sessions/ From 4c77ccb23e3aa18256470298c7eb678938021daa Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 01:40:02 +0800 Subject: [PATCH 6/8] fix: replace broken /** gitignore with explicit output directory patterns /** pattern cannot be overridden by ! negation in git. Replaced with explicit directory names for root files, legacy dirs, run_id dirs, and project-level output subdirectories. Baselines naturally excluded from ignore rules (they should be tracked). --- .gitignore | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index d37fada..6cf7d2b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ htmlcov/ # workspace 测试产出(敏感 + 体积大) workspace/测试数据/ -workspace/测试报告/** workspace/测试用例/ workspace/测试计划/ workspace/需求分析/ @@ -27,8 +26,47 @@ workspace/_outputs/ workspace/feedback/ workspace/自动化脚本/ -# 但保留各项目 baselines/(性能基线需提交) -!workspace/测试报告/*/baselines/ +# 测试报告 — 排除产物,保留 baselines/ +# 根级直接文件(临时报告、自检产物等) +workspace/测试报告/*.md +workspace/测试报告/*.docx +workspace/测试报告/*.json +# 旧式子目录(v1.42 前,无项目名层级) +workspace/测试报告/allure-results/ +workspace/测试报告/allure-report/ +workspace/测试报告/jmeter-results/ +workspace/测试报告/jmeter-report/ +workspace/测试报告/decisions/ +workspace/测试报告/evidence/ +workspace/测试报告/reports/ +workspace/测试报告/security/ +workspace/测试报告/history/ +workspace/测试报告/quarantine/ +workspace/测试报告/soak/ +workspace/测试报告/ai-*/ +workspace/测试报告/web-vitals/ +workspace/测试报告/silent-failures/ +workspace/测试报告/audit/ +workspace/测试报告/screenshots/ +# 按 run_id 隔离的产出目录(时间戳格式: YYYYMMDD_HHMMSS_xxxxxx) +workspace/测试报告/*/2*/ +# 项目级产出子目录({项目名}/ 下) +workspace/测试报告/*/screenshots/ +workspace/测试报告/*/allure-results/ +workspace/测试报告/*/allure-report/ +workspace/测试报告/*/jmeter-results/ +workspace/测试报告/*/jmeter-report/ +workspace/测试报告/*/decisions/ +workspace/测试报告/*/evidence/ +workspace/测试报告/*/reports/ +workspace/测试报告/*/security/ +workspace/测试报告/*/history/ +workspace/测试报告/*/quarantine/ +workspace/测试报告/*/soak/ +workspace/测试报告/*/ai-*/ +workspace/测试报告/*/web-vitals/ +workspace/测试报告/*/silent-failures/ +workspace/测试报告/*/audit/ # ===== 敏感配置 ===== .env From 49a99a0552a528fc05309d0a374b0795bc28f583 Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 01:44:29 +0800 Subject: [PATCH 7/8] fix: stop tracking IDE config, auto-generated audit, automotive test output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed from tracking (kept locally): - .vscode/ — IDE config with machine-specific paths - workspace/audit/V1.43-health-check.md — auto-generated health check - workspace/automotive/can_plan.json — test output data Added workspace/automotive/ to .gitignore. --- .gitignore | 1 + .vscode/extensions.json | 14 --- .vscode/launch.json | 53 --------- .vscode/settings.json | 39 ------- workspace/audit/V1.43-health-check.md | 156 -------------------------- workspace/automotive/can_plan.json | 23 ---- 6 files changed, 1 insertion(+), 285 deletions(-) delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json delete mode 100644 workspace/audit/V1.43-health-check.md delete mode 100644 workspace/automotive/can_plan.json diff --git a/.gitignore b/.gitignore index 6cf7d2b..55ec9d1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ htmlcov/ # workspace 测试产出(敏感 + 体积大) workspace/测试数据/ +workspace/automotive/ workspace/测试用例/ workspace/测试计划/ workspace/需求分析/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index c3ccfff..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "recommendations": [ - "charliermarsh.ruff", - "ms-python.python", - "ms-python.vscode-pylance", - "tamasfe.even-better-toml", - "redhat.vscode-yaml", - "ms-azuretools.vscode-docker", - "github.vscode-github-actions", - "yzhang.markdown-all-in-one", - "bierner.markdown-mermaid", - "davidanson.vscode-markdownlint" - ] -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 2b50151..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "tagent CLI: demo", - "type": "debugpy", - "request": "launch", - "module": "runtime.cli.main", - "cwd": "${workspaceFolder}", - "args": ["demo", "-y"], - "console": "integratedTerminal" - }, - { - "name": "tagent CLI: doctor", - "type": "debugpy", - "request": "launch", - "module": "runtime.cli.main", - "cwd": "${workspaceFolder}", - "args": ["doctor"], - "console": "integratedTerminal" - }, - { - "name": "tagent CLI: catalog", - "type": "debugpy", - "request": "launch", - "module": "runtime.cli.main", - "cwd": "${workspaceFolder}", - "args": ["catalog"], - "console": "integratedTerminal" - }, - { - "name": "tagent API server", - "type": "debugpy", - "request": "launch", - "module": "uvicorn", - "cwd": "${workspaceFolder}", - "args": ["runtime.api.main:app", "--host", "0.0.0.0", "--port", "8800", "--reload"], - "console": "integratedTerminal", - "env": { - "TAGENT_LOG_LEVEL": "DEBUG" - } - }, - { - "name": "pytest: current file", - "type": "debugpy", - "request": "launch", - "module": "pytest", - "cwd": "${workspaceFolder}/runtime", - "args": ["-v", "--tb=short", "${file}"], - "console": "integratedTerminal" - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e3b197b..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "python.defaultInterpreterPath": "${workspaceFolder}/runtime/.venv/Scripts/python.exe", - "python.testing.pytestEnabled": true, - "python.testing.pytestPath": "${workspaceFolder}/runtime/.venv/Scripts/pytest.exe", - "python.testing.cwd": "${workspaceFolder}/runtime", - "python.testing.pytestArgs": ["-v", "--tb=short", "--no-header"], - "python.linting.enabled": true, - "python.linting.ruffEnabled": true, - "python.formatting.provider": "ruff", - "python.analysis.extraPaths": ["${workspaceFolder}/runtime"], - "python.analysis.typeCheckingMode": "basic", - "[python]": { - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.organizeImports": "explicit" - }, - "editor.defaultFormatter": "charliermarsh.ruff" - }, - "[markdown]": { - "editor.wordWrap": "bounded", - "editor.wordWrapColumn": 100 - }, - "[yaml]": { - "editor.insertSpaces": true, - "editor.tabSize": 2 - }, - "files.exclude": { - "**/__pycache__": true, - "**/*.pyc": true, - "**/.pytest_cache": true, - "**/.mypy_cache": true, - "**/*.egg-info": true - }, - "files.watcherExclude": { - "**/workspace/**": true, - "**/.venv/**": true, - "**/node_modules/**": true - } -} diff --git a/workspace/audit/V1.43-health-check.md b/workspace/audit/V1.43-health-check.md deleted file mode 100644 index d5924fe..0000000 --- a/workspace/audit/V1.43-health-check.md +++ /dev/null @@ -1,156 +0,0 @@ -# Test-Agent V1.43 体检报告 - -生成时间: 2026-05-19T00:00:00Z -执行人: claude general-purpose subagent (Task #3) -基线版本: V1.42.0 → V1.43.0 切版前 - ---- - -## 1. 测试通过率 - -**状态: ❌ BLOCKED (PowerShell 权限被拒)** - -本次会话 PowerShell 工具调用被沙箱拒绝("Permission to use PowerShell has been denied"),无法执行 `python -m pytest` 或 `--collect-only`。 - -替代证据 (静态收集): -- `runtime/tests/` 下共发现 **21 个** test_*.py 文件 (Glob `**/tests/test_*.py`): - - test_smoke_e2e.py, test_agent_runners.py, test_skill_runners.py, test_api_auth.py, test_build_artifact.py, test_catalog.py, test_router.py, test_cli_config.py, test_impl_status_filter.py, test_utils_silent_failure.py, test_utils_fairness.py, test_cli_commands.py, test_registry.py, test_portability.py, test_router_real.py, test_utils_evidence_chain.py, test_utils_bug_tracker.py, test_utils_absentee.py, test_utils_quality_gate.py, test_utils_i18n_taboo.py, test_utils_taboo_matrix.py -- 另有 1 个 `examples/web-demo/tests/test_smoke.py`(不在 runtime testpaths 内) -- `pyproject.toml [tool.pytest.ini_options] testpaths = ["tests"]`,正常路径下应 collect 这 21 个文件 -- pytest 配置: asyncio_mode=auto, addopts="--cov-branch", markers: flaky/portability/slow/smoke - -⚠️ **建议**: 下一次切版前由 user 在本地执行 `cd D:\项目文件\Test-Agent\runtime && python -m pytest tests/ --tb=line -q --no-header` 补齐本节实测数据。本报告该节为 BLOCKED 而非全绿。 - ---- - -## 2. 实装状态对账 ✅ - -### Expert (agents/*.md frontmatter EXPERT_IMPL_STATUS) - -| 状态 | 数量 | 列表 | -|------|------|------| -| production | **11** | 01-测试主管, 02-需求分析, 04-环境管理, 06-自动化脚本, 07-测试执行, 08-Bug管理, 10-移动测试, 12-视觉游戏测试, 13-系统集成测试, 15-渗透测试, 16-车载测试 | -| script | **5** | 03-用例设计, 05-数据准备, 09-报告生成, 11-桌面测试, 14-AI模型测试 | -| rollout / vision | **0** | — | -| **合计** | **16** | | - -ROADMAP 声称: 16 expert active(11 production + 5 script)→ **完全一致 ✅** - -### Skill (skills/*.md frontmatter SKILL_IMPL_STATUS) - -| 状态 | 数量 | 备注 | -|------|------|------| -| production | **23** | 业务 skill(不含 karpathy-guidelines 元 skill) | -| script | **7** | ai-test, data-preparation, desktop-test, jmeter-script-gen, python-script-gen, security-review, zentao-bug-submission | -| vision | **2** | agent-introspection-debugging, build-your-own-x-explorer | -| rollout | **0** | — | -| **业务合计** | **32** | (23 + 7 + 2) | -| 元 skill | 3 | nuwa-skill, darwin-skill, karpathy-guidelines (独立工具属性,不计入 32) | - -ROADMAP 声称: 30/32 active(23 production + 7 script)+ 2 vision + 3 meta → **完全一致 ✅** - -**不一致条目**: 无。frontmatter 与 ROADMAP 数字完全对齐。 - ---- - -## 3. TODO/FIXME 薄弱点 - -### 总数概览 (Grep `TODO|FIXME|HACK|XXX`,已排除 .git/.pytest_cache/archive/workspace) - -| 区域 | 总命中数 | 涉及文件数 | -|------|----------|-----------| -| runtime/ | 118 | 39 | -| utils/ | 7 | 3 | -| agents/ | 4 | 1 | -| skills/ | 1 | 1 | -| **合计** | **130** | **44** | - -### Top 10 文件 (按命中数降序) - -| 文件 | 命中数 | -|------|--------| -| runtime/orchestrator/agents/base.py | 13 | -| runtime/orchestrator/agents/test_lead.py | 12 | -| runtime/tests/test_agent_runners.py | 9 | -| runtime/orchestrator/adapters/experts.py | 7 | -| runtime/orchestrator/agents/bug_manager.py | 7 | -| runtime/tests/test_skill_runners.py | 7 | -| runtime/orchestrator/agents/INDEX.md | 4 | -| runtime/tests/test_impl_status_filter.py | 4 | -| agents/01-测试主管.md | 4 | -| runtime/registry/registry.py | 3 | - -备注:runtime/ 大部分 TODO 集中在 base.py / test_lead.py / INDEX.md / 测试文件,推测多为「下一步深化」标记(V2.x 期待项),而非「漏实装」。 - -### 5 条样本(具体位置 + 内容) - -1. **utils/platforms/mobile_driver.py:171** — `TODO(V2.x): 解析 timestamp 列,计算 (frame_count - 1) / (timestamp[-1] - timestamp[0]) 真 FPS` (FPS 真值计算延期到 V2) -2. **utils/testing/bdd_runner.py:80** — `pass # TODO: 实现登录` (BDD 登录 step 未实装,bdd_runner_v2 已重写但 v1 仍在仓库) -3. **utils/testing/bdd_runner.py:85** — `pass # TODO` (BDD step 空实现) -4. **utils/testing/bdd_runner.py:90** — `pass # TODO assert` (BDD assertion step 空实现) -5. **agents/01-测试主管.md:542-545** — `总计:XXX / 通过:XXX(XX%) / 失败:XXX(XX%) / 跳过:XXX` (模板占位符,不是漏实装,但 grep 会击中) - -**重点关注**: `utils/testing/bdd_runner.py` 是真漏实装的 3 处 `pass # TODO`,但 `bdd_runner_v2.py` 已是更新版本("Step implementation coverage scanner"),建议确认是否可以下线 v1 文件。 - ---- - -## 4. 文档一致性 ⚠️ - -### 4.1 版本号 4 处快照 - -| 位置 | 版本字符串 | 状态 | -|------|-----------|------| -| `VERSION` | `1.42.0` | ✅ 基线 | -| `runtime/pyproject.toml` L3 | `version = "1.42.0"` | ✅ 一致 | -| `runtime/__init__.py` L7 | `__version__ = "1.40.0"` | ❌ **滞后 2 版本** | -| `README.md` | 无直接 X.Y.Z 字面量(用 badge link 指向 VERSION 文件) | ⚠️ N/A(间接) | - -**不一致项 #1**: `runtime/__init__.py` 仍写 1.40.0,V1.41/V1.42 切版未同步。**这是切版基线遗漏,V1.43 切版必须修。** - -**不一致项 #2**: `runtime/__init__.py` L1 docstring 说 `(V1.40.0)`,L4 说 `32 skills + 76 utils`,而 README.md L46 说 `78 production utils` → 数字也滞后。 - -### 4.2 目录数声明 vs 实际 - -| 文件 | 声明 | 实际 (.md 计数) | 状态 | -|------|------|----------------|------| -| agents/README.md L3 | 16 Agent (11 production + 5 script + 0 rollout) | 16 业务 .md + 1 README = 17 .md;业务 16 ✅ | ✅ | -| skills/README.md L3 | 32 业务 Skill + 3 元 Skill | 业务顶层 32 .md(不含 README/子目录/references) ✅;3 元 SKILL.md ✅ | ✅ | -| skills/README.md L5 类目和 | 8+5+7+5+6+1 = 32 | 32 ✅ | ✅ | - -### 4.3 切版基线建议(V1.43) - -切版时必须同步以下文件: -1. `VERSION` → `1.43.0` -2. `runtime/__init__.py` L7 `__version__` + L1 docstring 版本号 + utils 数字 -3. `runtime/pyproject.toml` L3 `version` -4. `ROADMAP.md` 进度表追加 V1.43 行 -5. README.md badges 已是动态(指向 VERSION + actions),无需手改 - ---- - -## 5. 综合诊断与下一步建议 - -### 健康度判断 (≤150 字) - -Test-Agent V1.42.0 处于**健壮但需收紧**状态。实装侧 expert 16/16 + skill 30/32 active 与 ROADMAP 完全对齐,frontmatter 单源真实可信,防 mock 闭环已落地。主要风险点:(1) `runtime/__init__.py` 版本号滞后到 1.40.0(2 版本未同步);(2) `utils/testing/bdd_runner.py` 有 3 处 `pass # TODO` 真漏实装但 v2 已重写并存;(3) 测试通过率本次因沙箱权限无法实测,需 user 本地补跑。综合健康度: **B+**(产品骨架成熟,需切版纪律与遗留清理)。 - -### 下一步行动 3 个候选 - -**候选 A: V1.43 切版前修文档版本不同步 (推荐 · 1h)** -- 修 `runtime/__init__.py` L7 `__version__` 1.40.0 → 1.43.0 -- 修 L1 docstring 版本号 + utils 计数(76 → 78,与 README 对齐) -- 修 `VERSION` → 1.43.0 + `runtime/pyproject.toml` version -- 在 `ROADMAP.md` 进度表追加 V1.43 行(本次体检 + 切版同步) -- 影响面: 4 个文件 ≤ 10 行改动,零业务风险 - -**候选 B: 清理 bdd_runner v1 历史包袱 (中等 · 2h)** -- `utils/testing/bdd_runner.py` 是 v1 残留(3 处 `pass # TODO`),`bdd_runner_v2.py` 已提供 step coverage scanner -- 评估: 是否还有 import 引用 v1?若无,move bdd_runner.py → archive/,保留 v2 为单源 -- 影响面: utils 子目录 1 文件下线,需 grep 确认引用 - -**候选 C: 6 expert 深化路线启动 (V2.x · 中长期)** -- 对应 ROADMAP V2.x "6 expert 深化" 章节: env/mobile/visual/system/pentest/automotive 6 个 LLM-driven minimum viable expert 接入真实工具调用(sqlmap/Burp/CAN-bus 库等) -- 建议先从 `env-manager`(技术债最少 · 工具栈最稳)开试,确立深化范式 -- 影响面: 6 个 runtime/orchestrator/agents/*.py 各 +200~400 行,需配套 utils 真调用 wiring - -**首推**: 候选 A(切版基线必修)。其次 B(2h 清理一笔旧账)。C 留作 V2.0 启动节点。 diff --git a/workspace/automotive/can_plan.json b/workspace/automotive/can_plan.json deleted file mode 100644 index 3a018d2..0000000 --- a/workspace/automotive/can_plan.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "project_name": "selftest", - "run_id": "016-000013", - "protocols": [ - "CAN", - "CAN-FD", - "SOME-IP" - ], - "checks": [ - "proto_conformance", - "dbc_parse", - "timing", - "fault_injection" - ], - "outputs": { - "can_dir": "workspace/automotive/can/" - }, - "risks": [ - "CAN 总线物理层干扰致误判" - ], - "confidence": "medium", - "_mode": "mock" -} From 244e676daba7bfb0ad7f19e8f6857e1542f50b36 Mon Sep 17 00:00:00 2001 From: xiaoxing0135 <706015750@qq.com> Date: Wed, 3 Jun 2026 01:51:36 +0800 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20update=20CI=20utils=20count=20check?= =?UTF-8?q?=2078=E2=86=9279?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ed2083..a6f3309 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -293,7 +293,7 @@ jobs: echo "Agents=$AGENTS Skills=$SKILLS Utils=$UTILS" [ "$AGENTS" = "16" ] || { echo "❌ Agents count mismatch (expected 16, got $AGENTS)"; exit 1; } [ "$SKILLS" -eq "32" ] || { echo "❌ Skills count mismatch (expected 32, got $SKILLS)"; exit 1; } - [ "$UTILS" -eq "78" ] || { echo "❌ Utils count mismatch (expected 78, got $UTILS)"; exit 1; } + [ "$UTILS" -eq "79" ] || { echo "❌ Utils count mismatch (expected 79, got $UTILS)"; exit 1; } echo "✅ File counts correct" - name: 验证 .gitignore 排除源 MD