89 lines
4.2 KiB
JavaScript
89 lines
4.2 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { randomUUID } from "node:crypto";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
boundedBody,
|
|
eventCollector,
|
|
exportSession,
|
|
queryRecords,
|
|
redactHeaders,
|
|
safeUrl,
|
|
shouldRetryStartup,
|
|
summarizeProcessSamples,
|
|
} from "../scripts/m0-spike.mjs";
|
|
|
|
test("export policy redacts credentials and bounds bodies", () => {
|
|
const sensitive = randomUUID();
|
|
assert.deepEqual(redactHeaders({ Cookie: sensitive, Authorization: sensitive, Referer: "https://example.test/private", "Set-Cookie": sensitive, Accept: "*/*" }), {
|
|
accept: "*/*",
|
|
authorization: "[REDACTED]",
|
|
cookie: "[REDACTED]",
|
|
referer: "[REDACTED]",
|
|
"set-cookie": "[REDACTED]",
|
|
});
|
|
assert.equal(safeUrl("https://example.test/path?token=secret"), "https://example.test/path?<redacted>");
|
|
assert.deepEqual(boundedBody(sensitive, false, 100), { state: "fetched", source: "network", encoding: "utf8", storage: "omitted", reason: "default_body_policy", bytes: Buffer.byteLength(sensitive) });
|
|
assert(!JSON.stringify(boundedBody(sensitive, false, 100)).includes(sensitive));
|
|
assert.deepEqual(boundedBody("AP8=", true, 10, "memory_cache"), { state: "fetched", source: "memory_cache", encoding: "base64", storage: "omitted", reason: "default_body_policy", bytes: 2 });
|
|
assert.deepEqual(boundedBody("hello!", false, 5), { state: "size_limit", source: "network", encoding: "utf8", storage: "omitted", reason: "size_limit", bytes: 6 });
|
|
assert(shouldRetryStartup("Render process gone."));
|
|
assert(!shouldRetryStartup("Target closed."));
|
|
assert(!shouldRetryStartup(undefined));
|
|
});
|
|
|
|
test("cache state stays unknown without a preceding request event", () => {
|
|
const collector = eventCollector("session-a", "target-a");
|
|
collector.listener("Network.responseReceived", {
|
|
requestId: "orphan-response",
|
|
response: { url: "https://example.test/favicon.ico", status: 200, protocol: "h2", mimeType: "image/x-icon", headers: {} },
|
|
});
|
|
assert.deepEqual(collector.records[0].response.cache, { state: "unknown" });
|
|
});
|
|
|
|
test("WebSocket limits aggregate drops without payloads", () => {
|
|
const collector = eventCollector("session-a", "target-a", {
|
|
maxWebSocketFrameBytes: 4,
|
|
maxWebSocketEventsPerSecond: 1,
|
|
maxWebSocketEventsPerConnection: 2,
|
|
});
|
|
const frame = (method, payloadData, timestamp, opcode = 1) => collector.listener(method, { requestId: "ws-1", timestamp, response: { opcode, payloadData } });
|
|
frame("Network.webSocketFrameSent", "okay", 1.1);
|
|
frame("Network.webSocketFrameReceived", "x", 1.2);
|
|
frame("Network.webSocketFrameReceived", "YWJjZGVm", 2.1, 2);
|
|
frame("Network.webSocketFrameSent", "ok", 2.2);
|
|
frame("Network.webSocketFrameSent", "ok", 3.1);
|
|
frame("Network.webSocketFrameSent", "ok", 4.1);
|
|
|
|
assert.equal(collector.records.filter((record) => record.kind === "websocket_frame").length, 2);
|
|
const dropped = collector.records.find((record) => record.kind === "websocket_frames_dropped");
|
|
assert.deepEqual(dropped.dropped.reasons, { rate_limit: 2, frame_size_limit: 1, event_limit: 1 });
|
|
assert.equal(dropped.dropped.count, 4);
|
|
assert(!JSON.stringify(dropped).includes("YWJjZGVm"));
|
|
});
|
|
|
|
test("query and export isolate sessions before pagination", () => {
|
|
const records = [
|
|
{ session_id: "a", target_id: "a1", value: 1 },
|
|
{ session_id: "b", target_id: "b1", value: 2 },
|
|
{ session_id: "a", target_id: "a1", value: 3 },
|
|
];
|
|
assert.deepEqual(queryRecords(records, "a", { limit: 1 }), { items: [records[0]], next_cursor: 1 });
|
|
assert.deepEqual(queryRecords(records, "a", { cursor: 1, limit: 1 }), { items: [records[2]], next_cursor: null });
|
|
assert(!exportSession(records, "a").includes('"session_id":"b"'));
|
|
});
|
|
|
|
test("resource baseline summarizes repeated samples", () => {
|
|
assert.deepEqual(summarizeProcessSamples([
|
|
{ process_count: 8, rss_kib: 700_000, cpu_percent_snapshot: 10 },
|
|
{ process_count: 9, rss_kib: 800_000, cpu_percent_snapshot: 20 },
|
|
{ process_count: 9, rss_kib: 900_000, cpu_percent_snapshot: 30 },
|
|
], 200), {
|
|
sample_count: 3,
|
|
interval_ms: 200,
|
|
process_count: { min: 8, max: 9 },
|
|
rss_kib: { min: 700_000, max: 900_000, mean: 800_000, p95: 900_000 },
|
|
cpu_percent: { min: 10, max: 30, mean: 20, p95: 30 },
|
|
});
|
|
});
|