@@ -333,6 +333,24 @@ async def test_destroy_sandbox_cancels_deferred_boot_task(tmp_path):
333333 assert sandbox ["sandbox_id" ] not in manager .pending_boot_tasks
334334
335335
336+ @pytest .mark .asyncio
337+ async def test_destroy_persistent_sandbox_removes_record (tmp_path ):
338+ manager , provider = _manager (tmp_path )
339+ created = await manager .create_sandbox (None , "session-a" , "generic" , "Named" )
340+ manager .update_sandbox_config (
341+ created ["sandbox_id" ],
342+ idle_timeout = None ,
343+ expires_at = None ,
344+ retention_policy = "persistent" ,
345+ )
346+
347+ destroyed = await manager .destroy_sandbox ("session-a" , created ["sandbox_id" ])
348+
349+ assert destroyed ["sandbox_id" ] == created ["sandbox_id" ]
350+ assert manager .registry .get_sandbox (created ["sandbox_id" ]) is None
351+ assert provider .destroyed [0 ][1 ] == created ["sandbox_id" ]
352+
353+
336354@pytest .mark .asyncio
337355async def test_create_sandbox_sets_current_sandbox_after_lease (tmp_path ):
338356 manager , _provider = _manager (tmp_path )
@@ -673,7 +691,7 @@ async def test_manager_does_not_revive_destroyed_persistent_sandbox(tmp_path):
673691
674692 await manager .destroy_sandbox ("session-a" , created ["sandbox_id" ])
675693
676- with pytest .raises (RuntimeError , match = "has been destroyed " ):
694+ with pytest .raises (RuntimeError , match = "not found " ):
677695 await manager .get_observer_booter_by_id (
678696 created ["sandbox_id" ],
679697 "dashboard" ,
@@ -923,6 +941,39 @@ async def test_manager_reconcile_on_startup_keeps_valid_persistent_records(
923941 assert len (provider .created ) == 0
924942
925943
944+ @pytest .mark .asyncio
945+ async def test_manager_restore_persistent_sandboxes_times_out_and_deletes_record (
946+ tmp_path ,
947+ ):
948+ provider = FailingReconnectProvider ()
949+ manager , _provider = _manager (tmp_path , provider )
950+ restore_started = asyncio .Event ()
951+
952+ async def slow_create_booter (context , session_id , sandbox_id , config ):
953+ restore_started .set ()
954+ await asyncio .sleep (1 )
955+ return await FakeProvider ().create_booter (context , session_id , sandbox_id , config )
956+
957+ provider .create_booter = slow_create_booter
958+ manager .registry .upsert_sandbox (
959+ sandbox_id = "generic-1" ,
960+ sandbox_name = "Persistent" ,
961+ provider = "generic" ,
962+ managed = True ,
963+ created_by_astrbot = True ,
964+ owner_user_id = "session-a" ,
965+ owner_session_id = "session-a" ,
966+ connect_info = {"name" : "Persistent" },
967+ status = "running" ,
968+ retention_policy = "persistent" ,
969+ )
970+
971+ await manager .restore_persistent_sandboxes (object (), per_sandbox_timeout = 0.01 )
972+
973+ assert restore_started .is_set ()
974+ assert manager .registry .get_sandbox ("generic-1" ) is None
975+
976+
926977def test_manager_reconcile_on_startup_drops_temporary_records (tmp_path ):
927978 manager , _provider = _manager (tmp_path )
928979 manager .registry .upsert_sandbox (
0 commit comments