tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

io_v2_zig_publication.py (5486B)


      1 #!/usr/bin/env python3
      2 """Real source-owned publication policy on private Zig, with Haskell comparisons."""
      3 import argparse
      4 import hashlib
      5 import json
      6 import subprocess
      7 from pathlib import Path
      8 from source_order import Runner, field
      9 from http_headers import result, tree_list, number
     10 from process_rss import run_guarded
     11 ROOT = Path(__file__).resolve().parent.parent
     12 
     13 def text(s): return tree_list([number(ord(c)) for c in str(s)])
     14 def main():
     15     p=argparse.ArgumentParser(description=__doc__)
     16     p.add_argument('tricu',type=Path);p.add_argument('probe',type=Path);p.add_argument('--directory',type=Path,required=True)
     17     args=p.parse_args();d=args.directory.resolve();d.mkdir(parents=True,exist_ok=False)
     18     r=Runner(args.tricu,d);bundle=d/'publication.arboricx'
     19     r.run('compile',['compile','--file',ROOT/'demos/io-v2/publish.tri','--store',r.store,'--output',bundle]);pin=r.imported(bundle,'import')
     20     checks=[]
     21     def invoke(label,name,values,expected,compare=False):
     22         command=[str(args.probe.resolve()),str(bundle),name,*[str(v) if isinstance(v,int) else 'text:'+str(v) for v in values]]
     23         output,peak=run_guarded(command,memory_mib=128,seconds=180)
     24         (d/(label+'.log')).write_text(output)
     25         actual=bytes(map(int,output.strip()))
     26         if expected is not None: assert actual==expected,(label,actual,expected)
     27         if compare:
     28             flags=['--io']
     29             for i,v in enumerate(values):
     30                 arg=d/f'{label}-{i}.tree';arg.write_bytes(number(v) if isinstance(v,int) else text(v));flags+=['--arg-tree-file',arg]
     31             assert r.invoke(label+'-haskell',pin,name,flags)==actual,label
     32         checks.append(dict(label=label,peak_kib=peak))
     33         return actual
     34     for size in (0,1,4095,4096,4097,65536,1048576):
     35         source=d/f'input-{size}';body=(bytes(range(256))*((size+255)//256))[:size];source.write_bytes(body)
     36         target=d/f'objects-{size}';target.mkdir();digest=hashlib.sha256(body).hexdigest()
     37         for state in ('new','existing'):
     38             invoke(f'{state}-{size}','publish',[source,target,size],result(True,text(digest)),size==4097)
     39             assert (target/digest).read_bytes()==body
     40             assert (target/digest).stat().st_mode&0o077==0
     41             assert sorted(p.name for p in target.iterdir())==[digest]
     42     source=d/'source-λ-树';source.write_bytes(b'\0\xffbinary');target=d/'objects-λ-树';target.mkdir()
     43     digest=hashlib.sha256(source.read_bytes()).hexdigest()
     44     invoke('unicode','publish',[source,target,8],result(True,text(digest)),True)
     45     assert (target/digest).read_bytes()==source.read_bytes()
     46     source=d/'negative-input';source.write_bytes(b'abc');digest=hashlib.sha256(b'abc').hexdigest()
     47     for label,count,winner,message in [('short',4,None,'Incomplete artifact stream'),('excess',2,None,'Artifact exceeds declared length'),('bad-winner',3,b'xyz','Existing artifact digest mismatch'),('short-winner',3,b'ab','Existing artifact length mismatch'),('long-winner',3,b'abcd','Existing artifact length mismatch')]:
     48         target=d/label;target.mkdir()
     49         if winner is not None:(target/digest).write_bytes(winner)
     50         invoke(label,'publish',[source,target,count],result(False,text(message)),True)
     51         assert sorted(p.name for p in target.iterdir())==([] if winner is None else [digest])
     52         if winner is not None:assert (target/digest).read_bytes()==winner
     53     for name,message in [('earlySuccess','Incomplete artifact stream'),('ignoresWriteFailure','Artifact exceeds declared length'),('emptyChunk','Empty artifact chunk'),('overrideWrite','Incomplete artifact stream'),('failedAfterFull','Producer failed'),('rejectedDestination','Destination rejected')]:
     54         target=d/name;target.mkdir();invoke(name,name,[target],result(False,text(message)),True);assert list(target.iterdir())==[]
     55     for name,problem in [
     56         ('malformedDestination',tree_list([text('invalid-response'),text('artifact-stream'),text('destination'),text('Expected destination Result'),b'\0'])),
     57         ('badDigest',tree_list([text('invalid-response'),text('artifact-stream'),text('digest'),text('Invalid digest reply'),b'\0'])),
     58         *[(n,tree_list([text('producer-boundary'),text('artifact-stream'),text('publish'),text('Producer must be sequential'),tree_list([text('outer'),text('inner')])])) for n in ('nestedProducer','forkedProducer')]]:
     59         target=d/name;target.mkdir();invoke(name,name,[target],tree_list([text('failed'),problem,b'\0']),True);assert list(target.iterdir())==[]
     60     target=d/'invalidChunk';target.mkdir();actual=invoke('invalidChunk','invalidChunk',[target],None,True)
     61     assert field(actual,0)==b'\0' and field(actual,1,0,0)==text('write-all') and field(actual,1,0,1,0)==number(0)
     62     assert field(actual,1,0,1,1,0,0)==text('invalid-argument');assert list(target.iterdir())==[]
     63     target=d/'cancelled';target.mkdir()
     64     process=subprocess.run([str(args.probe.resolve()),str(bundle),'cancelled','text:'+str(target)],capture_output=True,timeout=60)
     65     assert process.returncode==1 and b'cancelled (reason not forced)' in process.stderr
     66     assert list(target.iterdir())==[] and not (d/'escape').exists()
     67     checks.append(dict(label='cancelled-no-private-names'))
     68     (d/'report.json').write_text(json.dumps(dict(checks=checks,haskell=r.records,probe_sha256=hashlib.sha256(args.probe.read_bytes()).hexdigest()),indent=2)+'\n')
     69     print(f'PASS {len(checks)} private Zig source publication/policy controls')
     70 if __name__=='__main__':main()