package host import ( "context" "os" "strings" "testing" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/hostguard" "github.com/carlosframework/platform/internal/release" ) type retiredReceiptLockStore struct { *rollbackDisk held bool } func (s *retiredReceiptLockStore) Lock(context.Context, string) (func(), error) { if s.held { return nil, os.ErrPermission } s.held = true return func() { s.held = false }, nil } func TestPlan14GenerationRetirementReceiptLockOrder(t *testing.T) { f, disk, _ := generationLaunchFixture(t) in, err := f.root.Guard.Root.Installation(t.Context(), f.target.Host, hostguard.Captured{Incarnation: f.target.Incarnation, Stamp: f.target.Stamp}) if err != nil { t.Fatal(err) } state := &retiredReceiptLockStore{rollbackDisk: &rollbackDisk{dir: t.TempDir()}} f.root.Guard.Root = hostguard.NewRootAuthority(state) if err := f.root.Guard.EstablishRoot(t.Context(), in, func(*hostclaim.Claim) error { return nil }); err != nil { t.Fatal(err) } if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil { t.Fatal(err) } r := readGenerationLaunch(t, disk) if err := f.root.stop(t.Context(), f.peer, *f.req.Reservation); err != nil { t.Fatal(err) } if err := f.journal.CloseWriters(t.Context(), f.target); err != nil { t.Fatal(err) } calls := 0 v := generationRetirement{guard: f.root.Guard, journal: f.journal, kernel: func(context.Context, release.GenerationReservation) (string, error) { return "", os.ErrPermission }, retiredKernel: func(_ context.Context, _ release.GenerationReservation, view hostguard.FenceView) (string, error) { if !state.held || view.Host != f.target.Host { t.Fatal("retirement verification escaped exclusion") } calls++ return strings.Repeat("a", 64), nil }} if err := v.retire(t.Context(), &release.RootGenerations{Store: disk}, r); err != nil { t.Fatal(err) } if calls != 1 || state.held { t.Fatalf("verification calls=%d lock=%v", calls, state.held) } }