okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
f6da61d
main
1// The readiness handshake makes ownership and confirmation races deterministic. 2// E2E cannot pause Go's apply call between helper capture and authorization. 3package storage 4 5import ( 6"albedo/cli/internal/daemon" 7"context" 8"errors" 9"os" 10"path/filepath" 11"strings" 12"testing" 13) 14 15func TestMaintenanceOwnershipAndRelease (t * testing.T ) { 16for _ ,ending := range []string {"success" ,"cancel" ,"helper killed" ,"input EOF" ,"replacement" ,"vacuum failure" ,"deletion failure" ,"no free pages" } { 17t .Run (ending ,func (t * testing.T ) { 18if ending == "deletion failure" && os .Geteuid ()== 0 { 19t .Skip ("root can unlink files in a directory without write permission" ) 20 } 21home := t .TempDir () 22directory := filepath .Join (home ,"candidates" ) 23if err := os .Mkdir (directory ,0700 );err != nil { 24t .Fatal (err ) 25 } 26path := filepath .Join (directory ,"candidate" ) 27if err := os .WriteFile (path , []byte ("data" ),0600 );err != nil { 28t .Fatal (err ) 29 } 30ctx ,cancel := context .WithCancel (t .Context ()) 31defer cancel () 32helper ,err := testService (home ).startMaintenance (ctx , []daemon.StorageFile {{Path :path ,Bytes :4 }}) 33if err != nil { 34t .Fatal (err ) 35 } 36defer helper .close () 37if other ,acquireErr := testService (home ).startMaintenance (t .Context (),nil );acquireErr == nil { 38other .close () 39t .Fatal ("second cleanup acquired ownership" ) 40 }else if ! strings .Contains (acquireErr .Error (),"storage is in use" ) { 41t .Fatal (acquireErr ) 42 } 43switch ending { 44case "success" : 45_ ,err = helper .apply (ctx ,false , daemon.StorageReport {}) 46case "cancel" : 47cancel () 48_ ,err = helper .apply (ctx ,false , daemon.StorageReport {}) 49if ! errors .Is (err ,context .Canceled ) { 50t .Fatalf ("lost cancellation: %v" ,err ) 51 } 52case "helper killed" : 53if err = helper .command .Process .Kill ();err != nil { 54t .Fatal (err ) 55 } 56_ ,err = helper .apply (ctx ,false , daemon.StorageReport {}) 57case "input EOF" : 58if err = helper .input .Close ();err != nil { 59t .Fatal (err ) 60 } 61err = helper .command .Wait () 62helper .waited = true 63case "replacement" : 64replacement := filepath .Join (home ,"replacement" ) 65if err = os .WriteFile (replacement , []byte ("else" ),0600 );err != nil { 66t .Fatal (err ) 67 } 68if err = os .Rename (replacement ,path );err != nil { 69t .Fatal (err ) 70 } 71_ ,err = helper .apply (ctx ,false , daemon.StorageReport {}) 72case "deletion failure" : 73if err = os .Chmod (directory ,0500 );err != nil { 74t .Fatal (err ) 75 } 76defer os .Chmod (directory ,0700 ) 77_ ,err = helper .apply (ctx ,false , daemon.StorageReport {}) 78case "vacuum failure" : 79_ ,err = helper .apply (ctx ,true , daemon.StorageReport {Database :4096 ,DB : daemon.StorageDatabase {FreePages :1 }}) 80case "no free pages" : 81var result CleanupResult 82result ,err = helper .apply (ctx ,true , daemon.StorageReport {Database :4096 }) 83if ! result .VacuumSkipped || result .Vacuumed { 84t .Fatalf ("unexpected vacuum result: %+v" ,result ) 85 } 86 } 87wantFailure := ending == "cancel" || ending == "helper killed" || ending == "replacement" || ending == "vacuum failure" || ending == "deletion failure" 88if (err != nil )!= wantFailure { 89t .Fatalf ("%s: %v" ,ending ,err ) 90 } 91helper .close () 92deleted := ending == "success" || ending == "vacuum failure" || ending == "no free pages" 93_ ,statErr := os .Lstat (path ) 94if os .IsNotExist (statErr )!= deleted { 95t .Fatalf ("unexpected candidate state: %v" ,statErr ) 96 } 97next ,err := testService (home ).startMaintenance (t .Context (),nil ) 98if err != nil { 99t .Fatalf ("ownership not released: %v" ,err ) 100 } 101next .close () 102 }) 103 } 104} 105 106func TestCleanupRequiresOwnershipBeforeRevalidation (t * testing.T ) { 107home := t .TempDir () 108service := testService (home ) 109plan ,err := service .PlanCleanup (t .Context (),CleanupOptions {Backups :true }) 110if err != nil { 111t .Fatal (err ) 112 } 113helper ,err := testService (home ).startMaintenance (t .Context (),nil ) 114if err != nil { 115t .Fatal (err ) 116 } 117defer helper .close () 118// Revalidation would fail on this directory. Contention must win first. 119if err := os .Mkdir (filepath .Join (home ,"albedo.sqlite" ),0700 );err != nil { 120t .Fatal (err ) 121 } 122if _ ,err := service .ApplyCleanup (t .Context (),plan );err == nil || ! strings .Contains (err .Error (),"storage is in use" ) { 123t .Fatalf ("did not acquire before report: %v" ,err ) 124 } 125}