| 1 | package hostops |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "errors" |
| 6 | "testing" |
| 7 | |
| 8 | "github.com/carlosframework/platform/internal/hostclaim" |
| 9 | "github.com/carlosframework/platform/internal/provision" |
| 10 | ) |
| 11 | |
| 12 | func TestPlan13RecoveryRefusesForeignHome(t *testing.T) { |
| 13 | w := newC7World(t, func(c *hostclaim.Claim, _ *provision.Record, _ *AppAdmission) { c.Op.Intent["home_region"] = "ie" }) |
| 14 | o, err := hostclaim.Read(t.Context(), w.raw, w.host) |
| 15 | if err != nil { |
| 16 | t.Fatal(err) |
| 17 | } |
| 18 | called := false |
| 19 | err = w.control.RunRecovery(t.Context(), func(ctx context.Context) error { |
| 20 | return runMoveRecovery(ctx, o, func(context.Context, *MoveRecoveryGrant) error { called = true; return nil }) |
| 21 | }) |
| 22 | if !errors.Is(err, ErrIdentity) || called { |
| 23 | t.Fatalf("foreign recovery invoked=%v err=%v", called, err) |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | func TestPlan13LossRefusesForeignHome(t *testing.T) { |
| 28 | w := newLossWorld(t, "landing", func(c *hostclaim.Claim, _ *provision.Record, _ *AppAdmission) { c.Op.Intent["home_region"] = "ie" }) |
| 29 | _, err := w.control.moveLossClaim(t.Context(), "bab", "app", lossHost) |
| 30 | if !errors.Is(err, ErrIdentity) { |
| 31 | t.Fatalf("foreign loss: %v", err) |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | func TestPlan13RecoveryAndLossHomeAgreement(t *testing.T) { |
| 36 | for _, home := range []string{"ie", "uk", ""} { |
| 37 | t.Run(home, func(t *testing.T) { |
| 38 | w := newC7World(t, func(c *hostclaim.Claim, _ *provision.Record, _ *AppAdmission) { c.Op.Intent["home_region"] = "ie" }) |
| 39 | w.control.homeRegion = home |
| 40 | called := false |
| 41 | err := w.control.RunRecovery(t.Context(), func(ctx context.Context) error { |
| 42 | return runMoveRecovery(ctx, w.claim(t), func(ctx context.Context, g *MoveRecoveryGrant) error { |
| 43 | called = true |
| 44 | _, _, _, err := g.current(ctx) |
| 45 | return err |
| 46 | }) |
| 47 | }) |
| 48 | if (err == nil) != (home == "ie") || called != (home == "ie") { |
| 49 | t.Fatalf("recovery called=%v: %v", called, err) |
| 50 | } |
| 51 | l := newLossWorld(t, "landing", func(c *hostclaim.Claim, _ *provision.Record, _ *AppAdmission) { c.Op.Intent["home_region"] = "ie" }) |
| 52 | l.control.homeRegion = home |
| 53 | _, err = l.control.InspectMoveLoss(t.Context(), l.signer, lossBucket, "operator", "bab", "app", lossHost, "uk-label") |
| 54 | if (err == nil) != (home == "ie") { |
| 55 | t.Fatalf("loss: %v", err) |
| 56 | } |
| 57 | }) |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // A named move that started before any home designation records no home |
| 62 | // name. Publishing the first designation must not strand it in recovery, |
| 63 | // lifecycle writes or declare-lost replays; one that recorded a different |
| 64 | // home must still refuse. |
| 65 | func TestPlan13AliasFreeOperationSurvivesFirstDesignation(t *testing.T) { |
| 66 | for _, kind := range []string{hostclaim.KindRestoring, hostclaim.KindReverting, "landing", "moving"} { |
| 67 | c := &hostclaim.Claim{} |
| 68 | c.Op.Kind = kind |
| 69 | c.Op.Intent = map[string]string{} |
| 70 | if !operationHomeMatches("ie", c) { |
| 71 | t.Errorf("%s: alias-free op refused after the first designation", kind) |
| 72 | } |
| 73 | c.Op.Intent["home_region"] = "ie" |
| 74 | if !operationHomeMatches("ie", c) { |
| 75 | t.Errorf("%s: matching home refused", kind) |
| 76 | } |
| 77 | c.Op.Intent["home_region"] = "uk" |
| 78 | if operationHomeMatches("ie", c) { |
| 79 | t.Errorf("%s: mismatched home accepted", kind) |
| 80 | } |
| 81 | } |
| 82 | } |
| 83 | |