package hostops import ( "context" "github.com/carlosframework/platform/internal/hostclaim" "github.com/carlosframework/platform/internal/park" "github.com/carlosframework/platform/internal/provision" "strings" "testing" ) func TestPlan13FenceRecoveryHomeAndNamed(t *testing.T) { for _, which := range []string{"source-home", "target-home", "named"} { t.Run(which, func(t *testing.T) { w := newC7World(t, func(c *hostclaim.Claim, r *provision.Record, _ *AppAdmission) { c.Op.Kind, c.Op.Phase, c.Op.Exec = hostclaim.KindLanding, hostclaim.PhaseProbing, "source" c.Op.Intent["source"], c.Op.Intent["target"], c.Op.Intent["to"], c.Op.Intent["target_enrollment"] = "target", "source", "ie", strings.Repeat("a", 32) c.Op.Participants = []string{"target", "source"} c.Obligations = nil c.Op.Journal = map[string]string{hostclaim.JournalSourceStamp: "1", hostclaim.JournalSrcGen: "src"} r.Region = "uk" r.Move.From, r.Move.To, r.Move.State = "uk", "ie", provision.MoveRollingBack if which == "source-home" { r.Region = "" r.Move.From = "" c.Op.Intent["home_region"] = "uk" } if which == "target-home" { r.Move.To = "" c.Op.Intent["to"] = park.HomeRegion c.Op.Intent["home_region"] = "ie" } at := r.CreatedAt key := "control/box-fences/" + strings.Repeat("a", 32) + ".json" r.Move.Rollback = &provision.MoveRollback{ID: "rb_abcdefghijklmnopqrstuvwxyz", Reason: provision.RollbackTargetFenced, Evidence: key, RequestedAt: &at, TargetPhase: provision.RbTargetLost, LossRef: key, LostAt: &at, SourcePhase: provision.RbSourceWaiting} }) if which == "source-home" { w.authority.home = "uk" w.control.homeRegion = "uk" } if which == "target-home" { w.authority.home = "ie" w.control.homeRegion = "ie" } run := func() error { return w.control.RunRecovery(t.Context(), func(ctx context.Context) error { return runMoveRecovery(ctx, w.claim(t), func(ctx context.Context, g *MoveRecoveryGrant) error { _, err := g.ReleaseFencedTarget(ctx, w.ref) return err }, w.authority) }) } if err := run(); err != nil { t.Fatal(err) } c := w.claim(t).Claim if c.Op.Phase != hostclaim.PhaseReleased { t.Fatal(c.Op) } want := "ie" if which == "target-home" { want = park.HomeRegion } for _, ob := range c.Obligations { if ob.Region != want { t.Fatalf("%+v", ob) } } if err := run(); err != nil { t.Fatal("record completion", err) } rec, err := provision.GetRecord(t.Context(), w.raw, "bab", "app", w.host) if err != nil { t.Fatal(err) } if which == "source-home" && (rec.Region != "" || rec.Move.From != "") { t.Fatal("source placement rewritten") } if which == "target-home" && rec.Move.To != "" { t.Fatal("target placement rewritten") } if which == "target-home" { o := w.claim(t) for _, ob := range o.Claim.Obligations { var e error o, e = hostclaim.Update(t.Context(), w.raw, o, hostclaim.CompleteObligation(ob.Op, ob.ID)) if e != nil { t.Fatal(e) } } o, err = hostclaim.Update(t.Context(), w.raw, o, func(c *hostclaim.Claim) error { c.Obligations = append(c.Obligations, hostclaim.Obligation{ID: "retained", Op: c.Op.ID, Kind: "park-generation", Region: "ie", Owner: "region:ie", Generation: "old", Retirement: "retirement"}) return nil }) if err != nil { t.Fatal(err) } stamp := func() error { return w.control.RunRecovery(t.Context(), func(ctx context.Context) error { return runMoveRecovery(ctx, w.claim(t), func(ctx context.Context, g *MoveRecoveryGrant) error { return g.StampLostMoveTargetParked(ctx) }, w.authority) }) } if err := stamp(); err == nil { t.Fatal("parked stamp ignored retained-name chore") } rec, err = provision.GetRecord(t.Context(), w.raw, "bab", "app", w.host) if err != nil || rec.Move.Rollback.TargetParkedAt != nil { t.Fatal("premature parked stamp", err) } if _, err = hostclaim.Update(t.Context(), w.raw, o, hostclaim.CompleteObligation(o.Claim.Op.ID, "retained")); err != nil { t.Fatal(err) } if err := stamp(); err != nil { t.Fatal("completed target refused", err) } } }) } }