Files
warmbly/qa/flows/fleet-telemetry.flow.ts
T
2026-10-05 12:11:35 +00:00

86 lines
6.3 KiB
TypeScript

import { readFileSync } from "node:fs";
import { expect, test } from "../lib/proof.ts";
// Requires the isolated admin origin, seeded admin session, and ../fixtures/fleet-telemetry.sql.
test("fleet planning targets and measured resources remain distinct", async ({ page, proof }) => {
test.skip(process.env.QA_FLEET_FIXTURES !== "1", "Apply the localhost fleet fixtures and set QA_FLEET_FIXTURES=1.");
await page.goto("/fleet?tab=capacity");
await expect(page.getByRole("tab", { name: "Capacity", exact: true })).toHaveAttribute("aria-selected", "true");
const container = page.getByRole("row").filter({ has: page.getByRole("link", { name: "fixture-container", exact: true }) });
const host = page.getByRole("row").filter({ has: page.getByRole("link", { name: "fixture-host", exact: true }) });
const unavailable = page.getByRole("row").filter({ has: page.getByRole("link", { name: "fixture-unavailable", exact: true }) });
const stale = page.getByRole("row").filter({ has: page.getByRole("link", { name: "fixture-stale", exact: true }) });
await expect(container).toContainText("400 / 400");
await expect(container).toContainText("100% of plan");
await expect(container).toContainText("12.5%container");
await expect(container).toContainText("25.0%container");
await expect(container).toContainText("256 / 1,024 MiB");
await expect(container).toContainText("137 MiB");
await expect(container).toContainText("8.8.8.8");
await expect(container).toContainText("80.0%");
await expect(host).toContainText("100 / 400");
await expect(host).toContainText("25% of plan");
await expect(host).toContainText("7.5%host");
await expect(host).toContainText("4,096 / 16,384 MiB");
await expect(host).toContainText("80 MiB");
await expect(host).toContainText("20.0%");
await expect(unavailable.getByRole("cell", { name: "Unavailable", exact: true })).toHaveCount(4);
await expect(stale.getByRole("cell", { name: "Stale", exact: true })).toHaveCount(3);
await expect(stale).not.toContainText("999 MiB");
await proof.chapter("Planning is not saturation", "Local SQL telemetry fixtures, real API. Addresses and send counters are synthetic.");
await proof.shot("fleet-capacity-resources", { caption: "Local DB fixtures: 400/400 is 100% of plan, while container RAM is 25% and process RSS is 137 MiB. Host, unavailable and stale states remain distinct." });
await page.getByRole("button", { name: "Columns", exact: true }).click();
for (const name of ["Health", "Live", "Mailboxes"]) await page.getByRole("checkbox", { name, exact: true }).uncheck();
for (const name of ["Send share 60m", "Send success 60m", "Last heartbeat"]) await page.getByRole("checkbox", { name, exact: true }).check();
await page.getByRole("button", { name: "Columns", exact: true }).click();
await expect(container.getByRole("cell", { name: "80.0%", exact: true })).toHaveCount(2);
await expect(container.getByRole("cell", { name: "90.0%", exact: true })).toBeVisible();
await expect(host.getByRole("cell", { name: "20.0%", exact: true })).toHaveCount(2);
await expect(host.getByRole("cell", { name: "100.0%", exact: true })).toBeVisible();
await expect(unavailable.getByRole("cell", { name: "No attempts", exact: true })).toHaveCount(2);
await expect(unavailable.getByRole("cell", { name: "0.0%", exact: true })).toHaveCount(2);
await expect(page.getByRole("cell", { name: "Never", exact: true })).toHaveCount(2);
await proof.chapter("Shares and provider handoffs", "Synthetic 60m counters: 72/80 = 90% handoff success, not inbox placement.");
await proof.shot("fleet-capacity-shares", { caption: "Selectable shares and success rates, zero-attempt states, and heartbeat ages from local SQL fixtures." });
const downloadPromise = page.waitForEvent("download");
await page.getByRole("button", { name: "Export CSV", exact: true }).click();
const download = await downloadPromise;
const path = await download.path();
expect(path).toBeTruthy();
const csv = readFileSync(path!, "utf8");
expect(csv).toContain("Send share 60m");
expect(csv).toContain("Send success 60m");
expect(csv).toContain("Last heartbeat");
expect(csv.split("\n")[0]).not.toContain("Health");
expect(csv).toContain("400/400 (100% of plan)");
expect(csv).toContain("12.5% container");
expect(csv).toContain("256/1024 MiB container");
expect(csv).toMatch(/fixture-container[^\n]*137[^\n]*80.0[^\n]*80.0[^\n]*90.0/);
expect(csv).toMatch(/fixture-stale[^\n]*stale,stale,stale/);
await download.saveAs(`${proof.dir}/fleet-capacity.csv`);
await page.getByRole("link", { name: "fixture-container", exact: true }).click();
await expect(page.getByRole("heading", { name: "fixture-container", exact: true })).toBeVisible();
const properties = page.getByRole("complementary").filter({ has: page.getByRole("heading", { name: "Properties", exact: true }) });
await expect(properties).toContainText("8.8.8.8");
await expect(properties).toContainText("Mailbox target400");
await expect(properties).toContainText("12.5%container");
await expect(properties).toContainText("256 / 1,024 MiB");
await expect(properties).toContainText("137 MiB");
await proof.chapter("Worker resource detail", "The same persisted SQL fixture, not live process sampling.");
await proof.shot("fleet-worker-resources", { caption: "Worker detail preserves public-address display, mailbox target, CPU/RAM scope, and 137 MiB process RSS from the local fixture." });
await page.getByRole("link", { name: "Workers", exact: true }).click();
await expect(page.getByRole("table")).toBeVisible();
await page.getByRole("button", { name: "Columns", exact: true }).click();
for (const name of ["CPU", "RAM", "Process RAM"]) await page.getByRole("checkbox", { name, exact: true }).check();
await page.getByRole("button", { name: "Columns", exact: true }).click();
await expect(container).toContainText("12.5%container");
await expect(container).toContainText("256 / 1,024 MiB");
await expect(container).toContainText("137 MiB");
await expect(unavailable.getByRole("cell", { name: "Unavailable", exact: true })).toHaveCount(3);
await expect(stale.getByRole("cell", { name: "Stale", exact: true })).toHaveCount(3);
await proof.shot("fleet-explorer-resources", { caption: "Fleet explorer's CPU, RAM and process RSS columns agree with capacity and worker detail; all telemetry is a local SQL fixture." });
});