"""Run release tests in bounded file groups using a disposable test environment. Set AIM_TEST_CORE_ROOT to a pristine Core source extraction, not a live controller. Artifacts go to --out; this does not install dependencies or contact real hosts. """ from __future__ import annotations import argparse import concurrent.futures import json import os from pathlib import Path import re import subprocess import sys import time def main() -> int: parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('--out',type=Path,required=True) parser.add_argument('--workers',type=int,default=3,choices=range(1,5)) parser.add_argument('--timeout',type=int,default=180) args=parser.parse_args() if args.timeout<30:parser.error('timeout must be at least 30 seconds') core=os.environ.get('AIM_TEST_CORE_ROOT','') if not core or not (Path(core)/'scripts/aimctl.py').is_file(): parser.error('Set AIM_TEST_CORE_ROOT to the pristine supplied Core source extraction.') root=Path(__file__).resolve().parents[1];args.out.mkdir(parents=True,exist_ok=True) env={**os.environ,'PYTEST_DISABLE_PLUGIN_AUTOLOAD':'1'} def run(path: Path) -> dict: started=time.monotonic() try: p=subprocess.run([sys.executable,'-m','pytest',str(path),'-q','-p','no:cacheprovider'], cwd=root,env=env,capture_output=True,text=True,timeout=args.timeout) output=p.stdout+p.stderr;code=p.returncode except subprocess.TimeoutExpired as exc: output=(exc.stdout or b'').decode(errors='replace') if isinstance(exc.stdout,bytes) else (exc.stdout or '') output+='\nRelease test-file timeout; not a pass.\n';code=124 (args.out/(path.stem+'.log')).write_text(output) summary=next((line for line in reversed(output.splitlines()) if re.search(r'\d+ (passed|failed|skipped|error)',line)),'No test summary') counts={k:int(n) for n,k in re.findall(r'(\d+) (passed|failed|skipped|errors?)',summary)} return {'file':path.name,'returncode':code,'seconds':round(time.monotonic()-started,3),'summary':summary,'counts':counts} with concurrent.futures.ThreadPoolExecutor(max_workers=args.workers) as pool: results=list(pool.map(run,sorted((root/'tests').glob('test_*.py')))) totals={k:sum(x['counts'].get(k,0) for x in results) for k in ('passed','failed','skipped','error','errors')} value={'mode':'independent bounded test-file groups','files':results,'totals':totals, 'all_passed':all(x['returncode']==0 for x in results),'native_managed_hosts_tested':False} (args.out/'results.json').write_text(json.dumps(value,indent=2)+'\n') for result in results:print(result['file']+': '+result['summary'],flush=True) print(json.dumps(totals),flush=True) return 0 if value['all_passed'] else 1 if __name__=='__main__':raise SystemExit(main())