bootstrap_smoke.py (5664B)
1 #!/usr/bin/env python3 2 """Small post-acceptance generation-two smoke; no fixture publication or matrix.""" 3 import argparse 4 import hashlib 5 import json 6 from pathlib import Path 7 import re 8 import time 9 10 from base_workloads import encode as n 11 from collections_batch import ProbeRunner, audit_workspace 12 from http_headers import pair, result, expect 13 from native_library_migration import digest 14 15 ROOT = Path(__file__).resolve().parent.parent 16 LIBRARY = '''!import prelude as B 17 !export copy 18 !export reverseLocal 19 copy [] = [] 20 copy [head | tail] = B.pair head (copy tail) 21 copy _ = [] 22 reverseLocal input = (let rec 23 walk [] reversed = reversed 24 walk [head | tail] reversed = walk tail (B.pair head reversed) 25 walk _ reversed = reversed 26 in walk input []) 27 ''' 28 PROGRAM = '''!import prelude as B 29 !import recursive as R 30 !import shapes as S 31 !export imports 32 !export copy 33 !export reverseLocal 34 !export invoice 35 imports input = [(S.first (B.pair 23 24)) (S.shape input)] 36 copy = R.copy 37 reverseLocal = R.reverseLocal 38 lineTotal (quantity, cents) = B.mul quantity cents 39 lineTotal _ = 0 40 invoice rows = (let total = B.foldl (sum row : B.add sum (lineTotal row)) 0 rows in 41 B.ok (B.pair total (B.showNumber total)) t) 42 ''' 43 44 45 def sha(path): 46 return hashlib.sha256(path.read_bytes()).hexdigest() 47 48 49 def smoke_cases(): 50 cases = [('imports', b'\0', n([23,0])), ('imports', b'\1\0', n([23,1])), 51 ('imports', b'\2\0\0', n([23,2]))] 52 for values in [[],[7],list(range(32))]: 53 cases += [('copy',n(values),n(values)),('reverseLocal',n(values),n(values[::-1]))] 54 for entries in [[],[(3,125),(2,49),(0,999),(1,1000)],[(9,9999),(11,12345)]]: 55 argument = b'\0' 56 for quantity,price in reversed(entries): 57 argument = pair(pair(n(quantity),n(price)),argument) 58 total = sum(q*p for q,p in entries) 59 cases.append(('invoice',argument,result(True,pair(n(total),n(list(str(total).encode())))))) 60 return cases 61 62 63 def main(): 64 p = argparse.ArgumentParser(description=__doc__) 65 p.add_argument('tricu', type=Path) 66 p.add_argument('--generation', type=Path, required=True) 67 p.add_argument('--acceptance', type=Path, required=True) 68 p.add_argument('--source-root', type=Path, required=True) 69 p.add_argument('--directory', type=Path, required=True) 70 args = p.parse_args() 71 accepted = json.loads(args.acceptance.read_text()) 72 generation = args.generation.resolve() 73 assert accepted['accepted'] and accepted['backend'] == 'stable' 74 assert generation == Path(accepted['generations'][1]).resolve() 75 artifact = generation/'build-stable.arboricx' 76 assert sha(artifact) == accepted['artifacts'][artifact.name] 77 assert sha(args.tricu) == accepted['inputs'][1]['runtime_sha256'] 78 root = args.directory.resolve(); root.mkdir(parents=True) 79 workspace = root/'workspace'; workspace.mkdir() 80 sources = {name:'lib/'+name+'.tri' for name in ['base','bytes','conversions','prelude']} 81 sources['native_math'] = 'lib/math/native.tri' 82 for alias, path in sources.items(): 83 source = args.source_root/path 84 assert sha(source) == accepted['inputs'][1]['sources'][alias] 85 (workspace/(alias+'.tri')).write_bytes(source.read_bytes()) 86 (workspace/'shapes.tri').write_bytes((args.source_root/'demos/source-patterns/patterns.tri').read_bytes()) 87 (workspace/'recursive.tri').write_text(LIBRARY) 88 (workspace/'program.tri').write_text(PROGRAM) 89 (root/'harness.py').write_bytes(Path(__file__).read_bytes()) 90 report = dict(complete=False, acceptance_sha256=sha(args.acceptance), 91 compiler_sha256=sha(artifact), runtime_sha256=sha(args.tricu), 92 harness_sha256=sha(Path(__file__)), cases=[]) 93 runner = ProbeRunner(args.tricu, root, 300) 94 try: 95 tool = runner.imported(artifact, 'generation-two') 96 bundle = root/'program.arboricx' 97 runner.run('compile', ['compile','--file',workspace/'program.tri', 98 '--toolchain',tool,'--tool-store',runner.store,'--store',runner.store, 99 '--output',bundle,'--compile-timeout','180'], 210) 100 raw = (runner.store/'objects'/tool[:3]/tool).read_bytes() 101 assert digest('arboricx.module-manifest.v1', raw) == tool 102 compiler = next(row.split('\t')[3] for row in raw.decode().splitlines()[1:] 103 if row.split('\t')[1] == 'sourceBuildGraph') 104 report['modules'] = audit_workspace(workspace, runner.store, compiler) 105 imported = runner.run('native-import', ['import','--file',bundle,'--store',runner.store]) 106 pin = re.search(r'Created module alias .* -> ([0-9a-f]{64})', imported)[1] 107 assert pin == report['modules']['program']['manifest'] 108 cases = smoke_cases() 109 for i,(export,argument,expected) in enumerate(cases): 110 path = root/'argument.tree'; path.write_bytes(argument) 111 actual = runner.invoke(str(i),pin,export,['--arg-tree-file',path]) 112 expect(actual,expected,export) 113 report['cases'].append(dict(export=export,input_sha256=hashlib.sha256(argument).hexdigest(), 114 output_sha256=hashlib.sha256(actual).hexdigest())) 115 assert actual != result(True, n(0)), 'wrong-output control' 116 report.update(complete=True, seconds=time.monotonic()-runner.started, 117 bundle_sha256=sha(bundle), wrong_output_rejected=True) 118 print(f'PASS: {len(cases)} complete results; native imports, top-level/local recursion, invoice totals/decimal text; {report["seconds"]:.2f}s') 119 finally: 120 (root/'report.json').write_text(json.dumps(report,indent=2)+'\n') 121 122 123 if __name__ == '__main__': 124 main()