mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-30 08:36:55 +09:00
The floor was --update'd from a dev box again, so CI collected 4516 against a floor of 4530 and the ratchet went red for a suite that lost nothing. Same 14 cases as last time (4431 -> 4417): test_builtin_extension_drift.py parametrises over the on-disk intersection of builtin-extensions/<ext>/backend and app/plugins/<ext>, and four live copies here are gitignored -- cloud-provision (3), ftp (3), remote-access (5), status (3). Fixing the number alone would queue up a third occurrence, so the machine-dependence is closed instead: check_test_count.py now collects with SERVERKIT_CLEAN_COLLECT=1, and under that flag the drift test pairs only git-TRACKED live copies. Ordinary runs are untouched and still compare the gitignored copies on the machine that has them. Verified with the WSL venv: the ratchet now reports 4518 locally, exactly CI's 4516 plus the two tests added here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
108 lines
4.5 KiB
Python
108 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Test-count ratchet — the guard the 2026-07 data loss taught us to want.
|
|
|
|
Back then code and its proving tests died TOGETHER, so the suite stayed green
|
|
(2572 -> 2209 passing) while whole features silently vanished — nobody diffs a
|
|
green number. This checks the collected-test count against a checked-in floor
|
|
(``backend/tests/BASELINE_COUNT``) and FAILS if collection has dropped below it.
|
|
|
|
- Raising the floor is expected as tests are added — run with ``--update`` to
|
|
bump ``BASELINE_COUNT`` to the current count (or just edit the file).
|
|
- Lowering it requires editing ``BASELINE_COUNT`` in the same commit — an
|
|
explicit, reviewable statement that tests were intentionally removed, instead
|
|
of a silent regression.
|
|
- Collection runs with ``SERVERKIT_CLEAN_COLLECT=1`` so the number is the one a
|
|
CLEAN CHECKOUT collects. A dev box carries gitignored extension copies that
|
|
add parametrised cases CI can never see; ``--update`` used to bake those into
|
|
the floor and leave the ratchet permanently red.
|
|
|
|
Usage:
|
|
python tests/check_test_count.py # verify (CI mode) — exit 1 if below
|
|
python tests/check_test_count.py --update # write current count as the new floor
|
|
|
|
Run from the ``backend/`` directory.
|
|
"""
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
BASELINE_FILE = os.path.join(HERE, 'BASELINE_COUNT')
|
|
|
|
|
|
def read_baseline():
|
|
try:
|
|
with open(BASELINE_FILE) as f:
|
|
return int(f.read().strip())
|
|
except (OSError, ValueError):
|
|
return 0
|
|
|
|
|
|
def collect_count():
|
|
"""Return the number of tests pytest collects, without running them."""
|
|
# Scoped to tests/ on purpose: a bare collect from backend/ also walks
|
|
# whatever this machine has lying around (dev-data/, sibling checkouts),
|
|
# which is how the floor was once --update'd ~282 items above anything a
|
|
# clean checkout can collect, turning the ratchet permanently red.
|
|
# SERVERKIT_CLEAN_COLLECT makes the count machine-independent: the only
|
|
# module whose parametrisation varies with what is on disk
|
|
# (test_builtin_extension_drift.py, which pairs builtin-extensions/<ext>
|
|
# against the mostly-gitignored live copies under app/plugins/) restricts
|
|
# itself to git-TRACKED copies when it is set. Without it, --update on a dev
|
|
# box wrote a floor no clean checkout could reach -- 4431 -> 4417, and again
|
|
# 4530 -> 4516, both times 14 cases from four gitignored extensions.
|
|
env = dict(os.environ, SERVERKIT_CLEAN_COLLECT='1')
|
|
proc = subprocess.run(
|
|
[sys.executable, '-m', 'pytest', 'tests', '--collect-only', '-q',
|
|
'-p', 'no:cacheprovider'],
|
|
cwd=os.path.dirname(HERE), # backend/
|
|
capture_output=True, text=True, env=env,
|
|
)
|
|
out = proc.stdout + proc.stderr
|
|
if proc.returncode != 0:
|
|
# Collection errors silently DEFLATE the count — an import-broken
|
|
# test module must fail the guard, not shrink the number it reports.
|
|
sys.stderr.write(f'pytest collection exited {proc.returncode}; '
|
|
'refusing to trust a partial count.\n')
|
|
sys.stderr.write(out[-2000:] + '\n')
|
|
sys.exit(2)
|
|
# pytest prints e.g. "2475 tests collected in 6.55s" (or "1 test collected")
|
|
m = re.search(r'(\d+)\s+tests?\s+collected', out)
|
|
if not m:
|
|
sys.stderr.write('Could not parse a collected-test count from pytest.\n')
|
|
sys.stderr.write(out[-2000:] + '\n')
|
|
sys.exit(2)
|
|
return int(m.group(1))
|
|
|
|
|
|
def main():
|
|
update = '--update' in sys.argv[1:]
|
|
collected = collect_count()
|
|
baseline = read_baseline()
|
|
|
|
if update:
|
|
with open(BASELINE_FILE, 'w') as f:
|
|
f.write(f'{collected}\n')
|
|
print(f'BASELINE_COUNT updated: {baseline} -> {collected}')
|
|
return 0
|
|
|
|
print(f'collected={collected} baseline={baseline}')
|
|
if collected < baseline:
|
|
sys.stderr.write(
|
|
f'\nTEST-COUNT RATCHET FAILED: collected {collected} tests, but the '
|
|
f'floor is {baseline}.\n'
|
|
'Tests disappeared. If this is an intentional removal, lower '
|
|
f'{os.path.relpath(BASELINE_FILE)} in THIS commit; otherwise a '
|
|
'feature (and its proving tests) went missing — investigate before '
|
|
'merging.\n')
|
|
return 1
|
|
if collected > baseline:
|
|
print(f'note: {collected - baseline} new test(s) since the floor was '
|
|
'set — run this with --update to raise BASELINE_COUNT.')
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|