okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
6e82811
main
1"""Saved Python state expires with its idle session, and only then. 2 3Expiry deletes files the daemon cannot recreate, so the bugs worth catching are 4the ones that delete too much (a live kernel's file) or nothing at all (a type 5mismatch once made the sweep a no-op), and only the real daemon exercises both. 6""" 7 8import os 9import time 10import unittest 11 12from harness import latest_user ,wait_until 13from harness import Albedo ,Provider ,exclusive ,python ,text 14 15IDLE_SECONDS = 1 16EXPIRY_SECONDS = 3 17LOST = ( 18"<system-note>The python kernel got reset and all variables are lost</system-note>" 19) 20 21 22# exclusive: changes daemon idle/expiry sweep timing and tests startup cleanup 23@exclusive 24class StateExpiryTests (unittest .TestCase ): 25def setUp (self ): 26def script (request ): 27if request ["input" ][- 1 ].get ("role" )== "user" : 28prompt = latest_user (request ) 29if prompt .startswith ("remember" ): 30return python ("answer = 7" ) 31if prompt .startswith ("pin" ): 32return python ("job = run('sleep', '25')\nanswer = 8" ) 33return text ("ok" ) 34 35self .provider = Provider (script ) 36self .addCleanup (self .provider .close ) 37self .app = Albedo ( 38self .provider , 39protocol = "responses" , 40prepare = lambda app :app .env .update ( 41ALBEDO_IDLE_SECONDS = str (IDLE_SECONDS ), 42ALBEDO_STATE_EXPIRY_SECONDS = str (EXPIRY_SECONDS ), 43 ), 44 ) 45self .app .__enter__ () 46self .addCleanup (self .app .__exit__ ,None ,None ,None ) 47 48def state (self ,session ): 49return self .app .home / "kernels" / f" { session } .state" 50 51def turn (self ,session ,prompt ): 52self .app .prompt (session ,prompt ).close () 53self .app .idle (session ) 54return latest_user (self .provider .requests [- 1 ]["request" ]) 55 56def test_an_idle_session_loses_its_state_and_a_live_kernel_keeps_it (self ): 57idle ,live = self .app .session (),self .app .session () 58for session in (idle ,live ): 59self .turn (session ,"remember this" ) 60wait_until ( 61lambda :self .state (idle ).exists ()and self .state (live ).exists (), 6215 , 63"idle kernels were never saved" , 64 ) 65# a background job pins this session's kernel, so it is not idle 66self .turn (live ,"pin this" ) 67wait_until ( 68lambda :not self .state (idle ).exists (),30 ,"an idle session kept its state" 69 ) 70self .assertTrue (self .state (live ).exists (),"a live kernel lost its state" ) 71self .assertEqual (self .turn (idle ,"recall it" ),"recall it" + LOST ) 72 73def test_old_orphan_state_goes_at_startup_and_a_young_one_stays (self ): 74kernels = self .app .home / "kernels" 75kernels .mkdir (exist_ok = True ) 76old ,young = kernels / "orphan-old.state" ,kernels / "orphan-young.state" 77for path in (old ,young ): 78path .write_bytes (b"x" ) 79two_days_ago = time .time ()- 2 * 86400 80os .utime (old , (two_days_ago ,two_days_ago )) 81self .app .restart () 82self .assertFalse (old .exists (),"an old orphan survived startup" ) 83self .assertTrue (young .exists (),"a young orphan was deleted" ) 84 85 86# exclusive: changes daemon retention/idle timing and restarts the daemon 87@exclusive 88class StateRetentionTests (unittest .TestCase ): 89def setUp (self ): 90self .provider = Provider ( 91lambda request : ( 92python ("answer = 7" ) 93if request ["input" ][- 1 ].get ("role" )== "user" 94else text ("ok" ) 95 ) 96 ) 97self .addCleanup (self .provider .close ) 98self .app = Albedo ( 99self .provider , 100protocol = "responses" , 101prepare = lambda app :app .env .update ( 102ALBEDO_IDLE_SECONDS = str (IDLE_SECONDS ), 103ALBEDO_STATE_EXPIRY_SECONDS = str (10 * 86400 ), 104 ), 105 ) 106self .app .__enter__ () 107self .addCleanup (self .app .__exit__ ,None ,None ,None ) 108 109def test_saved_pastes_older_than_the_retention_are_deleted (self ): 110folder = self .app .home / "pastes" / "some-session" 111folder .mkdir (parents = True ) 112old ,young = folder / "old-1.md" ,folder / "young-1.md" 113for path in (old ,young ): 114path .write_text ("pasted" ) 115eleven_days_ago = time .time ()- 11 * 86400 116os .utime (old , (eleven_days_ago ,eleven_days_ago )) 117self .app .restart () 118wait_until (lambda :not old .exists (),15 ,"an expired paste was kept" ) 119self .assertTrue (young .exists (),"a paste inside its retention was deleted" ) 120 121def test_a_session_inside_its_retention_keeps_an_old_file (self ): 122session = self .app .session () 123self .app .prompt (session ,"remember this" ).close () 124self .app .idle (session ) 125state = self .app .home / "kernels" / f" { session } .state" 126wait_until (state .exists ,15 ,"the idle kernel was never saved" ) 127two_days_ago = time .time ()- 2 * 86400 128os .utime (state , (two_days_ago ,two_days_ago )) 129self .app .restart () 130time .sleep (3 )# the first periodic sweep runs within a second of startup 131self .assertTrue (state .exists (),"a session inside its retention lost its state" )