Skip to content

Commit 714aacd

Browse files
committed
feat: add tests for easy to test devin-discovered edge cases
1 parent d00a938 commit 714aacd

2 files changed

Lines changed: 77 additions & 2 deletions

File tree

packages/livekit-rtc/src/tests/e2e_common.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AccessToken } from 'livekit-server-sdk';
55
import { randomUUID } from 'node:crypto';
66
import { setTimeout as delay } from 'node:timers/promises';
77
import { describe } from 'vitest';
8-
import { Room, type RoomEvent } from '../index.js';
8+
import { Room, type RoomDataStreamOptions, type RoomEvent } from '../index.js';
99

1010
export const hasE2EEnv =
1111
!!process.env.LIVEKIT_URL && !!process.env.LIVEKIT_API_KEY && !!process.env.LIVEKIT_API_SECRET;
@@ -91,6 +91,8 @@ export async function createJoinToken(params: {
9191

9292
export async function connectTestRooms(
9393
count: number,
94+
/** Extra room options applied to every room, e.g. data stream limits. */
95+
options?: { dataStream?: RoomDataStreamOptions },
9496
): Promise<{ roomName: string; rooms: Room[] }> {
9597
const env = getTestEnv();
9698
const roomName = `test_room_${randomUUID()}`;
@@ -103,7 +105,11 @@ export async function connectTestRooms(
103105
name: `Participant ${i}`,
104106
});
105107
const room = new Room();
106-
await room.connect(env.url, token, { autoSubscribe: true, dynacast: false });
108+
await room.connect(env.url, token, {
109+
autoSubscribe: true,
110+
dynacast: false,
111+
...options,
112+
});
107113
return room;
108114
}),
109115
);

packages/livekit-rtc/src/tests/e2e_data_streams.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,4 +532,73 @@ describeE2E('livekit-rtc data streams e2e', () => {
532532
},
533533
testTimeoutMs,
534534
);
535+
536+
it(
537+
'reads a closed reader as an empty stream',
538+
async () => {
539+
const { rooms } = await connectTestRooms(2);
540+
const [receivingRoom, sendingRoom] = rooms;
541+
const topic = 'read-after-close-topic';
542+
543+
const handed = withTimeout(
544+
new Promise<TextStreamReader>((resolve) => {
545+
receivingRoom!.registerTextStreamHandler(topic, async (reader) => {
546+
resolve(reader); // never read
547+
});
548+
}),
549+
testTimeoutMs,
550+
'Timed out waiting for the stream handler to be called',
551+
);
552+
553+
const writer = await sendingRoom!.localParticipant!.streamText({ topic });
554+
await writer.write('never consumed');
555+
556+
const reader = await handed;
557+
await reader.close();
558+
559+
const text = await withTimeout(
560+
reader.readAll(),
561+
testTimeoutMs,
562+
'Timed out reading a closed reader',
563+
);
564+
expect(text).toBe('');
565+
566+
await writer.close();
567+
await Promise.all(rooms.map((r) => r.disconnect()));
568+
},
569+
testTimeoutMs,
570+
);
571+
572+
// `dataStream.maxPayloadByteLength` caps what a receiver will accept (5gb by
573+
// default). The native side emits the stream to the handler first and then
574+
// fails it, so the error surfaces on the read rather than as a missing stream.
575+
it(
576+
'fails the read when an incoming stream exceeds maxPayloadByteLength',
577+
async () => {
578+
const maxPayloadByteLength = 1000;
579+
const { rooms } = await connectTestRooms(2, { dataStream: { maxPayloadByteLength } });
580+
const [receivingRoom, sendingRoom] = rooms;
581+
const topic = 'oversized-topic';
582+
583+
const handed = withTimeout(
584+
new Promise<TextStreamReader>((resolve) => {
585+
receivingRoom!.registerTextStreamHandler(topic, resolve);
586+
}),
587+
testTimeoutMs,
588+
'Timed out waiting for the oversized stream to be handed to the handler',
589+
);
590+
591+
// sendText declares the payload's total length up front, so the receiver
592+
// rejects the stream on the header without reading any of it.
593+
await sendingRoom!.localParticipant!.sendText(pseudoRandomText(maxPayloadByteLength * 5), {
594+
topic,
595+
});
596+
597+
const reader = await handed;
598+
await expect(reader.readAll()).rejects.toThrow(/payload exceeds maximum size/);
599+
600+
await Promise.all(rooms.map((r) => r.disconnect()));
601+
},
602+
testTimeoutMs,
603+
);
535604
});

0 commit comments

Comments
 (0)