| 1 | package host |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "github.com/carlosframework/platform/internal/hostclaim" |
| 6 | "github.com/carlosframework/platform/internal/lease" |
| 7 | "github.com/carlosframework/platform/internal/moves" |
| 8 | "github.com/carlosframework/platform/internal/park" |
| 9 | "strings" |
| 10 | "testing" |
| 11 | "time" |
| 12 | ) |
| 13 | |
| 14 | func TestPlan13HomeTargetReadiness(t *testing.T) { |
| 15 | for _, stored := range []string{park.HomeRegion, "ie", "ca"} { |
| 16 | t.Run(stored, func(t *testing.T) { |
| 17 | h := newPhase1Harness(t) |
| 18 | h.start(t, "manual") |
| 19 | rec := h.read(t, p1Host) |
| 20 | rec.Move.To = "" |
| 21 | obs, err := hostclaim.Read(t.Context(), h.s, p1Host) |
| 22 | if err != nil { |
| 23 | t.Fatal(err) |
| 24 | } |
| 25 | obs.Claim.Op.Intent["home_region"] = "ie" |
| 26 | obs.Claim.Touched.Regions = []string{stored} |
| 27 | obs.Claim.Touched.Boxes = append(obs.Claim.Touched.Boxes, "uk-box") |
| 28 | raw, err := json.Marshal(moves.MoveJSON{MoveID: rec.Move.ID, Incarnation: rec.Move.Incarnation, Host: rec.Host, From: rec.Move.From, To: rec.Move.To}) |
| 29 | if err != nil { |
| 30 | t.Fatal(err) |
| 31 | } |
| 32 | h.f.store("data-uk", moves.MoveJSONKey(rec.Host, rec.Move.ID), fakeMoveObject{lease.MirrorObject{ETag: "x", Size: int64(len(raw))}, string(raw)}) |
| 33 | w := &movesWorker{cfg: h.targetCfg(), mirrors: map[string]lease.MirrorStore{}} |
| 34 | got := w.checkClaim(t.Context(), obs, rec) |
| 35 | if got.OK != (stored != "ca") { |
| 36 | t.Fatalf("%s: %+v", stored, got) |
| 37 | } |
| 38 | if !got.OK && got.Reason != t9Untouched("ie") { |
| 39 | t.Fatal(got.Reason) |
| 40 | } |
| 41 | }) |
| 42 | } |
| 43 | } |
| 44 | func TestPlan13HomeQuietReason(t *testing.T) { |
| 45 | now := time.Unix(1000, 0) |
| 46 | o := hostclaim.Observed{Claim: &hostclaim.Claim{Op: hostclaim.Op{Intent: map[string]string{"home_region": "ie"}}, QuietAfter: map[string]time.Time{park.HomeRegion: now.Add(time.Minute)}}} |
| 47 | got := checkQuiet(o, park.HomeRegion, now) |
| 48 | if got.OK || strings.Contains(got.Reason, park.HomeRegion) || got.Reason != t12NotQuiet("ie", now.Add(time.Minute)) { |
| 49 | t.Fatal(got) |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | func TestPlan13ProbeHomeHistory(t *testing.T) { |
| 54 | h := &hostclaim.Holder{Admissions: []hostclaim.AdmissionRecord{ |
| 55 | {Generation: "move", Region: "ie", Box: "box", Mode: "cold"}, |
| 56 | {Generation: "next", Predecessor: "move", Region: "@home", Box: "box", Mode: "cold"}, |
| 57 | }} |
| 58 | for _, home := range []string{"ie", ""} { |
| 59 | m := &movesProbeOwners{Region: "ie", HomeRegion: home, Box: "box"} |
| 60 | if got := m.descendsFromMove(h, "next", "move"); got != (home != "") { |
| 61 | t.Fatal("descent", home, got) |
| 62 | } |
| 63 | _, ok := m.unpublishedPath(h, "next", "move") |
| 64 | if ok != (home != "") { |
| 65 | t.Fatal("unpublished path", home, ok) |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | func TestPlan13LandingUsesLocalBinding(t *testing.T) { |
| 71 | for _, tc := range []struct { |
| 72 | local, fleet, operation string |
| 73 | ok bool |
| 74 | }{ |
| 75 | {"", "ie", "uk", false}, {"", "uk", "uk", false}, {"uk", "uk", "uk", true}, {"uk", "ie", "uk", false}, |
| 76 | } { |
| 77 | f := newPOFixture(t) |
| 78 | c := f.poFlipClaim() |
| 79 | c.Op.Intent["to"], c.Op.Intent["home_region"] = park.HomeRegion, tc.operation |
| 80 | f.rec.Move.To = "" |
| 81 | f.owners.HomeRegion, f.owners.FleetHomeRegion = tc.local, tc.fleet |
| 82 | _, err := f.owners.landing(t.Context(), hostclaim.Observed{Host: poHost, Claim: c}) |
| 83 | if (err == nil) != tc.ok { |
| 84 | t.Fatalf("%+v: %v", tc, err) |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | func TestPlan13OwnStorageProjectionIgnoresOperationHome(t *testing.T) { |
| 89 | h := &hostclaim.Holder{Admissions: []hostclaim.AdmissionRecord{{Region: park.HomeRegion, PredecessorRegion: park.HomeRegion}}} |
| 90 | m := &movesProbeOwners{Region: "uk"} |
| 91 | r := m.request("test.example", h) |
| 92 | if r.Holder.Admissions[0].Region != park.HomeRegion { |
| 93 | t.Fatal("named storage borrowed a home alias") |
| 94 | } |
| 95 | m.HomeRegion = "uk" |
| 96 | r = m.request("test.example", h) |
| 97 | if r.Holder.Admissions[0].Region != "uk" || h.Admissions[0].Region != park.HomeRegion { |
| 98 | t.Fatal("home view lost binding or rewrote history") |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | func TestPlan13HomeOwnerReason(t *testing.T) { |
| 103 | got := checkOneOwner(moveFleet{}, "", "ie") |
| 104 | if got.OK || got.Reason != t8Count(0, "ie") { |
| 105 | t.Fatal(got) |
| 106 | } |
| 107 | o := hostclaim.Observed{Claim: &hostclaim.Claim{QuietAfter: map[string]time.Time{park.HomeRegion: time.Unix(2, 0)}}} |
| 108 | got = checkQuiet(o, park.HomeRegion, time.Unix(1, 0)) |
| 109 | if strings.Contains(got.Reason, park.HomeRegion) || strings.Contains(got.Reason, "left recently") { |
| 110 | t.Fatal(got) |
| 111 | } |
| 112 | } |
| 113 | |