add a serial test lane for concurrency-vulnerable tests
Generalizes the pty split into an explicit "parallel=false" opt-out: a `serial` tag (declared in dart_test.yaml). The parallel flutter run now excludes `pty || serial`; a separate `flutter test --tags serial --concurrency=1` pass runs the vulnerable ones. For the coverage gate the two passes are real-merged by ci/merge_lcov.py (union DA, max hits, recompute LF/LH) — a plain concat would double-count and corrupt the total. Tag transcript_publisher's bus-republish test serial (it flaked in the parallel pool). Gate verified green end-to-end at 95.08%. T-193. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Merge lcov files into one, on stdout.
|
||||
|
||||
clide runs coverage in two passes — the parallel pool and a serial
|
||||
(`--tags serial --concurrency=1`) pass for tests that can't share the
|
||||
parallel runner (T-193). Each `flutter test --coverage` pass overwrites
|
||||
coverage/lcov.info, and the coverage gate naively sums LF:/LH: across
|
||||
records, so a source file appearing in BOTH passes would double-count.
|
||||
|
||||
This unions DA (line→hits) per source file, taking the MAX hit count (a
|
||||
line executed in EITHER pass counts as hit), then recomputes LF/LH. Line
|
||||
coverage only — which is all flutter emits and all the gate reads. No
|
||||
`lcov` dependency.
|
||||
|
||||
Usage: merge_lcov.py a.info b.info [...] > merged.info
|
||||
"""
|
||||
import sys
|
||||
|
||||
files = {} # source path -> {line: hits}
|
||||
order = [] # first-seen order, for stable output
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
cur = None
|
||||
with open(path) as fh:
|
||||
for raw in fh:
|
||||
line = raw.rstrip("\n")
|
||||
if line.startswith("SF:"):
|
||||
cur = line[3:]
|
||||
if cur not in files:
|
||||
files[cur] = {}
|
||||
order.append(cur)
|
||||
elif line.startswith("DA:") and cur is not None:
|
||||
num, _, hits = line[3:].partition(",")
|
||||
num, hits = int(num), int(hits)
|
||||
files[cur][num] = max(files[cur].get(num, 0), hits)
|
||||
elif line == "end_of_record":
|
||||
cur = None
|
||||
|
||||
out = []
|
||||
for sf in order:
|
||||
da = files[sf]
|
||||
out.append("SF:" + sf)
|
||||
for num in sorted(da):
|
||||
out.append(f"DA:{num},{da[num]}")
|
||||
out.append(f"LF:{len(da)}")
|
||||
out.append(f"LH:{sum(1 for h in da.values() if h > 0)}")
|
||||
out.append("end_of_record")
|
||||
|
||||
sys.stdout.write("\n".join(out) + "\n")
|
||||
+16
-4
@@ -30,10 +30,22 @@ echo "==> dart test (pty — unreliable under the flutter test runner; serial)"
|
||||
# for resource-bound tests, vs. the old per-test `retry:` band-aid. (T-193)
|
||||
dart test --concurrency=1 --tags pty test/pty/session_test.dart test/panes/registry_test.dart
|
||||
|
||||
# The parallel pool excludes both pty (runs under dart test, above) and
|
||||
# serial-tagged tests (concurrency-vulnerable — run in their own --concurrency=1
|
||||
# pass below). See dart_test.yaml + T-193.
|
||||
if [[ "$coverage" == 1 ]]; then
|
||||
echo "==> flutter test --coverage (gate; unit + widget + golden + a11y)"
|
||||
flutter test --coverage --exclude-tags pty --timeout 60s
|
||||
echo "==> flutter test --coverage (parallel pool; excludes pty + serial)"
|
||||
flutter test --coverage --exclude-tags "pty || serial" --timeout 60s
|
||||
cp coverage/lcov.info coverage/lcov.parallel.info
|
||||
echo "==> flutter test --coverage (serial-tagged; --concurrency=1)"
|
||||
flutter test --coverage --tags serial --concurrency=1 --timeout 60s
|
||||
echo "==> merge coverage (parallel + serial passes → coverage/lcov.info)"
|
||||
python3 ci/merge_lcov.py coverage/lcov.parallel.info coverage/lcov.info > coverage/lcov.merged.info
|
||||
mv coverage/lcov.merged.info coverage/lcov.info
|
||||
rm -f coverage/lcov.parallel.info
|
||||
else
|
||||
echo "==> flutter test (dev; no coverage, parallel)"
|
||||
flutter test --exclude-tags pty --concurrency=12 --timeout 60s
|
||||
echo "==> flutter test (dev; parallel pool, excludes pty + serial)"
|
||||
flutter test --exclude-tags "pty || serial" --concurrency=12 --timeout 60s
|
||||
echo "==> flutter test (dev; serial-tagged, --concurrency=1)"
|
||||
flutter test --tags serial --concurrency=1 --timeout 60s
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user