#!/usr/bin/env python3 """Row278 commands prepared for Sage CLEAR. No execution on import.""" import argparse import hashlib import importlib.util import json import os from pathlib import Path import subprocess import sys sys.dont_write_bytecode = True HERE = Path(__file__).resolve().parent spec = importlib.util.spec_from_file_location('row278_checks', HERE/'checks.py') checks = importlib.util.module_from_spec(spec) spec.loader.exec_module(checks) def totals(path): result = {} for line in path.read_text(errors='replace').splitlines(): for key in ['tests', 'pass', 'fail', 'skipped']: prefix = '# '+key+' ' if line.startswith(prefix) and line[len(prefix):].isdigit(): result[key] = int(line[len(prefix):]) return result def main(): ap = argparse.ArgumentParser() ap.add_argument('--grant', required=True) ap.add_argument('--stage', choices=['syntax', 'red', 'focused', 'whole'], required=True) ap.add_argument('--out', type=Path, required=True) args = ap.parse_args() if not os.environ.get('TMPDIR', '').startswith('/mnt/storage/scratch/tmp/g'): raise RuntimeError('use the granted scratch TMPDIR') expected = json.loads((HERE/'CANDIDATE-SHAS.json').read_text()) for name, sha in expected.items(): assert hashlib.sha256((checks.REPO/name).read_bytes()).hexdigest() == sha, name args.out.mkdir(parents=True, exist_ok=True) results = dict(grant=args.grant, stage=args.stage, steps=[]) def step(name, command, red=False, seconds=1200): r = checks.run(command, args.out/(name+'.log'), seconds=seconds) r.update(name=name, expected_red=red, counts=totals(Path(r['log']))) results['steps'].append(r) (args.out/'results.json').write_text(json.dumps(results, indent=2)+'\n') if r['timeout']: raise RuntimeError('timeout: stop and report') if red and r['code'] == 0: raise RuntimeError('expected RED did not fail: stop and report') if not red and r['code'] != 0: raise RuntimeError('unexpected failure: stop and report') tests = ['packages/webui/tests/thread-claims.test.mjs', 'packages/webui/tests/thread-claims-browser.test.mjs', 'packages/webui/tests/shell.test.mjs'] if args.stage == 'syntax': for index, name in enumerate(expected): if name.endswith(('.js', '.mjs')): step('syntax-'+str(index), ['node', '--check', name]) elif args.stage == 'red': targets = ['packages/webui/src/cli.mjs', 'packages/webui/src/serve.mjs', 'packages/webui/src/public/bus.js'] saved = {name: (checks.REPO/name).read_bytes() for name in targets} status = subprocess.check_output(['git', 'status', '--porcelain', '--untracked-files=no'], cwd=checks.REPO) try: for name in targets: (checks.REPO/name).write_bytes(subprocess.check_output(['git', 'show', '6af85df4b:'+name], cwd=checks.REPO)) for index, (name, pattern) in enumerate(zip(tests, ['row278 HTTP read returns held claims', 'row278 browser lists held claims'])): step('red-'+str(index), ['node', '--test', '--test-reporter=tap', '--test-name-pattern', pattern, name], red=True) finally: for name, data in saved.items(): (checks.REPO/name).write_bytes(data) assert (checks.REPO/name).read_bytes() == data assert subprocess.check_output(['git', 'status', '--porcelain', '--untracked-files=no'], cwd=checks.REPO) == status elif args.stage == 'focused': for index, name in enumerate(tests): step('focused-'+str(index), ['node', '--test', '--test-reporter=tap', name]) else: step('bus', ['node', '--test', '--test-reporter=tap', 'packages/bus/tests/']) step('webui', ['node', '--test', '--test-reporter=tap', 'packages/webui/tests/']) files = sorted((checks.REPO/'scripts').glob('test-*.sh')) assert len(files) == 10 limits = json.loads((HERE/'SHELL-LIMITS.json').read_text())['scripts'] for path in files: script = str(path.relative_to(checks.REPO)) limit = limits[script]['limit_seconds'] step(path.stem, ['timeout', '-k', '10', str(limit), 'bash', script], seconds=limit+30) print(json.dumps(results, indent=2)) if __name__ == '__main__': main()