mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
Exit gates 9.2 and 9.3. Until now nothing ran the integration suite across a
process boundary at all - the spawn shape was proven only by the retrace lane,
which exercises one trace per case and no scenario assertions.
integration-spawn: 102 cases, 102 green.
THE SET IDENTITY IS THE POINT, AND IT IS NOT MAINTAINED BY HAND. 9.2 asks that
the spawn lane's case-name set equal the split lane's. Registering the spawn
arm as a second copy of each block would satisfy that today and drift the first
time somebody adds a scenario to one of them - and a spawn lane covering LESS
goes green while proving less, with nothing about a smaller green lane looking
wrong. The eleven split-environment blocks become eleven calls to one macro
that emits BOTH arms from one filter, so a case added to either is added to
both or to neither.
scripts/ci/spawn_lane_parity.py asserts it anyway, because a macro is one edit
from a hand-written block. It compares SETS rather than counts - a count can
agree while the membership does not - and carries exactly one sanctioned
asymmetry, named in the file: integration-split also labels the PUSH-MONOLITH
arm, whose scenario is monolith-only by construction. R-16: introduce a
split-only block and it reds naming the case and the macro to use.
THREE CASES SKIP UNDER SPAWN, BY NAME. CtWireScenario reads PipeApplier's
in-process tallies through ServerVerbs(); under spawn those live in the SERVER's
process and this one's copy is 0 forever, so the assertions were failing about
somebody else's memory. That is a harness limit, not a product defect - the
records themselves cross, which the retrace lane proves. They are SKIPPED and
not deregistered: a case dropped from the registration would make the two sets
differ silently, which is the drift the macro exists to prevent. What retires
the skip is cross-process telemetry, which is also what S8's SessionFaultCount
needs.
TWO REAL REGRESSIONS THE EXISTING GATES CAUGHT, both from this refactor:
* the macro dropped the per-block TEST_LIST variables, which were what
SplitLogPaths fed to give every entry a PRIVATE MOBILEGL_LOG_FILE_PATH.
SplitLogPaths.PrivateAndDistinct went red naming the first orphan. The
macro accumulates list NAMES now, so a block added later is covered without
anyone remembering to extend a list - and the names have to be unique,
because gtest_discover_tests' TEST_LIST is populated when CTEST runs, not
at configure time, so one shared variable held only the last block's
entries. That matters more on the spawn arm: there TWO PROCESSES append to
the path, so a shared file interleaves two sessions rather than merely
being ambiguous.
* the configure_file that substitutes those names ran BEFORE the F1 and Ct
blocks registered, so it captured neither. Same gate, naming
F1WireScenario.ClearBufferfiPixels. It now runs last.
junit_tally gains --require-spawn-ran beside --require-split-ran: the prefix IS
the arm, and a shared flag would let one lane tally the other's entries and call
itself run. Verified to discriminate - the spawn junit reads 96/0/5 under its
own flag and 0/0/0 under the split flag, which correctly fails.
Two death tests follow the ADOPT_TIER message the census commit retagged with
Fatal{UnimplementedAdoptTier}; their regexes asserted the old wording.
Unit 2353 (one pre-existing environmental failure), integration-split 186/186,
integration-spawn 102/102, retrace 6/6, fatal census 0 unmarked, G1 0 symbols
and .text unchanged at 0xa52203.
71 lines
3.2 KiB
Python
71 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Exit gate 9.2: integration-spawn's case-name set equals integration-split's.
|
|
|
|
WHY A GATE AND NOT A COMMENT. The two lanes are registered from one macro, so today they agree
|
|
by construction - but a macro is one edit away from a second hand-written block, and a spawn lane
|
|
covering LESS than the split lane goes green while proving less. Nothing about a smaller green
|
|
lane looks wrong. This asserts the sets rather than the counts, because a count can agree while
|
|
the membership does not.
|
|
|
|
ARM PREFIXES ARE STRIPPED BEFORE COMPARING. The lanes deliberately differ in name -
|
|
`DirectGLES.Split.X` against `DirectGLES.Spawn.X` - and the sub-lane tails (`F1.`, `Ct.`) are
|
|
part of neither the case nor the arm, so both come off.
|
|
|
|
ONE SANCTIONED ASYMMETRY, LISTED HERE AND NOWHERE ELSE. `integration-split` also labels the
|
|
PUSH-MONOLITH arm (the CMakeLists explains why: the label means "the set the disaggregation gate
|
|
runs", not "runs inproc"), and that arm's scenario is monolith-only by construction. It cannot
|
|
have a spawn counterpart, so it is named as an exception rather than allowed to widen the
|
|
tolerance for everything else.
|
|
"""
|
|
import argparse
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
# Registered only on the push-monolith arm, which has no spawn counterpart by construction.
|
|
MONOLITH_ONLY = {"MonolithAttachmentClearScenario"}
|
|
|
|
CASE = re.compile(r"DirectGLES\.[A-Za-z0-9]+\.(?:F1\.|Ct\.)?([A-Za-z0-9_]+Scenario\.[A-Za-z0-9_]+)")
|
|
|
|
|
|
def lane_cases(build_dir, label):
|
|
out = subprocess.run(["ctest", "-N", "-L", label], cwd=build_dir,
|
|
capture_output=True, text=True).stdout
|
|
return {m.group(1) for m in CASE.finditer(out)}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("build_dir")
|
|
args = parser.parse_args()
|
|
|
|
split = lane_cases(args.build_dir, "integration-split")
|
|
spawn = lane_cases(args.build_dir, "integration-spawn")
|
|
if not split or not spawn:
|
|
print(f"::error::a lane is EMPTY (split={len(split)}, spawn={len(spawn)}). An empty set "
|
|
f"compares equal to nothing and would pass this gate silently, which is the one "
|
|
f"way it could stop meaning anything.", file=sys.stderr)
|
|
return 1
|
|
|
|
split_comparable = {c for c in split if c.split(".", 1)[0] not in MONOLITH_ONLY}
|
|
missing = sorted(split_comparable - spawn)
|
|
extra = sorted(spawn - split_comparable)
|
|
|
|
print(f"spawn-lane parity: split {len(split)} ({len(split_comparable)} comparable), "
|
|
f"spawn {len(spawn)}")
|
|
if missing:
|
|
print("::error::cases in integration-split with no integration-spawn counterpart: " +
|
|
", ".join(missing) + ". Exit gate 9.2 requires the sets to be equal - a spawn lane "
|
|
"that covers less goes green while proving less. Register through "
|
|
"mgl_itest_register_split_arms, which emits both arms from one filter.",
|
|
file=sys.stderr)
|
|
if extra:
|
|
print("::error::cases in integration-spawn that integration-split does not run: " +
|
|
", ".join(extra) + ". The split arm is the control; a case only the spawn arm runs "
|
|
"has no baseline to be compared against.", file=sys.stderr)
|
|
return 1 if (missing or extra) else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|