test(turn): add Coturn relay-path load test - #83
Conversation
Puppeteer test that forces iceTransportPolicy:"relay" so all viewer media flows through Coturn, verifies relay use via getStats candidateType, and ramps viewers to find the TURN relay ceiling — untested until now. - load-test/turn-relay-load.js — forces + verifies relay; per-batch CSV - load-test/results/TURN-RELAY-LOAD.md — how relay is forced/verified, Coturn sampling Authored by Claude (Anthropic) via Claude Code. Not executed against a live backend — results are placeholders, not fabricated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
There was a problem hiding this comment.
5 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="load-test/turn-relay-load.js">
<violation number="1" location="load-test/turn-relay-load.js:304">
P0: After sign-in, `window.__csSocket` is never populated, so `login()` always times out before launching the broadcaster or any viewer. Wait on the app's actual readiness signal or add an explicit test hook.</violation>
<violation number="2" location="load-test/turn-relay-load.js:358">
P0: After the Go live click, the application never sets `window.__csRoomId`, so `launchBroadcaster()` times out before creating viewers. Read the returned/rendered room ID or add an explicit test hook.</violation>
<violation number="3" location="load-test/turn-relay-load.js:425">
P1: The viewer page never sets either timing global, so every successful join is reported as a failure after up to 40 seconds of unnecessary waiting. Add timing hooks in the app or wait for observable socket/video readiness and record timestamps from those events.</violation>
<violation number="4" location="load-test/turn-relay-load.js:527">
P2: When `maxViewers` is not a multiple of `batchSize`, the test under-loads the requested ceiling or runs zero viewers. Size the final batch from the remaining `MAX_VIEWERS - viewers.length` capacity.</violation>
</file>
<file name="load-test/results/TURN-RELAY-LOAD.md">
<violation number="1" location="load-test/results/TURN-RELAY-LOAD.md:7">
P3: This doc points readers at `load-test/sfu-capacity.js` (roadmap claim on line 7 and prerequisite on line 76), but no such file exists in the repository — `git ls-files load-test/` contains only `signaling-latency.js` and `turn-relay-load.js`. A reader cannot find the referenced test, and the claim that the media plane is already exercised by it is misleading. Reference the actual existing load test (`signaling-latency.js`) or remove the claim that a media-plane test exists.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| console.log('Clicked "Go live".'); | ||
|
|
||
| await page.waitForFunction( | ||
| () => Boolean(window.__csRoomId), |
There was a problem hiding this comment.
P0: After the Go live click, the application never sets window.__csRoomId, so launchBroadcaster() times out before creating viewers. Read the returned/rendered room ID or add an explicit test hook.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/turn-relay-load.js, line 358:
<comment>After the Go live click, the application never sets `window.__csRoomId`, so `launchBroadcaster()` times out before creating viewers. Read the returned/rendered room ID or add an explicit test hook.</comment>
<file context>
@@ -0,0 +1,666 @@
+ console.log('Clicked "Go live".');
+
+ await page.waitForFunction(
+ () => Boolean(window.__csRoomId),
+ { timeout: WAIT_TIMEOUT_MS }
+ );
</file context>
|
|
||
| await page.waitForFunction( | ||
| () => | ||
| window.__csSocket && |
There was a problem hiding this comment.
P0: After sign-in, window.__csSocket is never populated, so login() always times out before launching the broadcaster or any viewer. Wait on the app's actual readiness signal or add an explicit test hook.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/turn-relay-load.js, line 304:
<comment>After sign-in, `window.__csSocket` is never populated, so `login()` always times out before launching the broadcaster or any viewer. Wait on the app's actual readiness signal or add an explicit test hook.</comment>
<file context>
@@ -0,0 +1,666 @@
+
+ await page.waitForFunction(
+ () =>
+ window.__csSocket &&
+ window.__csSocket.connected === true,
+ { timeout: WAIT_TIMEOUT_MS }
</file context>
| let joinedAt = null; | ||
| try { | ||
| await page.waitForFunction( | ||
| () => Boolean(window.__csJoinedAt), |
There was a problem hiding this comment.
P1: The viewer page never sets either timing global, so every successful join is reported as a failure after up to 40 seconds of unnecessary waiting. Add timing hooks in the app or wait for observable socket/video readiness and record timestamps from those events.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/turn-relay-load.js, line 425:
<comment>The viewer page never sets either timing global, so every successful join is reported as a failure after up to 40 seconds of unnecessary waiting. Add timing hooks in the app or wait for observable socket/video readiness and record timestamps from those events.</comment>
<file context>
@@ -0,0 +1,666 @@
+ let joinedAt = null;
+ try {
+ await page.waitForFunction(
+ () => Boolean(window.__csJoinedAt),
+ { timeout: WAIT_TIMEOUT_MS }
+ );
</file context>
| console.log("========================================"); | ||
|
|
||
| const batch = await Promise.all( | ||
| Array.from({ length: BATCH_SIZE }, (_, i) => |
There was a problem hiding this comment.
P2: When maxViewers is not a multiple of batchSize, the test under-loads the requested ceiling or runs zero viewers. Size the final batch from the remaining MAX_VIEWERS - viewers.length capacity.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/turn-relay-load.js, line 527:
<comment>When `maxViewers` is not a multiple of `batchSize`, the test under-loads the requested ceiling or runs zero viewers. Size the final batch from the remaining `MAX_VIEWERS - viewers.length` capacity.</comment>
<file context>
@@ -0,0 +1,666 @@
+ console.log("========================================");
+
+ const batch = await Promise.all(
+ Array.from({ length: BATCH_SIZE }, (_, i) =>
+ launchViewer(browser, roomId, viewers.length + i)
+ )
</file context>
|
|
||
| ## Roadmap gap this closes | ||
|
|
||
| CrowdStream's media plane is exercised end-to-end by `load-test/sfu-capacity.js`, |
There was a problem hiding this comment.
P3: This doc points readers at load-test/sfu-capacity.js (roadmap claim on line 7 and prerequisite on line 76), but no such file exists in the repository — git ls-files load-test/ contains only signaling-latency.js and turn-relay-load.js. A reader cannot find the referenced test, and the claim that the media plane is already exercised by it is misleading. Reference the actual existing load test (signaling-latency.js) or remove the claim that a media-plane test exists.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At load-test/results/TURN-RELAY-LOAD.md, line 7:
<comment>This doc points readers at `load-test/sfu-capacity.js` (roadmap claim on line 7 and prerequisite on line 76), but no such file exists in the repository — `git ls-files load-test/` contains only `signaling-latency.js` and `turn-relay-load.js`. A reader cannot find the referenced test, and the claim that the media plane is already exercised by it is misleading. Reference the actual existing load test (`signaling-latency.js`) or remove the claim that a media-plane test exists.</comment>
<file context>
@@ -0,0 +1,219 @@
+
+## Roadmap gap this closes
+
+CrowdStream's media plane is exercised end-to-end by `load-test/sfu-capacity.js`,
+but that test lets each client pick its cheapest ICE path — on a LAN that is
+almost always a **host** or **server-reflexive** candidate, so the SFU talks to
</file context>
| CrowdStream's media plane is exercised end-to-end by `load-test/sfu-capacity.js`, | |
| CrowdStream's media plane is not currently exercised end-to-end by any load test; the only existing load test is `load-test/signaling-latency.js`, |



Puppeteer test that forces iceTransportPolicy:"relay" so all viewer media flows through Coturn, verifies relay use via getStats candidateType, and ramps viewers to find the TURN relay ceiling — untested until now.
Authored by Claude (Anthropic) via Claude Code. Not executed against a live backend — results are placeholders, not fabricated.
Summary by cubic
Adds a relay-path load test that forces every viewer's media through Coturn and verifies the relay is actually used, closing the gap where the existing SFU capacity test never exercised Coturn on a LAN.
Test mechanics
RTCPeerConnectionto mergeiceTransportPolicy: "relay"into the app's config — no frontend or backend changes.candidateType === 'relay'.load-test/results/TURN-RELAY-LOAD.mddocuments how relay is forced and verified, plus Coturn-side sampling commands.Not yet run against a live backend — results in the markdown are placeholders, not fabricated. Credentials are passed via flags or environment variables, never hardcoded.
Written for commit f7ec67f. Summary will update on new commits.