56 lines
4.0 KiB
Python
56 lines
4.0 KiB
Python
from pathlib import Path
|
|
import os,subprocess,signal,tempfile,json,re,time,hashlib,shlex
|
|
from datetime import datetime,timezone
|
|
ROOT=Path('/mnt/storage/scratch/rocko-r219'); RED=Path('/mnt/storage/scratch/rocko-r219-red-mos1429')
|
|
P=ROOT/'agents/rocko/work/queue-219';OUT=P/'r4/short-run';OUT.mkdir(exist_ok=True)
|
|
HEAD='7e70de9e68ba48d761a45894d037239b5d576a38';OLD='bfa421b6cd9b2b54d8da119e73b004aeafe606c3'
|
|
def stamp():return datetime.now(timezone.utc).isoformat()
|
|
def verify():
|
|
assert subprocess.check_output(['git','rev-parse','HEAD'],cwd=ROOT,text=True).strip()==HEAD
|
|
assert subprocess.check_output(['git','rev-parse','HEAD'],cwd=RED,text=True).strip()==OLD
|
|
for line in (P/'candidate-manifest.sha256').read_text().splitlines():
|
|
sha,path=line.split(' ',1);assert hashlib.sha256((ROOT/path).read_bytes()).hexdigest()==sha,path
|
|
|
|
def execute(label,root,file,pattern=None):
|
|
args=['node','--test','--test-reporter=tap']
|
|
if pattern:args+=['--test-name-pattern',pattern]
|
|
args+=[file]
|
|
env=os.environ.copy();env.update(TMPDIR=tempfile.mkdtemp(prefix='r',dir='/mnt/storage/scratch/tmp'),DOCKER_HOST='unix:///mnt/storage/scratch/rocko-r219-dead.sock',NO_COLOR='1')
|
|
env.pop('MOSAIC_GITEA_CREDENTIAL_FILE',None);env.pop('MOSAIC_LIVE_PROVIDER',None)
|
|
log=OUT/(label+'.tap');start=stamp();begin=time.monotonic()
|
|
cmd=shlex.join(['timeout','-k','10','300',*args])+' | tee '+shlex.quote(str(log))
|
|
child=subprocess.Popen(['bash','-o','pipefail','-c',cmd],cwd=root,env=env,stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT,start_new_session=True)
|
|
try:rc=child.wait(timeout=315)
|
|
except subprocess.TimeoutExpired:
|
|
os.killpg(child.pid,signal.SIGKILL);child.wait();rc=124
|
|
finally:
|
|
try:os.killpg(child.pid,signal.SIGTERM)
|
|
except ProcessLookupError:pass
|
|
text=log.read_text(errors='replace');counts={k:int(m[-1]) if (m:=re.findall(r'^# '+k+r' (\d+)\s*$',text,re.M)) else None for k in ['tests','pass','fail','cancelled','skipped']}
|
|
row=dict(label=label,start=start,end=stamp(),seconds=round(time.monotonic()-begin,3),exit=rc,counts=counts,skips=[x for x in text.splitlines() if re.search(r'^skip\b|# SKIP\b',x,re.I)],log=str(log.relative_to(ROOT)))
|
|
with (OUT/'results.jsonl').open('a') as f:f.write(json.dumps(row)+'\n')
|
|
print(json.dumps(row),flush=True)
|
|
assert rc not in (124,137,-9) and 'SyntaxError:' not in text, 'timeout/syntax '+label
|
|
return row,text
|
|
|
|
def green(label,file):
|
|
verify();r,t=execute(label,ROOT,file)
|
|
assert r['exit']==0 and r['counts']['fail']==0 and r['counts']['cancelled']==0 and not re.search(r'^\s*not ok\b',t,re.M),'unexpected red '+label
|
|
|
|
verify();(OUT/'head.json').write_text(json.dumps(dict(head=HEAD,red=OLD,manifest=hashlib.sha256((P/'candidate-manifest.sha256').read_bytes()).hexdigest(),start=stamp())))
|
|
pattern='sage-1908: once the agent of an applied grant is a creative role'
|
|
r,t=execute('red-grant',RED,'packages/bus/tests/grant-executor.test.mjs',pattern)
|
|
assert r['exit']!=0 and r['counts']['fail']==1 and "code: 'thread-required'" in t and 'bindLaunch' in t,'wrong grant red'
|
|
verify();r,t=execute('red-pin',RED,'packages/bus/tests/project-runtime.test.mjs','Broker keeps the sandbox client import closure')
|
|
assert r['exit']!=0 and r['counts']['fail']==1 and 'ERR_ASSERTION' in t and 'THREAD_DEFINITION' in t,'wrong pin red'
|
|
for name in ['grant-executor','project-runtime','threads']:green('green-'+name,'packages/bus/tests/'+name+'.test.mjs')
|
|
verify();s=next(x for x in json.loads((P/'mutants.json').read_text()) if x['id']=='T24');path=ROOT/s['file'];saved=path.read_bytes()
|
|
try:
|
|
text=path.read_text();assert text.count(s['old'])==1;path.write_text(text.replace(s['old'],s['new'],1))
|
|
r,t=execute('T24',ROOT,s['test'],s['pattern'])
|
|
assert r['exit']!=0 and r['counts']['fail']==1 and 'ERR_ASSERTION' in t and re.search(r'^\s*not ok \d+ - '+re.escape(pattern),t,re.M),'T24 invalid or survivor'
|
|
(OUT/'T24-receipt.txt').write_text(t)
|
|
finally:path.write_bytes(saved)
|
|
verify();(OUT/'restored.json').write_text(json.dumps(dict(paths=16,drift=[],head=HEAD,end=stamp())))
|
|
print('SHORT_RUN_GREEN',stamp(),flush=True)
|