package host import ( "context" "encoding/json" "github.com/carlosframework/platform/internal/rootparticipation" "os" "path/filepath" "testing" ) func updateParticipationFixture(t *testing.T) *rootparticipation.Ledger { t.Helper() disk := &rollbackDisk{dir: t.TempDir()} raw, _ := json.Marshal(rootparticipation.Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}) if err := disk.Write("census.json", raw); err != nil { t.Fatal(err) } return &rootparticipation.Ledger{State: disk, VerifyLaunches: func(context.Context, uint64) error { return nil }, ExcludeLaunches: func(ctx context.Context, fn func(context.Context) error) error { return fn(ctx) }} } func TestPlan14ExecutionSystemUpdateExclusion(t *testing.T) { for _, pending := range []bool{false, true} { t.Run(map[bool]string{true: "participating", false: "empty"}[pending], func(t *testing.T) { f := newApplyFixture(t, "stable", "old") f.a.regionHA = true f.a.participation = updateParticipationFixture(t) if pending { if err := f.a.participation.State.Write("shop.example.json", []byte("{\"Schema\":1,\"Status\":\"pending\"}")); err != nil { t.Fatal(err) } } mirror := filepath.Join(f.a.dataDir, ".hostexec") if err := os.MkdirAll(mirror, 0700); err != nil { t.Fatal(err) } if err := os.Remove(mirror); err != nil { t.Fatal(err) } err := f.a.beginExecutableChange(t.Context(), "new", f.now) if pending { if err == nil { t.Fatal("system update trusted deleted agent state") } return } if err != nil { t.Fatal(err) } if err := f.a.participation.Acquire(t.Context(), func() error { return nil }); err == nil { t.Fatal("acquisition crossed durable system update") } f.a.settleUpdateBegun(t.Context()) if err := f.a.participation.Acquire(t.Context(), func() error { return nil }); err != nil { t.Fatal("settled update still excludes", err) } }) } } func TestPlan14ExecutionRecoveryWithoutArmedFloor(t *testing.T) { for _, recoverable := range []bool{false, true} { t.Run(map[bool]string{false: "unresolved", true: "settled"}[recoverable], func(t *testing.T) { f := newApplyFixture(t, "stable", "old") if f.a.guarded() { t.Fatal("fixture has an armed floor") } if err := f.a.beginExecutableChange(t.Context(), "new", f.now); err != nil { t.Fatal(err) } if err := f.a.participation.State.Write("shop.example.json", []byte(`{"Schema":1,"Status":"lost"}`)); err != nil { t.Fatal(err) } old := recoverPendingControllers t.Cleanup(func() { recoverPendingControllers = old }) calls := 0 recoverPendingControllers = func(_ context.Context, data, guard string) error { calls++ if data != f.a.dataDir || guard != systemGuardDir(f.a.optDir) { t.Fatal("wrong recovery scope") } if !recoverable { return rootparticipation.ErrUnavailable } return f.a.participation.State.Remove("shop.example.json") } err := f.a.checkGuardRecovery(t.Context()) if (err == nil) != recoverable || calls != 1 { t.Fatalf("recovery=%t calls=%d err=%v", recoverable, calls, err) } if _, err := f.a.participation.UpdateID(); err != nil { t.Fatal("recovery removed update exclusion", err) } }) } } func TestPlan14ExecutionLegacyJournalRecoversBeforeReservation(t *testing.T) { f := newApplyFixture(t, "stable", "old") if err := f.a.journal(systemJournal{Phase: systemPhaseInstalling, Target: "new"}); err != nil { t.Fatal(err) } if err := f.a.participation.State.Write("shop.example.json", []byte(`{"Schema":1,"Status":"lost"}`)); err != nil { t.Fatal(err) } old := recoverPendingControllers t.Cleanup(func() { recoverPendingControllers = old }) calls := 0 recoverPendingControllers = func(context.Context, string, string) error { calls++ return f.a.participation.State.Remove("shop.example.json") } if err := f.a.checkGuardRecovery(t.Context()); err != nil { t.Fatal(err) } if calls != 1 { t.Fatalf("recovery calls=%d", calls) } if _, err := f.a.participation.UpdateID(); err != nil { t.Fatal("legacy journal lacked root exclusion", err) } }