shared_library_smoke.py (4525B)
1 #!/usr/bin/env python3 2 """Compile and audit one application, then compare CLI/C-ABI complete results. 3 4 The independent imports/recursive-list/invoice oracles also serve compiler 5 post-acceptance smokes. This uses the packaged compiler and creates no compiler 6 generation or acceptance checkpoint. 7 """ 8 import argparse 9 import json 10 import os 11 from pathlib import Path 12 import re 13 import sys 14 from bootstrap_smoke import LIBRARY, PROGRAM, smoke_cases, sha 15 from collections_batch import ProbeRunner, audit_workspace 16 from native_library_migration import digest 17 from process_rss import run_guarded 18 19 ROOT = Path(__file__).resolve().parent.parent 20 21 22 def main(): 23 parser = argparse.ArgumentParser(description=__doc__) 24 parser.add_argument('--tricu', type=Path, required=True) 25 parser.add_argument('--library', type=Path, required=True) 26 parser.add_argument('--directory', type=Path, required=True) 27 args = parser.parse_args() 28 root = args.directory.resolve() 29 root.mkdir(parents=True, exist_ok=False) 30 workspace = root / 'workspace' 31 workspace.mkdir() 32 (workspace / 'tricu.workspace').write_text('tricu.workspace.v1\n') 33 for alias, relative in {'base':'lib/base.tri', 'bytes':'lib/bytes.tri', 34 'conversions':'lib/conversions.tri', 'prelude':'lib/prelude.tri', 35 'native_math':'lib/math/native.tri', 36 'shapes':'demos/source-patterns/patterns.tri'}.items(): 37 (workspace / (alias + '.tri')).write_bytes((ROOT / relative).read_bytes()) 38 (workspace / 'recursive.tri').write_text(LIBRARY) 39 (workspace / 'program.tri').write_text(PROGRAM) 40 # Per-process test allocator policy; no library initialization changes. 41 os.environ['MALLOC_ARENA_MAX'] = '2' 42 runner = ProbeRunner(args.tricu, root, 300) 43 report = dict(complete=False, compiler_sha256=sha(ROOT / 'bootstrap/build-stable.arboricx'), 44 runtime_sha256=sha(args.library), observer_sha256=sha(ROOT / 'test/haskell_observe.py'), 45 binding_sha256=sha(ROOT / 'ext/haskell/python/tricu.py'), cases=[], 46 scope='packaged compiler application; no compiler generation') 47 try: 48 tool = runner.imported(ROOT / 'bootstrap/build-stable.arboricx', 'compiler') 49 bundle = root / 'program.arboricx' 50 runner.run('compile', ['compile', '--file', workspace/'program.tri', 51 '--toolchain', tool, '--toolchain-io-version', '2', '--tool-store', runner.store, 52 '--store', runner.store, '--output', bundle, '--compile-timeout', '180'], 210) 53 manifest_bytes = (runner.store / 'objects' / tool[:3] / tool).read_bytes() 54 assert digest('arboricx.module-manifest.v1', manifest_bytes) == tool 55 compiler = next(row.split('\t')[3] for row in manifest_bytes.decode().splitlines()[1:] 56 if row.split('\t')[1] == 'sourceBuildGraph') 57 report['modules'] = audit_workspace(workspace, runner.store, compiler) 58 imported = runner.run('import-program', ['import', '--file', bundle, '--store', runner.store]) 59 manifest = re.search(r'Created module alias .* -> ([0-9a-f]{64})', imported)[1] 60 assert manifest == report['modules']['program']['manifest'] 61 for i, (export, argument, expected) in enumerate(smoke_cases()): 62 path, output = root / f'{i}.input.tree', root / f'{i}.output.tree' 63 path.write_bytes(argument) 64 actual = runner.invoke(str(i), manifest, export, ['--arg-tree-file', path]) 65 assert actual == expected, (export, i, 'CLI') 66 reply, peak = run_guarded([sys.executable, str(ROOT / 'test/haskell_observe.py'), 67 '--library', str(args.library), '--bundle', str(bundle), '--export', export, 68 '--argument', str(path), '--output', str(output)], memory_mib=512, seconds=65) 69 (root / f'{i}.log').write_text(reply) 70 assert output.read_bytes() == expected, (export, i, 'C ABI') 71 report['cases'].append(dict(export=export, input_sha256=sha(path), 72 output_sha256=sha(output), peak_kib=peak)) 73 assert output.read_bytes() != b'\0', 'wrong-output control' 74 report.update(complete=True, bundle_sha256=sha(bundle), wrong_output_rejected=True) 75 print('PASS: 12 independent complete results through CLI and C ABI') 76 finally: 77 (root / 'report.json').write_text(json.dumps(report, indent=2) + '\n') 78 79 80 if __name__ == '__main__': 81 main()