diff options
| author | eunhhu <[email protected]> | 2026-10-19 03:02:51 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-10-19 03:02:51 +0100 |
| commit | 5842b26e8353a38192afb1ebe4c08809da48dbf4 (patch) | |
| tree | a4bf3d5e8ad8194b37d1beb1fa3639a6fd12c279 /tests/check.py | |
| parent | 85a35189c6588903ffc287837c9005ef3063e056 (diff) | |
| download | pure-5842b26e8353a38192afb1ebe4c08809da48dbf4.tar.gz pure-5842b26e8353a38192afb1ebe4c08809da48dbf4.zip | |
140's 9, HTTP/1.1 requests a packet at a time (RFC 9112), written in aup with no new opcode (aup's examples/http.aup: each packet an event, its bytes added to what the last left, every request they complete read, h11's grammar): 200 streams (132,623 bytes, 578 requests: methods, targets, HTTP/1.1 and a last 1.0, mixed-case names, spaces around values, Content-Length and chunked bodies with extensions and trailers, some ending in part of a request) fed whole, at random boundaries and a byte at a time (the 50 under 400 bytes), the requests read h11's on every cut and the bytes left those after them, the three paths' outputs the same bytes; 200 damaged streams fed whole as http_requests.py (the Python reference) reads them, 35 refused by both and 165 the same; module_specs in make check: 80 streams and their reading (tests/specs/http, no h11 at check time) whole on the three paths and cut 88 ways; bars: written, three workarounds (the bytes left in a list of one: bytes are no state; names and codings compared as text: bytes have no ==; field lines returned in a record: a fn returns no bare list), 159 lines against Python's 79, 278 ns a byte against the same algorithm in C 3.27 (85x), pure Python 67 (its bytes methods are C: Pure 4.1x slower), h11 284; 140's decision point after 027: bytes alone as a state (inflate, HTTP) and bytes' == (DNS, HTTP) now each met by two written specs, so the two-spec rule lets them into the core (their design not begun); a view calling a block fn met by one (DNS); aup's three its compiler's; CHECKPOINT's direction row
Diffstat (limited to 'tests/check.py')
| -rw-r--r-- | tests/check.py | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/tests/check.py b/tests/check.py index b78b184..b3b4750 100644 --- a/tests/check.py +++ b/tests/check.py @@ -1733,7 +1733,9 @@ def module_specs(aup, pure, work): a tree (its examples/json_tree.aup); raw deflate streams zlib made inflated by its examples/inflate.aup to the original's bytes, cut ones refused; DNS messages dnspython made (tests/specs/dns) read by its examples/dns.aup and - written back by its view to the same records, cut ones refused.""" + written back by its view to the same records, cut ones refused; HTTP/1.1 + request streams (tests/specs/http) read by its examples/http.aup a packet + at a time, cut anywhere, to the same requests.""" import hashlib import os import random @@ -1896,6 +1898,41 @@ def module_specs(aup, pure, work): cut = [wire[:len(wire) // 2] for wire in wires[::9]] assert all(json.loads(line)['fault'] != 'none' for line in read(cut, {}).splitlines()), 'dns cut' runs['dns'] = {'messages': len(wires), 'records': sum(len(state['states']['records']) for state in first), 'cut': len(cut)} + # HTTP/1.1 requests read a packet at a time (its examples/http.aup): streams and their reading (tests/specs/http, h11's + # in the research check), each stream fed whole, at random boundaries and a byte at a time if it is short, each packet + # an event: the same requests and bytes left on every cut, and on the three paths fed whole. + program = work / 'http.pmod' + compile_module(aup, EXAMPLES / 'http.aup', program) + given, made = (pure / 'tests/specs/http/streams.bin').read_bytes(), [] + while given: + made.append(given[4:4 + int.from_bytes(given[:4], 'big')]) + given = given[4 + len(made[-1]):] + reading = json.loads((pure / 'tests/specs/http/read.json').read_text()) + + def fed(packets, env): + lines = '' + for n, packet in enumerate(packets): + (work / f'{n}.packet').write_bytes(packet) + lines += f'message packet @{work / f"{n}.packet"}\n' + out = subprocess.run([str(pure / 'build/pure-run'), str(program)], input=lines, capture_output=True, text=True, + timeout=120, env=dict(os.environ, **env)).stdout.splitlines() + assert all(json.loads(line)['fault'] == 'none' for line in out), 'http' + s = json.loads(out[-1])['states'] + pairs = lambda fs: [[f['name'], f['value']] for f in fs] + return out[-1], {'requests': [[r['method'], r['target'], r['minor'], pairs(r['fields']), r['body'], pairs(r['trailers'])] + for r in s['requests']], 'left': s['pending'][0]['data'] if s['pending'] else ''} + + cuts = 0 + for stream, want in zip(made, reading): + whole = {name: fed([stream], env) for name, env in + (('batches', {'PURE_JIT': '0'}), ('rounds', {'PURE_JIT': '0', 'PURE_BATCH': '0'}), ('all', {'PURE_JIT': 'all'}))} + assert whole['rounds'][0] == whole['all'][0] == whole['batches'][0] and whole['batches'][1] == want, 'http' + at = sorted(chooser.sample(range(1, len(stream)), min(len(stream) - 1, 6))) + for packets in [[stream[a:b] for a, b in zip([0] + at, at + [len(stream)])]] + \ + ([[stream[i:i + 1] for i in range(len(stream))]] if len(stream) < 300 else []): + assert fed(packets, {})[1] == want, ('http cut', len(packets)) + cuts += 1 + runs['http'] = {'streams': len(made), 'requests': sum(len(w['requests']) for w in reading), 'cuts': cuts} return runs |
