diff --git a/docs/parity-workflow.md b/docs/parity-workflow.md index 9153949df..bbb7512df 100644 --- a/docs/parity-workflow.md +++ b/docs/parity-workflow.md @@ -123,9 +123,13 @@ callers. Run Linux games under `xvfb-run -a` when no display is available. Each process gets scratch game, launcher, XDG data and config homes; telemetry, audio and launcher self-update are disabled. -`lan_integration` and `friends_integration` register these suites with the normal -`parity.py` selection used by CI. Their traced imports and Cargo artifacts select -them when the drivers or game implementation change. LAN writes `results.json` +`lan_integration` and `friends_integration` register these suites with `parity.py`. +`friends_integration` (under a minute) is selected like any harness when the +drivers or game implementation change. `lan_integration` is the whole LAN suite +(~40 minutes on a loaded runner, and single checks flake under load), so +`tools/parity_hosts.json` lists it under `named_only`: no automatic selection +(`--changed`, `--failed`, `--flake-check`, CI, parity-main) picks it; it runs +when named and in the nightly audit (`--all`). LAN writes `results.json` with the host mode and each result beside its screenshots and logs. A skipped case is recorded explicitly and does not count as passing coverage. diff --git a/tests/test_parity_runner.py b/tests/test_parity_runner.py index 2d16e7179..a85f1e969 100644 --- a/tests/test_parity_runner.py +++ b/tests/test_parity_runner.py @@ -145,6 +145,11 @@ class ParityRunnerTests(unittest.TestCase): with mock.patch.object(parity.sys, "platform", "darwin"): self.assertEqual(parity.platform_skips(config), {"options": "libm"}) + def test_named_only_harnesses_are_listed_from_the_host_config(self): + self.assertEqual(parity.named_only({"named_only": {"lan_integration": "slow"}}), {"lan_integration": "slow"}) + self.assertEqual(parity.named_only({}), {}) + self.assertIn("lan_integration", parity.named_only(parity.host_config())) + def test_a_pass_from_another_worktree_counts_only_for_the_same_content(self): with tempfile.TemporaryDirectory() as temp: elsewhere, here, shared = Path(temp, "a"), Path(temp, "b"), Path(temp, "shared") diff --git a/tools/parity.py b/tools/parity.py index 3f18b922d..4c2cd5426 100644 --- a/tools/parity.py +++ b/tools/parity.py @@ -11,6 +11,9 @@ python3 tools/parity.py --list # what would run, without running it python3 tools/parity.py --status # last result of every harness +Harnesses in parity_hosts.json's "named_only" run only when named or with --all +(the nightly audit): no automatic selection picks them. + Each harness runs unmodified, in parallel, under a tracer that records what it read: its Python modules, Java oracle sources, other repository files, and the Rust sources of every probe it executed (from Cargo's dep-info). A harness @@ -1285,6 +1288,12 @@ def platform_skips(config): return dict(config.get("linux_only", {})) +def named_only(config): + """Harnesses tools/parity_hosts.json keeps out of every automatic selection (--changed, --failed, the default, + --flake-check): they run only when named or with --all, the nightly audit. {name: reason}""" + return dict(config.get("named_only", {})) + + def finished_run(failed): """Record that this run completed, for tools/gate.py: a crashed runner never writes it.""" STATE_DIR.mkdir(parents=True, exist_ok=True) @@ -1369,9 +1378,13 @@ def main(): for name in [name for name in chosen if base_name(name) in skips and not args.names]: print(f"skipped on {sys.platform}: {name}: {skips[base_name(name)]}", flush=True) chosen.remove(name) + manual = {} if args.names or args.all else named_only(host_config()) + for name in [name for name in chosen if base_name(name) in manual]: + print(f"not selected (runs when named, and nightly): {name}: {manual[base_name(name)]}", flush=True) + chosen.remove(name) rounds = {name: args.repeat for name in chosen} if args.repeat > 1 else {} if args.flake_check: - changed = changed_harnesses(found, records, args.flake_check) + changed = {name for name in changed_harnesses(found, records, args.flake_check) if base_name(name) not in manual} for name in sorted(changed): # A pass counts for a changed harness only if it held over enough runs. if name not in chosen and records.get(name, {}).get("rounds", 1) < args.flake_rounds: diff --git a/tools/parity_hosts.json b/tools/parity_hosts.json index f2ba65c68..164a3ff42 100644 --- a/tools/parity_hosts.json +++ b/tools/parity_hosts.json @@ -36,5 +36,8 @@ "local_only": { "save_roundtrip": "runs the game on a virtual screen (vscreen) with a null ALSA device, or offscreen in the logged-in macOS session" }, - "linux_only": {} + "linux_only": {}, + "named_only": { + "lan_integration": "the whole lan_e2e suite: ~40 min a run on a loaded runner, and single checks flake under load; run it by name, or tools/lan_e2e.py" + } }