| index b5b475b2f..86b868151 100644 |
| --- a/internal/domains/reconcile_test.go |
| +++ b/internal/domains/reconcile_test.go |
| @@ -1221,3 +1221,40 @@ func TestStampHealthStandsAlone(t *testing.T) { |
| t.Errorf("unconfigured pass stamped %+v", got) |
| } |
| } |
| + |
| +// A resolver failure never overwrites a verdict: the last known verdict |
| +// and its stamp time stay, so a bad DNS tick cannot unpublish a working |
| +// custom domain (#287's gate) or launder staleness into "never checked". |
| +func TestStampHealthHoldsLastVerdictOnResolverFailure(t *testing.T) { |
| + reg := regWith(t, registry.Route{Host: "app.acct.oncarlos.test", Kind: "service", Addr: "10.0.0.1:1", Status: "ready"}) |
| + if err := reg.UpsertAlias(registry.RouteAlias{Alias: "www.customer.test", Host: "app.acct.oncarlos.test", Account: "acct", App: "app"}); err != nil { |
| + t.Fatal(err) |
| + } |
| + good := domains.Config{AppsDomain: "oncarlos.test", EdgeIPs: []string{"203.0.113.7"}, |
| + Resolve: func(string) ([]string, error) { return []string{"203.0.113.7"}, nil }, |
| + Now: func() time.Time { return time.Unix(1000, 0) }} |
| + if err := domains.StampHealth(context.Background(), reg, good, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + broken := good |
| + broken.Resolve = func(string) ([]string, error) { return nil, errors.New("SERVFAIL") } |
| + broken.Now = func() time.Time { return time.Unix(2000, 0) } |
| + if err := domains.StampHealth(context.Background(), reg, broken, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + if got := mustGet(t, reg, "app.acct.oncarlos.test"); got.DNSStatus != "pointing" || got.DNSCheckedAt != 1000 { |
| + t.Errorf("route after resolver failure = %q @%d; want pointing @1000", got.DNSStatus, got.DNSCheckedAt) |
| + } |
| + aliases, _ := reg.ListAliases() |
| + if len(aliases) != 1 || aliases[0].DNSStatus != "pointing" || aliases[0].DNSCheckedAt != 1000 { |
| + t.Errorf("alias after resolver failure = %+v; want pointing @1000", aliases) |
| + } |
| + // A never-checked row still records unknown, so "unknown" stays honest. |
| + fresh := regWith(t, registry.Route{Host: "new.acct.oncarlos.test", Kind: "service", Addr: "10.0.0.1:1", Status: "ready"}) |
| + if err := domains.StampHealth(context.Background(), fresh, broken, nil); err != nil { |
| + t.Fatal(err) |
| + } |
| + if got := mustGet(t, fresh, "new.acct.oncarlos.test"); got.DNSStatus != "" || got.DNSCheckedAt != 2000 { |
| + t.Errorf("fresh row = %q @%d; want \"\" @2000", got.DNSStatus, got.DNSCheckedAt) |
| + } |
| +} |