65 lines
3.5 KiB
Python
65 lines
3.5 KiB
Python
"""Run one row 69 verification stage after the reserved test slot clears."""
|
||
import os, subprocess, signal, pathlib, json, hashlib, sys
|
||
root=pathlib.Path.home()/'filbert-scratch/r69-review/wt'
|
||
out=root.parent/'verification';out.mkdir(exist_ok=True)
|
||
env=dict(os.environ,TMPDIR=str(pathlib.Path.home()/'filbert-scratch/tmp'),DOCKER_HOST='unix:///nonexistent.sock')
|
||
seats=['darkwing','dewey','rocko','researcher','sage']
|
||
other=[str(pathlib.Path.home()/f'{seat}-scratch') for seat in seats]+[str(pathlib.Path('/mnt/storage/scratch')/seat) for seat in seats]
|
||
def quiet():
|
||
busy=[]
|
||
for p in pathlib.Path('/proc').iterdir():
|
||
if not p.name.isdigit():continue
|
||
try:
|
||
cwd=str((p/'cwd').resolve(strict=True))
|
||
if any(cwd==x or cwd.startswith(x+'/') for x in other):busy.append((p.name,cwd))
|
||
except (OSError,RuntimeError):pass
|
||
if busy:raise SystemExit('Other scratch processes active: '+repr(busy))
|
||
def matches():
|
||
m=pathlib.Path('/mnt/storage/src/mosaic-stack/agents/darkwing/work/queue-69/candidate-manifest.sha256')
|
||
for line in m.read_text().splitlines():
|
||
sha,path=line.split();assert hashlib.sha256((root/path).read_bytes()).hexdigest()==sha,path
|
||
quiet();matches()
|
||
def run(cmd,cwd,log):
|
||
quiet()
|
||
with log.open('w') as f:
|
||
p=subprocess.Popen(cmd,cwd=cwd,env=env,stdout=f,stderr=subprocess.STDOUT,start_new_session=True)
|
||
try:p.wait(timeout=180)
|
||
except subprocess.TimeoutExpired:
|
||
os.killpg(p.pid,signal.SIGKILL);p.wait();return 'timeout'
|
||
return p.returncode
|
||
stage=sys.argv[1]
|
||
if stage in ['cli','queue']:
|
||
cwd=root/'packages'/stage
|
||
files=[str(p.relative_to(cwd)) for p in sorted((cwd/'tests').glob('*.test.mjs'))]
|
||
rc=run(['node','--test',*files],cwd,out/f'{stage}.log')
|
||
stats=[s for s in (out/f'{stage}.log').read_text().splitlines() if s.startswith(('ℹ tests ','ℹ pass ','ℹ fail ','# tests ','# pass ','# fail '))]
|
||
row={'suite':stage,'rc':rc,'stats':stats};print(json.dumps(row),flush=True)
|
||
(out/f'{stage}-summary.json').write_text(json.dumps(row,indent=2)+'\n')
|
||
raise SystemExit(rc!=0)
|
||
if stage!='mutants':raise SystemExit('usage: verify.py cli|queue|mutants')
|
||
S='packages/cli/src/screens.mjs';A='packages/cli/src/app.mjs'
|
||
M=[
|
||
('shown-no-min-cols',S,'return cols >= MIN_COLS && rows >= MIN_ROWS && o?.kind','return rows >= MIN_ROWS && o?.kind'),
|
||
('r3-shown-no-min',S,'return cols >= MIN_COLS && rows >= MIN_ROWS && o?.kind','return o?.kind'),
|
||
('n9-17000-end-off',S,'(n >= 0x17000 && n <= 0x18d08)','(n >= 0x17000 && n <= 0x18cff)'),
|
||
('cut-drops-choice',S,'const tail = b.slice(-2);','const tail = b.slice(-1);'),
|
||
('hidden-no-way-out',S,', "Resize, or use mosaic decide."]',']'),
|
||
('hidden-status-promises-y',A,'const state = hidden ? {','const state = false ? {'),
|
||
]
|
||
rows=[]
|
||
for name,path,old,new in M:
|
||
quiet();p=root/path;src=p.read_text();assert src.count(old)==1,(name,src.count(old))
|
||
try:
|
||
p.write_text(src.replace(old,new));log=out/f'mutant-{name}.log'
|
||
rc=run(['node','--test','packages/cli/tests/app.test.mjs'],root,log)
|
||
failures=[s for s in log.read_text().splitlines() if s.startswith(('✖','not ok'))]
|
||
row={'mutant':name,'rc':rc,'result':'survived' if rc==0 else 'timeout' if rc=='timeout' else 'killed','failures':failures[:4]}
|
||
rows.append(row);print(json.dumps(row),flush=True)
|
||
finally:p.write_text(src)
|
||
matches()
|
||
rc=run(['node','--test','packages/cli/tests/app.test.mjs'],root,out/'restored-app.log')
|
||
rows.append({'restored_app_rc':rc,'manifest_matches':True})
|
||
(out/'mutant-summary.json').write_text(json.dumps(rows,indent=2)+'\n')
|
||
print(json.dumps(rows[-1]),flush=True)
|
||
raise SystemExit(rc!=0 or any(r.get('result') in ['survived','timeout'] for r in rows))
|