test(media): gate explicit cap3 topology (#168)

Preserve the cap2 baseline while requiring observed Host3 and relay3 topology in explicit cap3 benchmark runs.
This commit is contained in:
AAA authored and GitHub committed 2026-08-22 04:43:08 +08:00
1 parent b81aa75cda
commit 0389364731
3 files changed
+139 -15

No files matched your search

+5
View File
@@ -255,6 +255,11 @@ no fatal error. The run proves the two-child control path and bound on local
Chrome only. It does not prove shared encoding, CPU/GPU cost, visual quality,
games, mobile resources, public networking, or endurance.
The loopback runner retains cap2 by default; `BENCHMARK_EXPECTED_ENDPOINT_CAP=3`
configures only its local server and gate. A 2026-08-22 Chrome 151 two-second
smoke passed with three Viewers at Host2/relay1 and six at Host3/relay3, with all
Viewers decoding. This is not a production-default, SFU-capacity, or resource claim.
Peer multicast research such as SplitStream demonstrates why load-balanced,
failure-tolerant overlays normally introduce multiple trees and content
striping. Those mechanisms are intentionally excluded: needing them is a reason
+66 -14
View File
@@ -6,7 +6,11 @@ import { basename, dirname, isAbsolute, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import WebSocket from "ws";
import type { ParticipantRouteAssignment } from "../src/shared/protocol";
import {
DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES,
MAX_PEER_RELAY_DOWNSTREAM_EDGES,
type ParticipantRouteAssignment,
} from "../src/shared/protocol";
import {
createScreenerServer,
type ScreenerServer,
@@ -30,6 +34,7 @@ type PageRole = "host" | "viewer";
export interface BenchmarkConfig {
chromePath: string;
viewerCounts: number[];
expectedEndpointCap: number;
profileId: ProfileId;
durationMs: number;
settleMs: number;
@@ -358,6 +363,22 @@ function parseBoolean(value: string | undefined, fallback: boolean, name: string
throw new Error(`${name} must be true, false, 1, or 0`);
}
export function parseExpectedEndpointCap(value: string | undefined): number {
const parsed = value?.trim()
? Number(value)
: DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES;
if (
!Number.isSafeInteger(parsed) ||
parsed < DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES ||
parsed > MAX_PEER_RELAY_DOWNSTREAM_EDGES
) {
throw new Error(
`BENCHMARK_EXPECTED_ENDPOINT_CAP must be an integer from ${DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES} to ${MAX_PEER_RELAY_DOWNSTREAM_EDGES}`,
);
}
return parsed;
}
export function parseBenchmarkConfig(
environment: NodeJS.ProcessEnv = process.env,
): BenchmarkConfig {
@@ -395,6 +416,9 @@ export function parseBenchmarkConfig(
return {
chromePath,
viewerCounts,
expectedEndpointCap: parseExpectedEndpointCap(
environment.BENCHMARK_EXPECTED_ENDPOINT_CAP,
),
profileId,
durationMs:
parseNumber(
@@ -694,7 +718,12 @@ export function buildRunChecks(
summary: NonNullable<BenchmarkRun["summary"]>,
viewerCount: number,
profileId: ProfileId,
expectedEndpointCap = DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES,
): RunCheck[] {
const endpointCapObserved =
summary.maxHostAssignedChildren === expectedEndpointCap &&
(viewerCount < expectedEndpointCap * 2 ||
summary.maxRelayActiveMediaEdges === expectedEndpointCap);
const sfuConsistencyCheck: RunCheck = summary.sfuPublicationObserved
? {
name: "sfu-route-consistency",
@@ -712,22 +741,33 @@ export function buildRunChecks(
return [
{
name: "host-active-media-edges",
passed: summary.maxHostActiveMediaEdges <= 2,
passed: summary.maxHostActiveMediaEdges <= expectedEndpointCap,
actual: summary.maxHostActiveMediaEdges,
expected: "<= 2",
expected: `<= ${expectedEndpointCap}`,
},
{
name: "host-assigned-children",
passed: summary.maxHostAssignedChildren <= 2,
passed: summary.maxHostAssignedChildren <= expectedEndpointCap,
actual: summary.maxHostAssignedChildren,
expected: "<= 2",
expected: `<= ${expectedEndpointCap}`,
},
{
name: "relay-active-media-edges",
passed: summary.maxRelayActiveMediaEdges <= 2,
passed: summary.maxRelayActiveMediaEdges <= expectedEndpointCap,
actual: summary.maxRelayActiveMediaEdges,
expected: "<= 2",
expected: `<= ${expectedEndpointCap}`,
},
...(expectedEndpointCap > DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES &&
viewerCount >= expectedEndpointCap
? [
{
name: "endpoint-cap-observed",
passed: endpointCapObserved,
actual: endpointCapObserved,
expected: `${expectedEndpointCap} Host children and required relay fanout`,
},
]
: []),
{
name: "all-viewers-decoded",
passed: summary.everyViewerDecoded,
@@ -752,20 +792,23 @@ export function buildRunChecks(
];
}
export function buildRecoveryCheck(recovery: RecoveryResult): RunCheck {
export function buildRecoveryCheck(
recovery: RecoveryResult,
expectedEndpointCap = DEFAULT_PEER_RELAY_DOWNSTREAM_EDGES,
): RunCheck {
const passed =
recovery.triggered &&
recovery.error === undefined &&
recovery.recoveredAtEpochMs !== undefined &&
recovery.maxHostActiveMediaEdges !== undefined &&
recovery.maxHostActiveMediaEdges <= 2 &&
recovery.maxHostActiveMediaEdges <= expectedEndpointCap &&
recovery.maxHostAssignedChildren !== undefined &&
recovery.maxHostAssignedChildren <= 2;
recovery.maxHostAssignedChildren <= expectedEndpointCap;
return {
name: "relay-recovery-correctness",
passed,
actual: passed,
expected: "decoded frames resume with host media edges and assigned children <= 2",
expected: `decoded frames resume with host media edges and assigned children <= ${expectedEndpointCap}`,
};
}
@@ -777,6 +820,7 @@ export function buildBenchmarkInitScript(options: {
width: number;
height: number;
frameRate: number;
expectedEndpointCap: number;
}): string {
const serialized = JSON.stringify(options);
return `(() => {
@@ -835,7 +879,7 @@ export function buildBenchmarkInitScript(options: {
}
if (
!Array.isArray(value.childPeerIds) ||
value.childPeerIds.length > 2 ||
value.childPeerIds.length > options.expectedEndpointCap ||
!value.childPeerIds.every(isOpaqueId) ||
new Set(value.childPeerIds).size !== value.childPeerIds.length ||
(value.sfuPublicationGeneration !== null &&
@@ -2030,6 +2074,7 @@ async function runCase(
width: captureResolution.width,
height: captureResolution.height,
frameRate: capture.maxFramerate,
expectedEndpointCap: config.expectedEndpointCap,
};
const hostPage = await createPage(cdp, baseUrl, {
...commonInit,
@@ -2088,7 +2133,12 @@ async function runCase(
samples.push(await samplePages(cdp, pages, measurementStartedAt));
const summary = summarizeSamples(samples, viewerCount);
const checks = buildRunChecks(summary, viewerCount, config.profileId);
const checks = buildRunChecks(
summary,
viewerCount,
config.profileId,
config.expectedEndpointCap,
);
if (config.qualityControlSmoke && viewerCount >= 3) {
const qualityControl = await runQualityControlSmoke(
cdp,
@@ -2129,7 +2179,7 @@ async function runCase(
config.recoveryTimeoutMs,
signal,
);
checks.push(buildRecoveryCheck(recovery));
checks.push(buildRecoveryCheck(recovery, config.expectedEndpointCap));
}
return {
viewerCount,
@@ -2211,6 +2261,7 @@ export async function main(): Promise<number> {
},
configuration: {
viewerCounts: config.viewerCounts,
expectedEndpointCap: config.expectedEndpointCap,
profileId: config.profileId,
durationMs: config.durationMs,
settleMs: config.settleMs,
@@ -2266,6 +2317,7 @@ export async function main(): Promise<number> {
ALLOWED_ORIGINS: baseUrl,
ROOM_DATABASE_PATH: "",
PEER_ASSISTED_MEDIA: "true",
MAX_PEER_RELAY_DOWNSTREAM_EDGES: String(config.expectedEndpointCap),
MAX_VIEWERS_PER_ROOM: String(Math.max(...config.viewerCounts)),
STUN_URLS: "",
});
+68 -1
View File
@@ -11,6 +11,7 @@ import {
everyViewerRecoveredMedia,
mergeRecoveryHostPeaks,
parseBenchmarkConfig,
parseExpectedEndpointCap,
parseViewerCounts,
summarizeSamples,
} from "../scripts/peer-assisted-benchmark";
@@ -142,7 +143,7 @@ interface ObserverSnapshot {
maxAssignedChildren: number;
}
function createObserverHarness() {
function createObserverHarness(expectedEndpointCap = 2) {
const context: Record<string, unknown> = {
WebSocket: FakeWebSocket,
RTCPeerConnection: class FakePeerConnection {},
@@ -162,6 +163,7 @@ function createObserverHarness() {
width: 1280,
height: 720,
frameRate: 30,
expectedEndpointCap,
}).replace(
'const statsModule = import("/src/client/webrtc/stats.ts");',
"const statsModule = new Promise(() => undefined);",
@@ -230,6 +232,19 @@ describe("peer topology loopback configuration", () => {
).toThrow(/selected viewer count/);
});
it("keeps cap2 by default and accepts only an explicit cap3 expectation", () => {
expect(parseExpectedEndpointCap(undefined)).toBe(2);
for (const value of ["1", "2.5", "4"]) {
expect(() => parseExpectedEndpointCap(value)).toThrow(/integer from 2 to 3/);
}
expect(
parseBenchmarkConfig({
CHROME_PATH: "chrome",
BENCHMARK_EXPECTED_ENDPOINT_CAP: "3",
}).expectedEndpointCap,
).toBe(3);
});
it("requires a relay-sized case for the optional quality control smoke", () => {
expect(() =>
parseBenchmarkConfig({
@@ -298,6 +313,38 @@ describe("peer topology loopback observations", () => {
).toBe(true);
});
it("requires an explicit cap3 run to exercise cap3 fanout", () => {
const initial = [
page("host", "host", 3, 0),
...Array.from({ length: 6 }, (_, index) =>
page("viewer", `viewer-${index + 1}`, index === 0 ? 3 : 0, 1),
),
];
const final = structuredClone(initial);
for (const viewer of final.filter((entry) => entry.role === "viewer")) {
viewer.connections.at(-1)!.receiveTotals!.framesTotal = 20;
}
const summary = summarizeSamples(
[
{ atEpochMs: 2_000, elapsedMs: 0, pages: initial },
{ atEpochMs: 4_000, elapsedMs: 2_000, pages: final },
],
6,
);
const checks = buildRunChecks(summary, 6, "720p30", 3);
expect(checks.find((check) => check.name === "endpoint-cap-observed")?.passed).toBe(true);
const underused = {
...summary,
maxHostAssignedChildren: 2,
maxRelayActiveMediaEdges: 2,
};
expect(
buildRunChecks(underused, 6, "720p30", 3).find(
(check) => check.name === "endpoint-cap-observed",
)?.passed,
).toBe(false);
});
it("fails continuity when frames freeze or stats collection errors", () => {
const frozenInitial = [
page("host", "host", 1, 0),
@@ -830,6 +877,25 @@ describe("peer topology loopback observations", () => {
});
});
it("accepts a three-child route only for an explicit cap3 observer", () => {
const assignment = routeAssignment(["child_peer_0001", "child_peer_0002", "child_peer_0003"]);
for (const [cap, accepted] of [[2, false], [3, true]] as const) {
const observer = createObserverHarness(cap);
const socket = observer.socket();
authenticate(socket);
socket.emitMessage({
type: "authenticated",
role: "host",
peerId: "host_peer_0001",
mediaMode: "peer-assisted",
routeRevision: 1,
routeAssignment: assignment,
qualitySettings: lowQualitySettings,
});
expect(observer.snapshot().routeAssignment !== null).toBe(accepted);
}
});
it("clears hybrid state only from the current authenticated socket", () => {
const observer = createObserverHarness();
const previous = observer.socket();
@@ -891,6 +957,7 @@ describe("peer topology loopback observations", () => {
width: 1280,
height: 720,
frameRate: 30,
expectedEndpointCap: 2,
});
expect(source).toContain('"width":1280');
expect(source).toContain('"frameRate":30');