console: fix round 1 — row-scope the Health-word test assertions
TestAppPageOwnerMetricsBoundary and TestAppPageOwnerMetricsStaleBoxIsNotCurrent asserted "Not responding"/"Asleep" against the whole page body, which the fixture's bystander route (kass.carlosapp.dev, always instance-kind, never metered or hibernating) could satisfy regardless of what the route under test actually rendered. Added an instanceRow test helper that slices the body down to the one <tr> naming a given host, and scoped both assertions to it. Verified the fix pins the row: temporarily hibernating the route under test in each case flips the row-scoped assertion to a failure, then reverting restores green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+44
−10
internal/console/server_test.go+44 −10
diff --git a/internal/console/server_test.go b/internal/console/server_test.go| index d42e60f64..cd1d58dd9 100644 |
| --- a/internal/console/server_test.go |
| +++ b/internal/console/server_test.go |
| @@ -1755,20 +1755,27 @@ func TestAppPageOwnerMetricsBoundary(t *testing.T) { |
| t.Fatalf("/apps/kass/instances = %d, want 200: %s", status, body) |
| } |
| // The per-host CPU/Mem readings now live as columns on the Instances |
| - // table itself (no separate Resources section) — each phrase below is |
| - // unique to the one fixture route it describes, so checking presence |
| - // page-wide still pins it to that route. Not-reporting rows all show |
| - // "no data" in the CPU/Mem cell; Asleep vs Not responding is the Health |
| - // column's job, not the metrics cell's. |
| + // table itself (no separate Resources section) — "11%"/"1.0 KB" are |
| + // unique to owned.example.com's own row, so checking presence page-wide |
| + // still pins them to that route. Asleep vs Not responding is the Health |
| + // column's job, not the metrics cell's, and the fixture always carries |
| + // other instance-kind rows (its own bystanders), so those two words are |
| + // scoped to their own row below rather than checked page-wide — a |
| + // page-wide Contains would pass even if the wrong row said it. |
| for _, want := range []string{ |
| "owned.example.com", "11%", "1.0 KB", |
| - "asleep.example.com", "Asleep", |
| - "unmetered.example.com", "Not responding", "no data", |
| + "asleep.example.com", "unmetered.example.com", |
| } { |
| if !strings.Contains(body, want) { |
| t.Fatalf("app page missing %q in:\n%s", want, body) |
| } |
| } |
| + if row := instanceRow(t, body, "asleep.example.com"); !strings.Contains(row, "Asleep") { |
| + t.Fatalf("asleep.example.com's own row did not read Asleep:\n%s", row) |
| + } |
| + if row := instanceRow(t, body, "unmetered.example.com"); !strings.Contains(row, "Not responding") || !strings.Contains(row, "no data") { |
| + t.Fatalf("unmetered.example.com's own row did not read Not responding / no data:\n%s", row) |
| + } |
| // The boundary: nothing about the other tenant, the host, or the box. |
| for _, forbidden := range []string{ |
| "other-tenant", "box-secret-a", // other tenant's unit, the box's name |
| @@ -1895,6 +1902,27 @@ func resourcesSection(t *testing.T, body string) string { |
| return body[i : i+j] |
| } |
| +// instanceRow returns the Running table's one <tr> naming the given host — |
| +// sliced from the host's own anchor through the row's closing tag. The |
| +// fixture always carries more than one route (its own bystanders plus |
| +// whatever a test adds), so a page-wide strings.Contains on a Health word |
| +// like "Not responding" or "Asleep" can be satisfied by SOME row without |
| +// pinning it to the row under test; scoping to the row is what actually |
| +// proves it. |
| +func instanceRow(t *testing.T, body, host string) string { |
| + t.Helper() |
| + i := strings.Index(body, host) |
| + if i < 0 { |
| + t.Fatalf("no row for host %q in:\n%s", host, body) |
| + } |
| + row := body[i:] |
| + j := strings.Index(row, "</tr>") |
| + if j < 0 { |
| + t.Fatalf("row for host %q never closed in:\n%s", host, row) |
| + } |
| + return row[:j] |
| +} |
| + |
| // TestAppPageOwnerMetricsStaleBoxIsNotCurrent: a box that stopped publishing |
| // keeps its last sample inside the 48h sweep window forever. Rendering that |
| // as the instance's CURRENT figure would be a lie with no expiry, so a box |
| @@ -1926,9 +1954,15 @@ func TestAppPageOwnerMetricsStaleBoxIsNotCurrent(t *testing.T) { |
| // The CPU/Mem cell reads the same "no data" a hibernating instance gets |
| // (staleness is not distinguishable from any other non-reporting cause at |
| // that cell); the route isn't hibernating, so the Health column must say |
| - // so plainly rather than claim Asleep. |
| - if !strings.Contains(body, "Not responding") || !strings.Contains(body, "no data") { |
| - t.Fatalf("stale box did not render as not responding with no data:\n%s", resourcesSection(t, body)) |
| + // so plainly rather than claim Asleep. Scoped to owned.example.com's own |
| + // row: the fixture also carries kass.carlosapp.dev, an instance-kind |
| + // route that is never metered and never hibernating, which renders "Not |
| + // responding" on every run of this page regardless of what this test |
| + // does — a page-wide Contains would pass even with the wrong route |
| + // hibernating. |
| + row := instanceRow(t, body, "owned.example.com") |
| + if !strings.Contains(row, "Not responding") || !strings.Contains(row, "no data") { |
| + t.Fatalf("stale box did not render as not responding with no data:\n%s", row) |
| } |
| for _, forbidden := range []string{"23%", "2.0 KB"} { |
| if strings.Contains(body, forbidden) { |