#!/usr/bin/env python3 """Run every source test, retain logs and continue past failures. The exported-package test needs a built PCK and runs via make test-exported-opening. """ import argparse import json from pathlib import Path import subprocess import time def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--output', type=Path, default=Path('artifacts/all-tests')) parser.add_argument('--godot', default='godot') parser.add_argument('--timeout', type=int, default=1200) args = parser.parse_args() root = Path(__file__).resolve().parents[1] output = args.output.resolve() output.mkdir(parents=True, exist_ok=True) paths = [root / 'tests/run_tests.gd'] + sorted((root / 'tests').rglob('test*.gd')) results = [] for path in paths: relative = path.relative_to(root) if 'export' in relative.parts or relative.as_posix() == 'tests/s0/test_kernel_and_save.gd': # The RefCounted kernel module is already invoked by run_tests.gd. continue start = time.monotonic() name = str(relative).replace('/', '__') + '.log' # Stream to disk so long-running scenarios expose progress immediately. with (output / name).open('w') as log: try: run = subprocess.run( [args.godot, '--headless', '--path', str(root), '--script', 'res://' + str(relative)], cwd=root, stdout=log, stderr=subprocess.STDOUT, timeout=args.timeout, ) code = run.returncode except subprocess.TimeoutExpired: code = 124 content = (output / name).read_text() failed = code != 0 or 'SCRIPT ERROR:' in content or '\nERROR:' in content results.append(dict(test=str(relative), exit_code=code, failed=failed, seconds=round(time.monotonic() - start, 2), log=name)) (output / 'all-tests.json').write_text(json.dumps(results, indent=2) + '\n') print(f'{"FAIL" if failed else "PASS"} {relative}', flush=True) failed = sum(result['failed'] for result in results) print(f'{len(results)} tests, {failed} failures; logs: {output}') return 1 if failed else 0 if __name__ == '__main__': raise SystemExit(main())