feat(observability): add diagnostic dashboards (#27)
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
import {
|
||||
SessionProjection,
|
||||
buildBrowseUrl,
|
||||
buildStreamUrl,
|
||||
chooseSnapshotTransport,
|
||||
safeText,
|
||||
} from "../../src/FinalFactory.Rendezvous.Server/Diagnostics/Assets/app.mjs";
|
||||
|
||||
const cursor = "rvs1.test-cursor";
|
||||
|
||||
function session(id, name = `Host ${id}`) {
|
||||
return {
|
||||
contractVersion: 1,
|
||||
listingId: `00000000-0000-0000-0000-${String(id).padStart(12, "0")}`,
|
||||
gameId: "space-game",
|
||||
environmentId: "smoke",
|
||||
regionId: "local",
|
||||
protocolVersion: 1,
|
||||
buildVersion: "1.0.0",
|
||||
displayName: name,
|
||||
visibility: "public",
|
||||
publisherTrustMode: "managedDedicated",
|
||||
capacity: { currentPlayers: 1, maximumPlayers: 8 },
|
||||
metadata: { mode: "online-coop" },
|
||||
};
|
||||
}
|
||||
|
||||
function event(kind, values = {}) {
|
||||
return {
|
||||
contractVersion: 1,
|
||||
kind,
|
||||
cursor: values.cursor ?? cursor,
|
||||
session: values.session ?? null,
|
||||
listingId: values.listingId ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
test("snapshot and ordered deltas match the final public projection", () => {
|
||||
const projection = new SessionProjection(10);
|
||||
assert.equal(projection.replace([session(1)], cursor), "applied");
|
||||
assert.equal(projection.apply(event("sessionUpsert", {
|
||||
cursor: `${cursor}-2`,
|
||||
session: session(2),
|
||||
})), "applied");
|
||||
assert.equal(projection.apply(event("sessionUpsert", {
|
||||
cursor: `${cursor}-3`,
|
||||
session: session(1, "Updated host"),
|
||||
})), "applied");
|
||||
assert.equal(projection.apply(event("sessionRemove", {
|
||||
cursor: `${cursor}-4`,
|
||||
listingId: session(2).listingId,
|
||||
})), "applied");
|
||||
|
||||
assert.deepEqual(
|
||||
projection.sessions().map((entry) => entry.session.displayName),
|
||||
["Updated host"],
|
||||
);
|
||||
assert.equal(projection.cursor, `${cursor}-4`);
|
||||
});
|
||||
|
||||
test("reset, malformed events, and a partial snapshot fail closed", () => {
|
||||
const projection = new SessionProjection(2);
|
||||
assert.equal(projection.replace([session(1)], cursor, true), "applied");
|
||||
assert.equal(projection.apply(event("sessionRemove", {
|
||||
listingId: session(1).listingId,
|
||||
})), "refresh");
|
||||
assert.equal(projection.apply(event("reset")), "reset");
|
||||
assert.equal(projection.apply({ kind: "sessionUpsert" }), "invalid");
|
||||
assert.equal(projection.replace([session(1), session(2), session(3)], cursor), "overflow");
|
||||
});
|
||||
|
||||
test("bursts coalesce by listing identity and memory stays bounded", () => {
|
||||
const projection = new SessionProjection(2);
|
||||
assert.equal(projection.replace([], cursor), "applied");
|
||||
for (let index = 0; index < 1_000; index += 1) {
|
||||
assert.equal(projection.apply(event("sessionUpsert", {
|
||||
cursor: `${cursor}-${index}`,
|
||||
session: session(1, `Host ${index}`),
|
||||
})), "applied");
|
||||
}
|
||||
assert.equal(projection.sessions().length, 1);
|
||||
assert.equal(projection.sessions()[0].session.displayName, "Host 999");
|
||||
assert.equal(projection.apply(event("sessionUpsert", { session: session(2) })), "applied");
|
||||
assert.equal(projection.apply(event("sessionUpsert", { session: session(3) })), "overflow");
|
||||
assert.equal(projection.sessions().length, 2);
|
||||
});
|
||||
|
||||
test("requests are fixed same-origin paths with an exact configured filter", () => {
|
||||
const filter = {
|
||||
gameId: "space-game",
|
||||
environmentId: "smoke",
|
||||
protocolVersion: 1,
|
||||
regionId: "local",
|
||||
excludeFull: true,
|
||||
};
|
||||
const browse = buildBrowseUrl(filter);
|
||||
const stream = buildStreamUrl(filter, cursor);
|
||||
assert.match(browse, /^\/v1\/sessions\?/u);
|
||||
assert.match(stream, /^\/v1\/sessions\/stream\?/u);
|
||||
assert.match(browse, /gameId=space-game/u);
|
||||
assert.match(browse, /environmentId=smoke/u);
|
||||
assert.match(stream, /streamCursor=rvs1.test-cursor/u);
|
||||
assert.doesNotMatch(browse, /https?:/u);
|
||||
assert.doesNotMatch(stream, /https?:/u);
|
||||
});
|
||||
|
||||
test("snapshot transport preserves deliberate polling and bounds partial snapshots", () => {
|
||||
assert.equal(chooseSnapshotTransport(false, false), "stream");
|
||||
assert.equal(chooseSnapshotTransport(true, false), "boundedPolling");
|
||||
assert.equal(chooseSnapshotTransport(false, true), "pollingOnly");
|
||||
assert.equal(chooseSnapshotTransport(true, true), "pollingOnly");
|
||||
});
|
||||
|
||||
test("hostile display data remains literal text and no unsafe DOM sink exists", async () => {
|
||||
const payload = `<img src=x onerror=alert(1)><style>body{display:none}</style><a href=//evil>go</a>`;
|
||||
assert.equal(safeText(payload, 200), payload);
|
||||
const source = await readFile(new URL(
|
||||
"../../src/FinalFactory.Rendezvous.Server/Diagnostics/Assets/app.mjs",
|
||||
import.meta.url,
|
||||
), "utf8");
|
||||
for (const forbidden of [
|
||||
"innerHTML",
|
||||
"outerHTML",
|
||||
"insertAdjacentHTML",
|
||||
"document.write",
|
||||
"eval(",
|
||||
"new Function",
|
||||
"window.location",
|
||||
]) {
|
||||
assert.equal(source.includes(forbidden), false, `unsafe browser sink: ${forbidden}`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user