Files
stack/agents/filbert/work/queue-97/r1/verify.py
T

83 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Row 97 independent verification. Do not run before its assigned test slot."""
import os, subprocess, signal, pathlib, json, hashlib, sys, time
root=pathlib.Path.home()/'filbert-scratch/r97-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/researcher/work/queue-97/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 active_group(group):
found=[]
for d in pathlib.Path('/proc').iterdir():
if not d.name.isdigit():continue
try:
if os.getpgid(int(d.name))==group:
stat=(d/'stat').read_text().split(') ',1)[1].split()[0]
if stat!='Z':found.append((d.name,(d/'comm').read_text().strip()))
except OSError:pass
return found
def run(cmd,cwd,log,limit=180):
quiet();start=time.monotonic()
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=limit);rc=p.returncode
except subprocess.TimeoutExpired:
rc='timeout'
try:os.killpg(p.pid,signal.SIGKILL)
except ProcessLookupError:pass
p.wait()
# Record normal cleanup BEFORE safety cleanup. Do not conceal leftover browser processes.
leftovers=active_group(p.pid)
if leftovers:
try:os.killpg(p.pid,signal.SIGKILL)
except ProcessLookupError:pass
return {'rc':rc,'seconds':round(time.monotonic()-start,2),'leftovers_before_safety_cleanup':leftovers}
rows=[];stage=sys.argv[1]
if stage in ['webui','control-board']:
cwd=root/'packages'/stage;r=run(['node','--test','tests/'],cwd,out/f'{stage}.log')
r.update(suite=stage,stats=[s for s in (out/f'{stage}.log').read_text().splitlines() if s.startswith(('ℹ tests ','ℹ pass ','ℹ fail ','# tests ','# pass ','# fail '))])
(out/f'{stage}-summary.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r),flush=True)
raise SystemExit(r['rc']!=0 or bool(r['leftovers_before_safety_cleanup']))
if stage=='shell':
for script in sorted((root/'scripts').glob('test-*.sh')):
r=run(['bash',str(script)],root,out/f'{script.stem}.log');r.update(suite=script.stem,last=(out/f'{script.stem}.log').read_text().splitlines()[-1:])
rows.append(r);print(json.dumps(r),flush=True)
(out/'shell-summary.json').write_text(json.dumps(rows,indent=2)+'\n')
raise SystemExit(any(r['rc']!=0 or r['leftovers_before_safety_cleanup'] for r in rows))
if stage!='mutants':raise SystemExit('usage: verify.py webui|control-board|shell|mutants')
A='packages/webui/src/public/app.js';B='packages/webui/src/public/bus.js'
M=[
('13 toggle-off schedule',A,'if (!paused && machine && !out()) timer','if (!paused && !out()) timer',['tests/board-held.test.mjs'],120),
('27 signed-out bus schedule',B,'if (!paused() && !out()) timer','if (!paused()) timer',['tests/board-held.test.mjs'],120),
('19 toggle on reads nothing',A,'fresh(); refresh(); } else hideMachine();','fresh(); } else hideMachine();',['tests/browser-edge.test.mjs'],30),
]
start={path:hashlib.sha256((root/path).read_bytes()).hexdigest() for path in [A,B]}
for name,path,old,new,tests,limit in M:
quiet();p=root/path;orig=p.read_bytes();src=orig.decode();assert src.count(old)==1,(name,src.count(old))
try:
p.write_text(src.replace(old,new));log=out/f'mutant-{name.split()[0]}.log'
r=run(['node','--test',*tests],root/'packages/webui',log,limit)
r.update(mutant=name,result='survived' if r['rc']==0 else 'stalled' if r['rc']=='timeout' else 'killed')
if name.startswith('19 '):r['five_second_message_seen']='Show machine sessions made no /api/board request in 5 s' in log.read_text()
rows.append(r);print(json.dumps(r),flush=True)
finally:p.write_bytes(orig)
assert all(hashlib.sha256((root/path).read_bytes()).hexdigest()==sha for path,sha in start.items())
matches()
r=run(['node','--test','tests/board-held.test.mjs','tests/browser-edge.test.mjs'],root/'packages/webui',out/'restored-tests.log')
r.update(restored_tests=True,manifest_matches=True,product_sources_restored=True);rows.append(r);print(json.dumps(r),flush=True)
(out/'mutant-summary.json').write_text(json.dumps(rows,indent=2)+'\n')
raise SystemExit(r['rc']!=0 or any(x.get('result') in ['survived','stalled'] or x['leftovers_before_safety_cleanup'] or x.get('five_second_message_seen') is False for x in rows))