| index 9e63d7cb3..545fba187 100644 |
| --- a/e2e_test.go |
| +++ b/e2e_test.go |
| @@ -36,6 +36,7 @@ import ( |
| "github.com/carlosframework/platform/internal/appconfig" |
| "github.com/carlosframework/platform/internal/domains" |
| "github.com/carlosframework/platform/internal/edge" |
| + "github.com/carlosframework/platform/internal/provision" |
| "github.com/carlosframework/platform/internal/registry" |
| "github.com/carlosframework/platform/internal/release" |
| "github.com/carlosframework/platform/internal/status" |
| @@ -2917,6 +2918,58 @@ func TestRouteEnvironmentRefusedOnProvisionedRoute(t *testing.T) { |
| } |
| } |
| |
| +// Task 11 item 5 (carried from Task 9's review): the sidecar reconcile pass |
| +// (internal/provision/sidecar_reconcile.go, convergeSidecar) converges |
| +// Hibernate from the app's sidecars manifest on EVERY pass — unconditionally, |
| +// not the ordinary instance record's tri-state (absent-means-free) column a |
| +// Provisioned instance route carries. A `-hibernate` write on such a row |
| +// lands and is reverted within seconds of the next serial bump, with nothing |
| +// said anywhere — the same class of bug #130 was, on the axis this repo has |
| +// not yet paid the lesson for. |
| +// |
| +// The reserved sidecar suffix (suffixRail) already refuses every genuine |
| +// sidecar row through a different door — every one is minted under |
| +// provision.SidecarSuffix by construction — so this test uses a host OUTSIDE |
| +// that suffix to isolate the NEW check from that existing one: this is |
| +// deliberately the shape suffixRail's own doc comment calls out as not |
| +// hypothetical (an ordinary-kind row's Provisioned+Kind combination is what |
| +// this rail reads, not the hostname). |
| +func TestRouteHibernateRefusedOnProvisionedSidecarRow(t *testing.T) { |
| + f := newRouteTestFixture(t) |
| + f.addRoute(registry.Route{Host: "bot.eleven.bdm.example.com", Kind: "sidecar", App: "eleven", Account: "bdm", |
| + Status: "ready", Provisioned: true}) |
| + |
| + out, err := f.run(f.fullEnv(), "route", "-registry", f.regPath, "-host", "bot.eleven.bdm.example.com", "-hibernate=false") |
| + if err == nil { |
| + t.Fatalf("route -hibernate on a provisioned sidecar row was accepted:\n%s", out) |
| + } |
| + if !strings.Contains(out, "sidecar") || !strings.Contains(out, provision.SidecarManifestKey("bdm", "eleven")) { |
| + t.Errorf("refusal does not name the sidecar manifest as the door:\n%s", out) |
| + } |
| + if got := f.routeOf("bot.eleven.bdm.example.com").Hibernate; got != false { |
| + t.Fatalf("hibernate = %v, want it unwritten after the refusal", got) |
| + } |
| +} |
| + |
| +// TestRouteHibernateRefusedOnGenuineSidecarSuffixRow is the end-to-end proof |
| +// against a REAL sidecar host shape (under provision.SidecarSuffix): both |
| +// rails agree, and the operator-facing message names the reconcile pass, not |
| +// just "reserved suffix". |
| +func TestRouteHibernateRefusedOnGenuineSidecarSuffixRow(t *testing.T) { |
| + f := newRouteTestFixture(t) |
| + host := provision.SidecarHost("bot", "eleven", "bdm") |
| + f.addRoute(registry.Route{Host: host, Kind: "sidecar", App: "eleven", Account: "bdm", |
| + Status: "ready", Provisioned: true}) |
| + |
| + out, err := f.run(f.fullEnv(), "route", "-registry", f.regPath, "-host", host, "-hibernate") |
| + if err == nil { |
| + t.Fatalf("route -hibernate on a genuine sidecar row was accepted:\n%s", out) |
| + } |
| + if got := f.routeOf(host).Hibernate; got != false { |
| + t.Fatalf("hibernate = %v, want it unwritten after the refusal", got) |
| + } |
| +} |
| + |
| // The box-scoped axes are untouched: they name resources that exist on one |
| // machine, the record does not own them, and an operator must still be able |
| // to grant a port or stamp a unit on a provisioned route. |