mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-15 08:02:42 +00:00
79 lines
5.0 KiB
TypeScript
79 lines
5.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { NodeBrokerSource, NodeLogEvent } from "@/lib/api/client/admin/nodeDiagnostics";
|
|
import { emptyLogFilters, logFilterError, parseLogFilters, safeLogEvent, validatedBroker } from "./nodeDiagnostics";
|
|
|
|
const id = "11111111-1111-4111-8111-111111111111";
|
|
const group = `worker-${id}`;
|
|
const topic = `w.${id}`;
|
|
const at = "2026-10-10T08:00:00Z";
|
|
function source(): NodeBrokerSource {
|
|
return {
|
|
id, availability: "fresh", coverage: "complete", observed_at: at, checked_at: at, measured_scopes: 1, expected_scopes: 1,
|
|
metrics: [{ id: "committed_lag", title: "Broker committed_lag", unit: "messages", scope_id: id, availability: "fresh", condition: "unknown", severity: "info", note: "Observation only", count: 6,
|
|
observed_at: at, evidence_at: at, latest_evidence_at: at, affected_mailboxes: null, affected_organizations: null, unknown_organization_rows: null, evidence_age_seconds: null, next_eligible_at: null, window_start: null, window_end: null, threshold_seconds: null,
|
|
broker: { consumer_group: group, topics: [topic], partitions: [{ topic, partition: 0, earliest: 10, committed: 16, latest: 22, committed_lag: 6 }] },
|
|
}],
|
|
};
|
|
}
|
|
|
|
describe("read-only node broker evidence", () => {
|
|
it("accepts exact retained committed offsets, not send rates or invented member counts", () => {
|
|
const result = validatedBroker(source(), group, topic);
|
|
expect(result?.lag).toBe(6);
|
|
expect(result?.members).toBeNull();
|
|
});
|
|
it("keeps validated zero lag distinct from an unsupported observation", () => {
|
|
const zero = source();
|
|
zero.metrics[0].count = 0;
|
|
zero.metrics[0].broker!.partitions[0].committed = 22;
|
|
zero.metrics[0].broker!.partitions[0].committed_lag = 0;
|
|
expect(validatedBroker(zero, group, topic)?.lag).toBe(0);
|
|
expect(validatedBroker({ ...zero, availability: "unavailable", metrics: [], reason: "unsupported" }, group, topic)).toBeNull();
|
|
});
|
|
it.each(["stale", "unavailable"] as const)("does not render %s observations as fresh values", (availability) => {
|
|
expect(validatedBroker({ ...source(), availability }, group, topic)).toBeNull();
|
|
});
|
|
it("does not attribute the shared result group to worker commands", () => {
|
|
expect(validatedBroker(source(), "consumer-group", "jobs.worker-events")).toBeNull();
|
|
});
|
|
it.each(["missing", "duplicate", "negative", "out-of-retention", "future-commit", "mismatch", "wrong-topic", "wrong-group", "overflow", "unsafe-offset", "healthy-condition", "wrong-scope", "partial"])("withholds %s data", (invalid) => {
|
|
const value = source();
|
|
const metric = value.metrics[0];
|
|
const detail = metric.broker!;
|
|
const partition = detail.partitions[0];
|
|
switch (invalid) {
|
|
case "missing": metric.count = null; break;
|
|
case "duplicate": detail.partitions.push({ ...partition }); break;
|
|
case "negative": partition.partition = -1; break;
|
|
case "out-of-retention": partition.committed = 9; break;
|
|
case "future-commit": partition.committed = 23; break;
|
|
case "mismatch": metric.count = 7; break;
|
|
case "wrong-topic": partition.topic = "unexpected"; break;
|
|
case "wrong-group": detail.consumer_group = "consumer-group"; break;
|
|
case "overflow": detail.partitions = Array.from({ length: 129 }, (_, i) => ({ ...partition, partition: i })); break;
|
|
case "unsafe-offset": partition.latest = Number.MAX_SAFE_INTEGER + 1; break;
|
|
case "healthy-condition": metric.condition = "healthy"; break;
|
|
case "wrong-scope": metric.scope_id = "other"; break;
|
|
case "partial": value.coverage = "partial"; break;
|
|
}
|
|
expect(validatedBroker(value, group, topic)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("redacted node evidence and filters", () => {
|
|
it("only accepts canonical allowlisted event records", () => {
|
|
const event: NodeLogEvent = { id, event: "sync_control_plane_held", observed_at: at, level: "warn", category: "control_plane", http_status: 503 };
|
|
expect(safeLogEvent(event)).toBe(true);
|
|
expect(safeLogEvent({ ...event, event: "raw_provider_message" })).toBe(false);
|
|
expect(safeLogEvent({ ...event, category: "provider" })).toBe(false);
|
|
expect(safeLogEvent({ ...event, observed_at: "invalid" })).toBe(false);
|
|
});
|
|
it("strips unrelated stored fields and rejects invalid UUID/time ranges", () => {
|
|
expect(parseLogFilters({ ...emptyLogFilters, level: "warn", secret: "not-stored" })).toEqual({ ...emptyLogFilters, level: "warn" });
|
|
expect(parseLogFilters({ ...emptyLogFilters, mailbox: "not-a-uuid" })).toBeNull();
|
|
expect(parseLogFilters({ ...emptyLogFilters, after: "invalid" })).toBeNull();
|
|
expect(logFilterError({ ...emptyLogFilters, after: "2026-10-10T10:00", before: "2026-10-10T09:00" })).toMatch(/Start time/);
|
|
expect(logFilterError({ ...emptyLogFilters, mailbox: id, after: "2026-10-10T08:00" })).toBeNull();
|
|
});
|
|
});
|