| index 9a19a5bf3..34a4f66e8 100644 |
| --- a/internal/domains/aliases_test.go |
| +++ b/internal/domains/aliases_test.go |
| @@ -701,3 +701,114 @@ func TestReconcileAliasesStillDerivesTheCatchAllForAFirstRouteClaim(t *testing.T |
| "instead of \"*.\"+host, refusing every first-route wildcard claim", aliases) |
| } |
| } |
| + |
| +// TestReconcileAliasesDerivesReplicaAlias covers the account-host half of |
| +// #162 (spec §3): a local route carrying ReplicaOf derives an alias from |
| +// the home's host to the replica's own host, with no claim involved at all. |
| +func TestReconcileAliasesDerivesReplicaAlias(t *testing.T) { |
| + s := release.NewDirStore(t.TempDir()) |
| + reg := aliasRegWith(t, registry.Route{ |
| + Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance", |
| + Status: "ready", ReplicaOf: "acme.go.tito.io", |
| + }) |
| + for i := 0; i < 2; i++ { // twice: the second pass is the sweep's chance to eat it |
| + if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + aliases, err := reg.ListAliases() |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if len(aliases) != 1 { |
| + t.Fatalf("got %d aliases, want 1: %+v", len(aliases), aliases) |
| + } |
| + if a := aliases[0]; a.Alias != "acme.go.tito.io" || a.Host != "r7x2k9m4qa.go.tito.io" || |
| + a.Account != "bab" || a.App != "tito" { |
| + t.Fatalf("replica alias row mismatch: %+v", a) |
| + } |
| +} |
| + |
| +// TestReconcileAliasesSweepsAReplicaAliasWhoseRouteIsGone covers the removal |
| +// half: when the replica's route disappears (its record went, the instance |
| +// pass retired the route), the alias derived from it must not outlive it — |
| +// no new retirement code, the ordinary sweep at the bottom of the pass. |
| +func TestReconcileAliasesSweepsAReplicaAliasWhoseRouteIsGone(t *testing.T) { |
| + s := release.NewDirStore(t.TempDir()) |
| + reg := aliasRegWith(t, registry.Route{ |
| + Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance", |
| + Status: "ready", ReplicaOf: "acme.go.tito.io", |
| + }) |
| + if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := reg.Delete("r7x2k9m4qa.go.tito.io"); err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + if aliases, err := reg.ListAliases(); err != nil { |
| + t.Fatal(err) |
| + } else if len(aliases) != 0 { |
| + t.Fatalf("the replica alias outlived its route: %+v", aliases) |
| + } |
| +} |
| + |
| +// TestReconcileAliasesReplicaAliasLosesToARealRoute covers the collision |
| +// rule: if the home ever lands on the same box as its replica, the real |
| +// local route for the account host must win — no alias derived over it. |
| +func TestReconcileAliasesReplicaAliasLosesToARealRoute(t *testing.T) { |
| + s := release.NewDirStore(t.TempDir()) |
| + reg := aliasRegWith(t, |
| + registry.Route{Host: "acme.go.tito.io", App: "tito", Account: "bab", Kind: "instance", Status: "ready"}, |
| + registry.Route{Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance", |
| + Status: "ready", ReplicaOf: "acme.go.tito.io"}, |
| + ) |
| + if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + if aliases, err := reg.ListAliases(); err != nil { |
| + t.Fatal(err) |
| + } else if len(aliases) != 0 { |
| + t.Fatalf("an alias was derived over a real local route: %+v", aliases) |
| + } |
| +} |
| + |
| +// TestReconcileAliasesDerivesReplicaCustomDomainAlias covers the half that |
| +// carries titogo's real checkout traffic (spec §5a, revision 3): a claim |
| +// whose Route names the HOME host, with no local route of its own, derives |
| +// an alias to the REPLICA's host — the claim's own primary lookup misses |
| +// locally, but a local route's ReplicaOf names the same home. Survives a |
| +// second pass, same as the account-host alias above. |
| +func TestReconcileAliasesDerivesReplicaCustomDomainAlias(t *testing.T) { |
| + s := release.NewDirStore(t.TempDir()) |
| + reg := aliasRegWith(t, registry.Route{ |
| + Host: "r7x2k9m4qa.go.tito.io", App: "tito", Account: "bab", Kind: "instance", |
| + Status: "ready", ReplicaOf: "acme.go.tito.io", |
| + }) |
| + putClaim(t, s, Claim{ |
| + Host: "tickets.example.com", Account: "bab", App: "tito", Route: "acme.go.tito.io", |
| + }) |
| + for i := 0; i < 2; i++ { |
| + if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + aliases, err := reg.ListAliases() |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + var found *registry.RouteAlias |
| + for i := range aliases { |
| + if aliases[i].Alias == "tickets.example.com" { |
| + found = &aliases[i] |
| + } |
| + } |
| + if found == nil { |
| + t.Fatalf("custom-domain replica alias missing: %+v", aliases) |
| + } |
| + if found.Host != "r7x2k9m4qa.go.tito.io" || found.Account != "bab" || found.App != "tito" { |
| + t.Fatalf("custom-domain replica alias row mismatch: %+v", *found) |
| + } |
| +} |