package hostclaim import ( "errors" "fmt" "strings" "testing" "time" ) func TestPlan13ResidueAliasQueue(t *testing.T) { for _, home := range []string{"ie", "", "uk"} { for _, different := range []bool{false, true} { t.Run(home+"/"+map[bool]string{false: "same", true: "different"}[different], func(t *testing.T) { c, scope := parkFixture(t) c.Op.Intent["home_region"] = home inState(c, KindLanding, PhaseProbing) id := plan13IDs() first := scope(c.Holder.Location) if err := QueueResidueParks(moveA, "ie", first, []string{"g1"}, id)(c); err != nil { t.Fatal(err) } second := first if different { second.EvidenceAt = second.EvidenceAt.Add(time.Second) } before := string(mustJSON(t, c)) err := QueueResidueParks(moveA, "@home", second, []string{"g1"}, id)(c) if home == "ie" { if different && (!errors.Is(err, ErrWrongState) || !strings.Contains(err.Error(), "another scope")) { t.Fatalf("scope conflict: %v", err) } if !different && err != nil { t.Fatal(err) } if string(mustJSON(t, c)) != before { t.Fatal("alias replay changed claim") } } else if err != nil || len(c.Obligations) != 2 { t.Fatalf("unbound region: %v %+v", err, c.Obligations) } }) } } } func TestPlan13ReplicaAliasQueue(t *testing.T) { for _, home := range []string{"ie", "", "uk"} { c, scope := parkFixture(t) c.Op.Intent["home_region"] = home s := scope("moves/" + c.Host + "/" + moveA) id := plan13IDs() if _, err := queueReplicaPark(c, moveA, "ie", s, id); err != nil { t.Fatal(err) } if got := owesStagingPark(c, moveA, "@home"); got != (home == "ie") { t.Fatalf("home %q: staging owed %v", home, got) } if _, err := queueReplicaPark(c, moveA, "@home", s, id); err != nil { t.Fatal(err) } want := 2 if home == "ie" { want = 1 } if len(c.Obligations) != want { t.Fatalf("home %q: %+v", home, c.Obligations) } } } func plan13IDs() func() string { n := 0 return func() string { n++; return fmt.Sprintf("chore%d", n) } } func TestPlan13AbortAndRevertRetainHomeChore(t *testing.T) { for _, action := range []string{"abort", "revert", "revert-replay"} { t.Run(action, func(t *testing.T) { c, scope := parkFixture(t) c.Op.Intent["home_region"], c.Op.Intent["to"] = "ie", "@home" s := scope("moves/" + c.Host + "/" + moveA) id := plan13IDs() if _, err := queueReplicaPark(c, moveA, "ie", s, id); err != nil { t.Fatal(err) } if action == "abort" { c.Op.Phase = PhaseAborting changed := s changed.EvidenceAt = changed.EvidenceAt.Add(time.Second) if err := Abort(moveA, "@home", changed, id)(c); !errors.Is(err, ErrWrongState) { t.Fatalf("abort accepted conflicting alias scope: %v", err) } if err := Abort(moveA, "@home", s, id)(c); err != nil { t.Fatal(err) } } else { c.Op.Exec = "" setJournal(c, JournalEvidenceSource, "evidence") if action == "revert-replay" { c.Op.Kind, c.Op.Exec = KindReverting, "ie-box" setJournal(c, JournalRevPhase, RevPhaseEvidence) } if err := Revert(moveA, "ie-box", "@home", &s, id)(c); err != nil { t.Fatal(err) } } if len(c.Obligations) != 1 || c.Obligations[0].Region != "ie" { t.Fatalf("rewrote or duplicated chore: %+v", c.Obligations) } }) } } func TestPlan13ReturnLaneAliasScope(t *testing.T) { c, scope := parkFixture(t) c.Op.Intent["home_region"] = "ie" c.Op.Intent["rollback"] = "rb_abcdefghijklmnopqrstuvwxyz" inState(c, KindRestoring, PhaseProbed) s := scope("moves/" + c.Host + "/" + c.Op.Intent["rollback"]) id := plan13IDs() if _, err := queueReplicaPark(c, moveA, "ie", s, id); err != nil { t.Fatal(err) } setJournal(c, journalReturnLane, s.Location) changed := s changed.EvidenceAt = changed.EvidenceAt.Add(time.Second) if err := QueueReturnLanePark(moveA, "@home", changed, id)(c); !errors.Is(err, ErrWrongState) { t.Fatalf("journal masked conflicting alias chore: %v", err) } if err := QueueReturnLanePark(moveA, "@home", s, id)(c); err != nil { t.Fatal(err) } if len(c.Obligations) != 1 || c.Obligations[0].Region != "ie" { t.Fatal(c.Obligations) } }