Files
WeHub Mirror 2bba424313
Integration Tests - PostgreSQL + Elasticsearch + Redis / Detect Changes (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Detect Changes (push) Has been cancelled
Java Checkstyle / java-checkstyle (push) Has been cancelled
Maven Collate Tests / maven-collate-ci (push) Has been cancelled
OpenMetadata Service Unit Tests / Detect Changes (push) Has been cancelled
Publish Package to Maven Central Repository / publish-maven-packages (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / Detect Changes (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / Build Integration Test Runtime (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / Integration Test Lane (global-state) (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / Integration Test Lane (multi-node) (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / Integration Test Lane (parallel) (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / Integration Test Lane (retry-queue) (push) Has been cancelled
Integration Tests - PostgreSQL + Elasticsearch + Redis / ${{ github.event_name == 'pull_request_target' && github.event.action == 'labeled' && github.event.label.name != 'safe to test' && 'integration-tests-postgres-elasticsearch-redis (ignored label)' || 'integration-tests-postgres-elasticsearch-redis' }} (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Build Integration Test Runtime (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Integration Test Lane (global-state) (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / Build Integration Test Runtime (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / Integration Test Lane (global-state) (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / Integration Test Lane (multi-node) (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / Integration Test Lane (parallel) (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / Integration Test Lane (retry-queue) (push) Has been cancelled
Integration Tests - MySQL + Elasticsearch / ${{ github.event_name == 'pull_request_target' && github.event.action == 'labeled' && github.event.label.name != 'safe to test' && 'integration-tests-mysql-elasticsearch (ignored label)' || 'integration-tests-mysql-elasticsearch' }} (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Integration Test Lane (parallel) (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Integration Test Lane (retry-queue) (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / ${{ github.event_name == 'pull_request_target' && github.event.action == 'labeled' && github.event.label.name != 'safe to test' && 'integration-tests-postgres-opensearch (ignored label)' || 'integration-tests-postgres-opensearch' }} (push) Has been cancelled
OpenMetadata Service Unit Tests / openmetadata-service-unit-tests (push) Has been cancelled
OpenMetadata Service Unit Tests / k8s_operator-unit-tests (push) Has been cancelled
OpenMetadata Service Unit Tests / openmetadata-service-unit-tests-status (push) Has been cancelled
Integration Tests - PostgreSQL + OpenSearch / Integration Test Lane (multi-node) (push) Has been cancelled
WeHub snapshot of bae3e29f60050c5970ef31185b76f560fdee41b7
2026-08-07 16:54:16 +08:00

162 lines
5.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""Verify planned coverage using timings and native zero-attempt skip records."""
from __future__ import annotations
import argparse
import glob
import json
from collections import Counter
from pathlib import Path
# Playwright "setup" projects declared in playwright.config.ts as
# `dependencies: [...]` values on other projects. Their tests run once per
# shard-invocation that includes a dependent project (Playwright behaviour —
# a setup project runs before each dependent), not once per plan. The planner
# already excludes them from `FULL_PROJECTS`, so they never appear in a
# shard's `testIds`. But they DO appear in the shard's timing artifact, so
# the coverage checker used to flag them as "unexpected + duplicate" whenever
# LPT split two dependent files across shards.
#
# Example failure — merge_group run 31083026904:
# [data-insight-application] > dataInsightApp.ts > Run Data Insight
# application and wait until success
# ran on chromium-04 AND chromium-17 because two @data-insight spec files
# landed on separate shards, but appeared in neither plan's `testIds`.
#
# Keep this list aligned with playwright.config.ts's setup-project section.
LIFECYCLE_PROJECTS: frozenset[str] = frozenset({
"setup",
"entity-data-setup",
"entity-data-teardown",
"data-insight-application",
"search-rbac-setup",
"search-rbac-teardown",
})
def is_lifecycle_test(test: dict) -> bool:
"""A `test` from the timing artifact is a lifecycle test if its Playwright
project name matches one of the setup projects declared in the config.
Lifecycle tests are expected to run once per shard-invocation, not once
per plan, so the coverage checker must exclude them from the plan-vs-exec
reconciliation.
"""
return test.get("project") in LIFECYCLE_PROJECTS
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument("--plan-glob", required=True)
parser.add_argument("--timing-glob", required=True)
parser.add_argument("--result-glob")
parser.add_argument("--output", type=Path, required=True)
return parser.parse_args()
def iter_specs(suite: dict) -> list[dict]:
specs = list(suite.get("specs", []))
for child in suite.get("suites", []):
specs.extend(iter_specs(child))
return specs
def zero_attempt_skipped_tests(report: dict, executed: Counter) -> dict[str, dict]:
skipped: dict[str, dict] = {}
for suite in report.get("suites", []):
for spec in iter_specs(suite):
test_id = spec.get("id")
if not test_id or test_id in executed:
continue
tests = spec.get("tests", [])
if not tests or not all(
test.get("status") == "skipped" and not test.get("results")
for test in tests
):
continue
skipped[test_id] = {
"id": test_id,
"project": tests[0].get("projectName", ""),
"file": spec.get("file", ""),
"title": spec.get("title", ""),
"category": "zero-attempt-skipped",
"reason": "unknown",
}
return skipped
def main() -> None:
args = parse_args()
planned = Counter()
executed = Counter()
plan_files = sorted(glob.glob(args.plan_glob, recursive=True))
timing_files = sorted(glob.glob(args.timing_glob, recursive=True))
result_files = (
sorted(glob.glob(args.result_glob, recursive=True)) if args.result_glob else []
)
for filename in plan_files:
payload = json.loads(Path(filename).read_text(encoding="utf-8"))
if "shardId" not in payload:
continue
planned.update(payload.get("testIds", []))
for filename in timing_files:
payload = json.loads(Path(filename).read_text(encoding="utf-8"))
executed.update(
test["id"]
for test in payload.get("tests", [])
if not is_lifecycle_test(test)
)
zero_attempt_skipped: dict[str, dict] = {}
for filename in result_files:
payload = json.loads(Path(filename).read_text(encoding="utf-8"))
zero_attempt_skipped.update(zero_attempt_skipped_tests(payload, executed))
zero_attempt_skipped = {
test_id: details
for test_id, details in zero_attempt_skipped.items()
if test_id in planned
}
duplicate_plans = sorted(test_id for test_id, count in planned.items() if count > 1)
duplicate_executions = sorted(
test_id for test_id, count in executed.items() if count > 1
)
missing = sorted(planned.keys() - executed.keys() - zero_attempt_skipped.keys())
unexpected = sorted(executed.keys() - planned.keys())
result = {
"version": 1,
"planFiles": len(plan_files),
"timingFiles": len(timing_files),
"resultFiles": len(result_files),
"plannedTests": len(planned),
"executedTests": len(executed),
"accountedTests": len(executed.keys() | zero_attempt_skipped.keys()),
"zeroAttemptSkippedTests": [
zero_attempt_skipped[test_id] for test_id in sorted(zero_attempt_skipped)
],
"zeroAttemptSkippedTestIds": sorted(zero_attempt_skipped),
"duplicatePlanTestIds": duplicate_plans,
"duplicateExecutionTestIds": duplicate_executions,
"missingTestIds": missing,
"unexpectedTestIds": unexpected,
}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(result, indent=2) + "\n", encoding="utf-8")
failures = duplicate_plans + duplicate_executions + missing + unexpected
if failures:
raise SystemExit(
"Playwright coverage mismatch: "
f"{len(missing)} missing, {len(unexpected)} unexpected, "
f"{len(duplicate_plans)} duplicate plans, and "
f"{len(duplicate_executions)} duplicate executions"
)
if __name__ == "__main__":
main()