feat(tester): add integration-first journey execution
This commit is contained in:
@@ -18,7 +18,15 @@ from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from journey import CLIENT_SUITES, client_suite, contract_errors, preflight as journey_preflight
|
||||
from journey import (
|
||||
CLIENT_SUITES,
|
||||
INTEGRATION_SUITES,
|
||||
TEST_TYPES,
|
||||
contract_errors,
|
||||
preflight as journey_preflight,
|
||||
suite as case_suite,
|
||||
test_type,
|
||||
)
|
||||
|
||||
try:
|
||||
import yaml
|
||||
@@ -370,7 +378,7 @@ def cmd_list(root: Path) -> int:
|
||||
pending = [c for c in cases if c.get("lifecycle") == "pending"]
|
||||
print(f"## 测试目录 active {len(active)} / pending {len(pending)} / retired {len(retired)}")
|
||||
print()
|
||||
headers = ["分类", "标题", "条数", "smoke"] + risks + list(DRIVERS)
|
||||
headers = ["分类", "标题", "条数", "journey", "integration", "smoke"] + risks + list(DRIVERS)
|
||||
print("| " + " | ".join(headers) + " |")
|
||||
print("| " + " | ".join("---" for _ in headers) + " |")
|
||||
|
||||
@@ -388,7 +396,14 @@ def cmd_list(root: Path) -> int:
|
||||
title = (cats_meta.get(cat) or {}).get("title") or (
|
||||
group[0].get("_file_title") if group else ""
|
||||
)
|
||||
row = [cat, str(title), str(len(group)), str(sum(1 for c in group if c.get("tag") == "smoke"))]
|
||||
row = [
|
||||
cat,
|
||||
str(title),
|
||||
str(len(group)),
|
||||
str(sum(1 for c in group if test_type(c) == "journey")),
|
||||
str(sum(1 for c in group if test_type(c) == "integration")),
|
||||
str(sum(1 for c in group if c.get("tag") == "smoke")),
|
||||
]
|
||||
for risk in risks:
|
||||
row.append(str(sum(1 for c in group if c.get("risk") == risk)))
|
||||
for driver in DRIVERS:
|
||||
@@ -783,7 +798,13 @@ def cmd_select(args: argparse.Namespace, root: Path) -> int:
|
||||
continue
|
||||
if args.tag and case.get("tag") != args.tag:
|
||||
continue
|
||||
if args.suite and client_suite(case) != args.suite:
|
||||
if args.test_type and test_type(case) != args.test_type:
|
||||
continue
|
||||
if args.suite and case_suite(case) != args.suite:
|
||||
continue
|
||||
# A mixed catalog keeps legacy cases runnable, but the implicit
|
||||
# default is the client journey surface. Integration is opt-in.
|
||||
if not args.test_type and not args.suite and test_type(case) == "integration":
|
||||
continue
|
||||
if args.driver and case.get("driver") != args.driver:
|
||||
continue
|
||||
@@ -814,6 +835,8 @@ def cmd_select(args: argparse.Namespace, root: Path) -> int:
|
||||
|
||||
selected, together = expand_run_together(meta, cases, selected, skipped, max_i, automation_filter)
|
||||
|
||||
# The historical key is kept in the JSON, but the gate now validates both
|
||||
# test types before any caller can start a phase.
|
||||
journey_gate = journey_preflight(selected, sessions=meta.get("sessions") or {})
|
||||
if journey_gate["status"] == "blocked":
|
||||
print(json.dumps({"preflight": journey_gate, "journey_preflight": journey_gate}, ensure_ascii=False, indent=2))
|
||||
@@ -850,6 +873,10 @@ def cmd_select(args: argparse.Namespace, root: Path) -> int:
|
||||
"artifacts": meta.get("artifacts") or {},
|
||||
"preflight": preflight,
|
||||
"journey_preflight": journey_gate,
|
||||
"test_types": {
|
||||
"journey": sum(1 for case in selected if test_type(case) == "journey"),
|
||||
"integration": sum(1 for case in selected if test_type(case) == "integration"),
|
||||
},
|
||||
"skipped": skipped,
|
||||
"run_together": together,
|
||||
"status_probe": status_probes,
|
||||
@@ -943,6 +970,17 @@ def validate(root: Path) -> list[str]:
|
||||
missing_suites = sorted(set(CLIENT_SUITES) - set(client_suites))
|
||||
if missing_suites:
|
||||
errors.append("catalog.client_suites 缺少标准套件: " + ", ".join(missing_suites))
|
||||
integration_suites = meta.get("integration_suites")
|
||||
if integration_suites is not None:
|
||||
if not isinstance(integration_suites, dict):
|
||||
errors.append("catalog.integration_suites 必须是 mapping")
|
||||
else:
|
||||
unknown = sorted(set(integration_suites) - set(INTEGRATION_SUITES))
|
||||
if unknown:
|
||||
errors.append("catalog.integration_suites 含非法套件: " + ", ".join(unknown))
|
||||
missing_suites = sorted(set(INTEGRATION_SUITES) - set(integration_suites))
|
||||
if missing_suites:
|
||||
errors.append("catalog.integration_suites 缺少标准套件: " + ", ".join(missing_suites))
|
||||
artifacts = meta.get("artifacts")
|
||||
if artifacts is not None:
|
||||
if not isinstance(artifacts, dict):
|
||||
@@ -1297,8 +1335,15 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
p_sel.add_argument("--category")
|
||||
p_sel.add_argument("--id", action="append", dest="ids", default=[])
|
||||
p_sel.add_argument("--tag", choices=TAGS)
|
||||
p_sel.add_argument("--suite", "--client-suite", dest="suite", choices=CLIENT_SUITES,
|
||||
help="客户端旅程套件")
|
||||
p_sel.add_argument(
|
||||
"--suite", "--client-suite", dest="suite",
|
||||
choices=[*CLIENT_SUITES, *INTEGRATION_SUITES],
|
||||
help="客户端或集成测试套件;不传时默认不选 integration",
|
||||
)
|
||||
p_sel.add_argument(
|
||||
"--test-type", choices=TEST_TYPES, default=None,
|
||||
help="按顶层 test_type 筛选;integration 必须显式选择",
|
||||
)
|
||||
p_sel.add_argument("--max-risk")
|
||||
p_sel.add_argument("--driver", choices=DRIVERS)
|
||||
p_sel.add_argument(
|
||||
|
||||
Reference in New Issue
Block a user