tricu

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

io_v2_zig_core.py (6203B)


      1 #!/usr/bin/env python3
      2 """Actual source core/handler parity using the PRIVATE Zig core probe, not native IO."""
      3 import argparse
      4 import hashlib
      5 import json
      6 import subprocess
      7 from pathlib import Path
      8 from source_order import Runner
      9 from io_v2_tasks import core_cases
     10 from process_rss import run_guarded
     11 from http_headers import number, result, tree_list
     12 from stable_bundle import byte_tree
     13 import time
     14 
     15 ROOT = Path(__file__).resolve().parent.parent
     16 
     17 def main():
     18     parser = argparse.ArgumentParser(description=__doc__)
     19     parser.add_argument('tricu', type=Path)
     20     parser.add_argument('probe', type=Path)
     21     parser.add_argument('--directory', type=Path, required=True)
     22     args = parser.parse_args()
     23     d = args.directory.resolve(); d.mkdir(parents=True, exist_ok=False)
     24     r = Runner(args.tricu, d)
     25     probe = args.probe.resolve()
     26     source = ROOT/'test/io-v2/tasks.tri'
     27     bundle = d/'tasks.arboricx'
     28     r.run('compile', ['compile', '--file', source, '--store', r.store, '--output', bundle])
     29     pin = r.imported(bundle, 'import')
     30     checks = []
     31     for name, expected in core_cases().items():
     32         flags = ['--io']; argv = []
     33         if name == 'lazyLabels':
     34             (d/'zero.tree').write_bytes(b'\0')
     35             flags += ['--arg-tree-file', d/'zero.tree']; argv = ['0']
     36         assert r.invoke('haskell-'+name, pin, name, flags) == expected, ('haskell', name)
     37         process = subprocess.run([str(probe), str(bundle), name, *argv], capture_output=True, timeout=60)
     38         (d/(name+'.stdout')).write_bytes(process.stdout)
     39         (d/(name+'.stderr')).write_bytes(process.stderr)
     40         assert process.returncode == 0, (name, process.returncode, process.stderr)
     41         assert process.stdout == ''.join(map(str, expected)).encode()+b'\n', name
     42         checks.append(name)
     43     controls_source = ROOT/'test/io-v2/core-controls.tri'
     44     controls_bundle = d/'controls.arboricx'
     45     r.run('compile-controls', ['compile', '--file', controls_source, '--store', r.store, '--output', controls_bundle])
     46     controls_pin = r.imported(controls_bundle, 'import-controls')
     47     def text(s): return byte_tree(s.encode())
     48     def problem(category, operation, detail=''):
     49         return result(False, tree_list([text(category), text(operation), text(detail), text('none')]))
     50     controls = {
     51         'cancelChild': (tree_list([text('cancelled'), text('stop'), b'\0']), False),
     52         'currentScopes': (number(1), False),
     53         'badFlags': (problem('invalid-argument', 'core/spawn'), True),
     54         'badTransfer': (problem('invalid-argument', 'core/spawn'), True),
     55         'discardedTicket': (problem('stale-task', 'core/join'), False),
     56         'selfCycle': (number(42), False),
     57         'pureDomainError': (result(False, text('ordinary')), False),
     58         'unknownWithPoison': (problem('unsupported', 'future/call', 'group revision 3'), True),
     59     }
     60     for name, (expected, seeded) in controls.items():
     61         flags = ['--io'] + (['--arg-tree-file', d/'zero.tree'] if seeded else [])
     62         assert r.invoke('haskell-'+name, controls_pin, name, flags) == expected, ('haskell', name)
     63         p = subprocess.run([str(probe), str(controls_bundle), name] + (['0'] if seeded else []), capture_output=True, timeout=60)
     64         (d/(name+'.stderr')).write_bytes(p.stderr)
     65         assert p.returncode == 0 and p.stdout == ''.join(map(str, expected)).encode()+b'\n', (name, p.returncode, p.stderr, p.stdout)
     66         checks.append(name)
     67     for name, seeded in [('selfCycleWrong', False), ('rootFailure', True), ('rootCancelled', True), ('malformedBind', False)]:
     68         flags = ['--io'] + (['--arg-tree-file', d/'zero.tree'] if seeded else [])
     69         try:
     70             r.invoke('haskell-'+name, controls_pin, name, flags)
     71         except subprocess.CalledProcessError as error:
     72             assert 'IO v2 task '+('cancelled' if name == 'rootCancelled' else 'failed') in error.output
     73         else:
     74             raise AssertionError(('Haskell negative succeeded', name))
     75         p = subprocess.run([str(probe), str(controls_bundle), name] + (['0'] if seeded else []), capture_output=True, timeout=60)
     76         assert p.returncode == 1 and p.stdout == b'' and b'not forced' in p.stderr, (name, p.returncode, p.stderr)
     77         checks.append(name+'-negative')
     78     p = subprocess.run([str(probe), str(controls_bundle), 'legacyEnvelope', '0'], capture_output=True, timeout=10)
     79     assert p.returncode != 0 and p.stdout == b'' and b'UnsupportedVersion' in p.stderr, p.stderr
     80     checks.append('v1-not-retried')
     81     retention_source = ROOT/'test/io-v2/core-retention.tri'
     82     retention_bundle = d/'retention.arboricx'
     83     r.run('compile-retention', ['compile', '--file', retention_source, '--store', r.store, '--output', retention_bundle])
     84     retention_pin = r.imported(retention_bundle, 'import-retention')
     85     retention = []
     86     for name in ('joined', 'discarded'):
     87         for count in (16, 128, 512):
     88             label = f'{name}-{count}'
     89             argument = d/(label+'.tree'); argument.write_bytes(number(count))
     90             assert r.invoke('haskell-retention-'+label, retention_pin, name, ['--io', '--arg-tree-file', argument]) == b'\0'
     91             command = [str(probe), str(retention_bundle), name, str(count)]
     92             start = time.monotonic()
     93             output, peak = run_guarded(command, memory_mib=128, seconds=180)
     94             (d/('zig-retention-'+label+'.log')).write_text(output)
     95             assert output == '0\n', (label, output)
     96             retention.append(dict(name=name, count=count, peak_kib=peak, seconds=time.monotonic()-start, command=command))
     97     paths = [controls_source, retention_source, source, probe, ROOT/'ext/zig/src/io_v2_core.zig', ROOT/'ext/zig/src/io_v2_tasks.zig', ROOT/'ext/zig/src/io_v2_resources.zig', ROOT/'ext/zig/src/io_v2_protocol.zig', ROOT/'test/io_v2_tasks.py']
     98     (d/'report.json').write_text(json.dumps({'checks': checks, 'scope': 'private-core-only-no-OS-facilities', 'retention': retention, 'sources': {str(p): hashlib.sha256(p.read_bytes()).hexdigest() for p in paths}, 'haskell_records': r.records}, indent=2)+'\n')
     99     print(f'PASS {len(checks)} actual source core/handler controls on Haskell and private Zig core')
    100 
    101 if __name__ == '__main__': main()