okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
f479db5
main
1"""Output retention invariants the daemon cannot observe through a cell result. 2 3A capture keeps the first RETAIN bytes and the last PREVIEW bytes of what was 4written, as bytes: a pipe chunk that splits a UTF-8 character must survive, 5the tail must equal the true end of the stream whichever path wrote it, and 6the memory held must stay within the two caps however much flows through. 7""" 8 9from pathlib import Path 10import sys 11import tempfile 12import tracemalloc 13from typing import cast 14import unittest 15 16sys .path .insert (0 ,str (Path (__file__ ).resolve ().parents [2 ]/ "priv" / "python" )) 17import albedo_state # noqa: E402 18from albedo_capture import PREVIEW ,RETAIN ,Capture # noqa: E402 19 20 21def stream_of (capture :Capture ,pieces )-> bytes : 22whole = bytearray () 23for piece in pieces : 24if isinstance (piece ,str ): 25capture .write (piece ) 26whole += piece .encode ("utf-8" ,errors = "replace" ) 27else : 28capture .write_bytes (piece ) 29whole += piece 30return bytes (whole ) 31 32 33class CaptureTest (unittest .TestCase ): 34def test_a_character_split_across_pipe_chunks_is_kept_whole (self ): 35capture = Capture ("job" ,"job" ) 36text = "héllo wörld — ✓\n" .encode () 37for cut in range (1 ,len (text )): 38capture .write_bytes (text [:cut ]) 39capture .write_bytes (text [cut :]) 40self .assertEqual (capture .read (0 ,RETAIN ),text .decode ()* (len (text )- 1 )) 41self .assertNotIn ("\ufffd" ,capture .tail ().decode ()) 42 43def test_both_write_paths_agree_on_what_is_kept (self ): 44for pieces in ( 45 ["x" * (RETAIN + 3 * PREVIEW )],# one ASCII print past every cap 46 ["x" * 10 ,"y" * (RETAIN + PREVIEW + 1 ),"tail" ], 47 ["ü" * (RETAIN + 10 )],# two bytes per character: the full encode 48 [b"\xff" * 100 ,"ascii" * 100 ,b"\xe2\x9c\x93" * (RETAIN // 3 )], 49 ["short" ,b"bytes" ], 50 ): 51with self .subTest (pieces = [len (p )for p in pieces ]): 52capture = Capture ("c" ) 53whole = stream_of (capture ,pieces ) 54self .assertEqual (capture .seen ,len (whole )) 55self .assertEqual (bytes (capture .data ),whole [:RETAIN ]) 56self .assertEqual (capture .tail (),whole [- PREVIEW :]) 57self .assertEqual (capture .tail (16 ),whole [- 16 :]) 58self .assertEqual (capture .tail (0 ),b"" ) 59 60def test_retained_bytes_stay_within_the_two_caps (self ): 61for label ,pieces in ( 62 ("pipe chunks" , [bytes (range (256 ))* 1000 ]* 40 ), 63 ("small prints" , ["some line of output\n" ]* 300_000 ), 64 ("one print" , ["x" * (3 * RETAIN )]), 65 ): 66with self .subTest (label ): 67capture = Capture ("c" ) 68whole = stream_of (capture ,pieces ) 69self .assertEqual (capture .seen ,len (whole )) 70self .assertEqual (len (capture .data ),RETAIN ) 71# bytearray growth slack is bounded; the buffers themselves are capped. 72held = sys .getsizeof (capture .data )+ sys .getsizeof (capture ._tail ) 73self .assertLess (held ,RETAIN + PREVIEW + PREVIEW // 4 ) 74 75def test_a_tail_buffer_exists_only_once_the_start_is_full (self ): 76capture = Capture ("c" ) 77capture .write ("a" * (RETAIN - 1 )) 78self .assertIsNone (capture ._tail ) 79self .assertEqual (capture .tail (4 ),b"aaaa" ) 80capture .write ("bb" ) 81self .assertIsNotNone (capture ._tail ) 82self .assertEqual (capture .tail (4 ),b"aabb" ) 83self .assertEqual (len (capture .data ),RETAIN ) 84 85def test_a_huge_ascii_print_is_not_encoded_whole (self ): 86capture = Capture ("c" ) 87text = "z" * (64 * 1024 * 1024 ) 88tracemalloc .start () 89try : 90capture .write (text ) 91_ ,peak = tracemalloc .get_traced_memory () 92finally : 93tracemalloc .stop () 94self .assertEqual (capture .seen ,len (text )) 95# The transient is a few retained-size pieces, not the 64 MiB text encoded. 96self .assertLess (peak ,4 * RETAIN ) 97 98 99class SnapshotBoundTest (unittest .TestCase ): 100def test_an_oversized_value_costs_the_cap_not_its_size (self ): 101namespace :dict [str ,object ]= {"big" :list (range (4_000_000 )),"small" : [1 ]} 102target = Path (self .enterContext (tempfile .TemporaryDirectory ())) 103tracemalloc .start () 104try : 105state = albedo_state .save_state (str (target / "state" ),namespace , {},set ()) 106_ ,peak = tracemalloc .get_traced_memory () 107finally : 108tracemalloc .stop () 109skipped = cast (list [dict [str ,str ]],state ["skipped" ]) 110self .assertEqual (state ["saved" ], ["small" ]) 111self .assertEqual ([item ["name" ]for item in skipped ], ["big" ]) 112self .assertIn ("per-variable cap" ,skipped [0 ]["reason" ]) 113self .assertLess (peak ,3 * albedo_state .STATE_MAX_VALUE ) 114 115 116if __name__ == "__main__" : 117unittest .main ()