| 1 | package hostclaim |
| 2 | |
| 3 | import ( |
| 4 | "errors" |
| 5 | "fmt" |
| 6 | "reflect" |
| 7 | "strings" |
| 8 | "testing" |
| 9 | "time" |
| 10 | ) |
| 11 | |
| 12 | func TestPlan13BoundHomeMoveStartCleanup(t *testing.T) { |
| 13 | for _, target := range []string{"@home", "ie"} { |
| 14 | c := &Claim{Holder: &Holder{}, Op: Op{Kind: KindServing, Exec: "src"}, Obligations: []Obligation{{ID: "cleanup", Op: "old", Kind: "park-replica", Region: "ie", Owner: "region:ie"}}} |
| 15 | before := append([]Obligation(nil), c.Obligations...) |
| 16 | a := MoveAdmission{AppID: "app", AdmissionID: "move", SourceEnrollment: strings.Repeat("a", 32), TargetEnrollment: strings.Repeat("b", 32), HomeRegion: "ie"} |
| 17 | if err := BeginAdmittedMove("move", "person", "src", "dst", target, time.Now(), a)(c); !errors.Is(err, ErrPendingChore) { |
| 18 | t.Fatal("pending home cleanup allowed move", target, err) |
| 19 | } |
| 20 | if !reflect.DeepEqual(c.Obligations, before) || c.Op.Kind != KindServing { |
| 21 | t.Fatal("refusal mutated claim") |
| 22 | } |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | func TestPlan13WholeLocationCoversHomeWithoutObjects(t *testing.T) { |
| 27 | for _, release := range []bool{false, true} { |
| 28 | for _, bound := range []bool{false, true} { |
| 29 | c := probedLanding(t) |
| 30 | home, region := "ie", "@home" |
| 31 | if release { |
| 32 | c = targetWroteLanding(t) |
| 33 | home = "uk" |
| 34 | c.Holder.Admissions = append(c.Holder.Admissions, AdmissionRecord{Region: "uk", PredecessorRegion: "uk", Session: 10, Box: "uk-box", Generation: "gen-r2", Predecessor: moveA, Mode: "cold"}) |
| 35 | c.Holder.Session, c.Holder.Generation = 10, "gen-r2" |
| 36 | if err := RollBack(moveA, rbA)(c); err != nil { |
| 37 | t.Fatal(err) |
| 38 | } |
| 39 | c.Op.Intent["to"] = region |
| 40 | } |
| 41 | if bound { |
| 42 | c.Op.Intent["home_region"] = home |
| 43 | } |
| 44 | n := 0 |
| 45 | ids := func() string { n++; return fmt.Sprint("park", n) } |
| 46 | var err error |
| 47 | if release { |
| 48 | err = TargetReleased(moveA, "uk-box", region, stoppedTarget, releaseScope(c), ids)(c) |
| 49 | } else { |
| 50 | src, lane := commitScopes(c) |
| 51 | err = Commit(moveA, region, "ie-box", "uk", src, lane, ids)(c) |
| 52 | } |
| 53 | if err != nil { |
| 54 | t.Fatal(err) |
| 55 | } |
| 56 | idx := 0 |
| 57 | if release { |
| 58 | idx = 1 |
| 59 | } |
| 60 | if c.Holder.Admissions[idx].Covered != bound { |
| 61 | t.Fatalf("release=%v bound=%v: %+v", release, bound, c.Holder.Admissions) |
| 62 | } |
| 63 | if c.Holder.Admissions[idx].PredecessorRegion != home { |
| 64 | t.Fatal("rewrote admission identity") |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | func TestPlan13ReturningWriterHomeCoverage(t *testing.T) { |
| 71 | for _, bound := range []bool{false, true} { |
| 72 | c := targetWroteLanding(t) |
| 73 | if err := RollBack(moveA, rbA)(c); err != nil { |
| 74 | t.Fatal(err) |
| 75 | } |
| 76 | c.Op.Intent["to"] = "@home" |
| 77 | if bound { |
| 78 | c.Op.Intent["home_region"] = "uk" |
| 79 | } |
| 80 | n := 0 |
| 81 | ids := func() string { n++; return fmt.Sprint("park", n) } |
| 82 | if err := TargetReleased(moveA, "uk-box", "@home", stoppedTarget, releaseScope(c), ids)(c); err != nil { |
| 83 | t.Fatal(err) |
| 84 | } |
| 85 | if err := ReturnToSource(moveA, "ie-box", false, ReturnFence{})(c); err != nil { |
| 86 | t.Fatal(err) |
| 87 | } |
| 88 | h := c.Holder |
| 89 | in := Admission{ObservedOpID: c.Op.ID, ObservedPhase: c.Op.Phase, ObservedSession: h.Session, ObservedGeneration: h.Generation, Box: c.Op.Exec, Mode: "cold", NewGeneration: "return", Region: "ie"} |
| 90 | if err := AdmitWriter(in)(c); err != nil { |
| 91 | t.Fatal(err) |
| 92 | } |
| 93 | last := c.Holder.Admissions[len(c.Holder.Admissions)-1] |
| 94 | if last.Covered != bound || last.PredecessorRegion != "uk" { |
| 95 | t.Fatalf("bound=%v: %+v", bound, last) |
| 96 | } |
| 97 | for _, ob := range append([]Obligation(nil), c.Obligations...) { |
| 98 | if err := CompleteObligation(ob.Op, ob.ID)(c); err != nil { |
| 99 | t.Fatal(err) |
| 100 | } |
| 101 | } |
| 102 | if c.Holder.Admissions[len(c.Holder.Admissions)-1].Covered != bound { |
| 103 | t.Fatal("empty cleanup lost coverage") |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | func TestPlan13RetainedHomeChoreBlocksLostTargetParked(t *testing.T) { |
| 108 | for _, ob := range []Obligation{ |
| 109 | {ID: "pending", Op: "move", Kind: "park-generation", Region: "ie", Owner: "region:ie"}, |
| 110 | {ID: "pending", Op: "move", Kind: "park-generation", Region: "other", Owner: "region:ie"}, |
| 111 | } { |
| 112 | c := &Claim{Holder: &Holder{}, Op: Op{ID: "move", Kind: KindRestoring, Exec: "source", Intent: map[string]string{"target": "target", "to": "@home", "home_region": "ie"}}, Lost: []string{"target"}, Obligations: []Obligation{ob}} |
| 113 | if LostMoveTargetParked(c, "@home") { |
| 114 | t.Fatal("pending retained-name chore ignored", ob) |
| 115 | } |
| 116 | c.Obligations = nil |
| 117 | if !LostMoveTargetParked(c, "ie") { |
| 118 | t.Fatal("completed bound target refused") |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | func TestPlan13WarmAndPublishedHomeCoverage(t *testing.T) { |
| 124 | for _, home := range []string{"ie", ""} { |
| 125 | c := &Claim{Gen: 2, Holder: &Holder{Session: 2, Stamp: 2, Generation: "new", WriterBox: "box", Admissions: []AdmissionRecord{{Session: 2, Region: "ie", PredecessorRegion: "ie", Generation: "new", Predecessor: "old", Mode: "cold"}}}, Op: Op{Kind: KindServing, Exec: "box", Intent: map[string]string{"home_region": home}}} |
| 126 | if err := PublishGeneration("", "", 2, "new", "@home", counter())(c); err != nil { |
| 127 | t.Fatal(err) |
| 128 | } |
| 129 | if c.Holder.Admissions[0].Covered != (home != "") { |
| 130 | t.Fatal("publication misses bound predecessor", home) |
| 131 | } |
| 132 | in := Admission{ObservedSession: 2, ObservedGeneration: "new", Box: "box", Mode: "warm", PredecessorCertified: true, Region: "@home"} |
| 133 | if err := AdmitWriter(in)(c); (err == nil) != (home != "") { |
| 134 | t.Fatal("warm admission", home, err) |
| 135 | } |
| 136 | } |
| 137 | } |
| 138 | |