@durable-streams/server-conformance-tests 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- const require_src = require('./src-CfXXlBaO.cjs');
1
+ const require_src = require('./src-CMFxsR_X.cjs');
2
2
 
3
3
  exports.runConformanceTests = require_src.runConformanceTests
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { runConformanceTests } from "./src-GWuAOela.js";
1
+ import { runConformanceTests } from "./src-Pd7PHJOG.js";
2
2
 
3
3
  export { runConformanceTests };
@@ -894,6 +894,8 @@ function runConformanceTests(options) {
894
894
  (0, vitest.expect)(text).toBe(``);
895
895
  (0, vitest.expect)(response.headers.get(__durable_streams_client.STREAM_UP_TO_DATE_HEADER)).toBe(`true`);
896
896
  (0, vitest.expect)(response.headers.get(__durable_streams_client.STREAM_OFFSET_HEADER)).toBeDefined();
897
+ const cacheControl = response.headers.get(`cache-control`);
898
+ (0, vitest.expect)(cacheControl).toContain(`no-store`);
897
899
  });
898
900
  (0, vitest.test)(`should return correct tail offset for offset=now`, async () => {
899
901
  const streamPath = `/v1/stream/offset-now-tail-test-${Date.now()}`;
@@ -1014,7 +1016,7 @@ function runConformanceTests(options) {
1014
1016
  const tailOffset = readResponse.headers.get(__durable_streams_client.STREAM_OFFSET_HEADER);
1015
1017
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=now&live=sse`, { untilContent: `"upToDate"` });
1016
1018
  (0, vitest.expect)(response.status).toBe(200);
1017
- const controlMatch = received.match(/event: control\s*\n\s*data: ({[^}]+})/);
1019
+ const controlMatch = received.match(/event: control\s*\n\s*data:({[^}]+})/);
1018
1020
  (0, vitest.expect)(controlMatch).toBeDefined();
1019
1021
  if (controlMatch && controlMatch[1]) {
1020
1022
  const controlData = JSON.parse(controlMatch[1]);
@@ -1066,7 +1068,7 @@ function runConformanceTests(options) {
1066
1068
  });
1067
1069
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=now&live=sse`, { untilContent: `"upToDate"` });
1068
1070
  (0, vitest.expect)(response.status).toBe(200);
1069
- const controlMatch = received.match(/event: control\s*\n\s*data: ({[^}]+})/);
1071
+ const controlMatch = received.match(/event: control\s*\n\s*data:({[^}]+})/);
1070
1072
  (0, vitest.expect)(controlMatch).toBeDefined();
1071
1073
  if (controlMatch && controlMatch[1]) {
1072
1074
  const controlData = JSON.parse(controlMatch[1]);
@@ -1343,6 +1345,20 @@ function runConformanceTests(options) {
1343
1345
  (0, vitest.expect)(cursor).not.toBeNull();
1344
1346
  (0, vitest.expect)(/^\d+$/.test(cursor)).toBe(true);
1345
1347
  });
1348
+ (0, vitest.test)(`should return immediately with Stream-Up-To-Date when data exists at offset`, async () => {
1349
+ const streamPath = `/v1/stream/longpoll-immediate-uptodate-test-${Date.now()}`;
1350
+ await fetch(`${getBaseUrl()}${streamPath}`, {
1351
+ method: `PUT`,
1352
+ headers: { "Content-Type": `text/plain` },
1353
+ body: `existing data`
1354
+ });
1355
+ const response = await fetch(`${getBaseUrl()}${streamPath}?offset=-1&live=long-poll`, { method: `GET` });
1356
+ (0, vitest.expect)(response.status).toBe(200);
1357
+ const text = await response.text();
1358
+ (0, vitest.expect)(text).toBe(`existing data`);
1359
+ (0, vitest.expect)(response.headers.get(__durable_streams_client.STREAM_UP_TO_DATE_HEADER)).toBe(`true`);
1360
+ (0, vitest.expect)(response.headers.get(__durable_streams_client.STREAM_OFFSET_HEADER)).toBeDefined();
1361
+ });
1346
1362
  (0, vitest.test)(`should echo cursor and handle collision with jitter`, async () => {
1347
1363
  const streamPath = `/v1/stream/longpoll-cursor-collision-test-${Date.now()}`;
1348
1364
  await fetch(`${getBaseUrl()}${streamPath}`, {
@@ -1969,7 +1985,7 @@ function runConformanceTests(options) {
1969
1985
  });
1970
1986
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `streamCursor` });
1971
1987
  (0, vitest.expect)(response.status).toBe(200);
1972
- const controlMatch = received.match(/event: control\s*\ndata: ({[^}]+})/);
1988
+ const controlMatch = received.match(/event: control\s*\ndata:({[^}]+})/);
1973
1989
  (0, vitest.expect)(controlMatch).toBeDefined();
1974
1990
  const controlData = JSON.parse(controlMatch[1]);
1975
1991
  (0, vitest.expect)(controlData.streamCursor).toBeDefined();
@@ -1983,11 +1999,11 @@ function runConformanceTests(options) {
1983
1999
  body: `test data`
1984
2000
  });
1985
2001
  const { received: received1 } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `streamCursor` });
1986
- const controlMatch1 = received1.match(/event: control\s*\ndata: ({[^}]+})/);
2002
+ const controlMatch1 = received1.match(/event: control\s*\ndata:({[^}]+})/);
1987
2003
  (0, vitest.expect)(controlMatch1).toBeDefined();
1988
2004
  const cursor1 = JSON.parse(controlMatch1[1]).streamCursor;
1989
2005
  const { received: received2 } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse&cursor=${cursor1}`, { untilContent: `streamCursor` });
1990
- const controlMatch2 = received2.match(/event: control\s*\ndata: ({[^}]+})/);
2006
+ const controlMatch2 = received2.match(/event: control\s*\ndata:({[^}]+})/);
1991
2007
  (0, vitest.expect)(controlMatch2).toBeDefined();
1992
2008
  const cursor2 = JSON.parse(controlMatch2[1]).streamCursor;
1993
2009
  (0, vitest.expect)(parseInt(cursor2, 10)).toBeGreaterThan(parseInt(cursor1, 10));
@@ -2027,9 +2043,9 @@ function runConformanceTests(options) {
2027
2043
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `event: control` });
2028
2044
  (0, vitest.expect)(response.status).toBe(200);
2029
2045
  (0, vitest.expect)(received).toContain(`event: control`);
2030
- const controlLine = received.split(`\n`).find((l) => l.startsWith(`data: `) && l.includes(`streamNextOffset`));
2046
+ const controlLine = received.split(`\n`).find((l) => l.startsWith(`data:`) && l.includes(`streamNextOffset`));
2031
2047
  (0, vitest.expect)(controlLine).toBeDefined();
2032
- const controlPayload = controlLine.slice(`data: `.length);
2048
+ const controlPayload = controlLine.slice(`data:`.length);
2033
2049
  const controlData = JSON.parse(controlPayload);
2034
2050
  (0, vitest.expect)(controlData[`streamNextOffset`]).toBe(httpOffset);
2035
2051
  });
@@ -2042,9 +2058,9 @@ function runConformanceTests(options) {
2042
2058
  });
2043
2059
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `"upToDate"` });
2044
2060
  (0, vitest.expect)(response.status).toBe(200);
2045
- const controlLine = received.split(`\n`).find((l) => l.startsWith(`data: `) && l.includes(`streamNextOffset`));
2061
+ const controlLine = received.split(`\n`).find((l) => l.startsWith(`data:`) && l.includes(`streamNextOffset`));
2046
2062
  (0, vitest.expect)(controlLine).toBeDefined();
2047
- const controlPayload = controlLine.slice(`data: `.length);
2063
+ const controlPayload = controlLine.slice(`data:`.length);
2048
2064
  const controlData = JSON.parse(controlPayload);
2049
2065
  (0, vitest.expect)(controlData.upToDate).toBe(true);
2050
2066
  });
@@ -2072,9 +2088,9 @@ function runConformanceTests(options) {
2072
2088
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `event: control` });
2073
2089
  (0, vitest.expect)(response.status).toBe(200);
2074
2090
  (0, vitest.expect)(received).toContain(`event: data`);
2075
- (0, vitest.expect)(received).toContain(`data: line1`);
2076
- (0, vitest.expect)(received).toContain(`data: line2`);
2077
- (0, vitest.expect)(received).toContain(`data: line3`);
2091
+ (0, vitest.expect)(received).toContain(`data:line1`);
2092
+ (0, vitest.expect)(received).toContain(`data:line2`);
2093
+ (0, vitest.expect)(received).toContain(`data:line3`);
2078
2094
  });
2079
2095
  (0, vitest.test)(`should prevent CRLF injection in payloads - embedded event boundaries become literal data`, async () => {
2080
2096
  const streamPath = `/v1/stream/sse-crlf-injection-test-${Date.now()}`;
@@ -2171,10 +2187,10 @@ function runConformanceTests(options) {
2171
2187
  });
2172
2188
  const { response, received } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `event: control` });
2173
2189
  (0, vitest.expect)(response.status).toBe(200);
2174
- const controlLines = received.split(`\n`).filter((l) => l.startsWith(`data: `) && l.includes(`streamNextOffset`));
2190
+ const controlLines = received.split(`\n`).filter((l) => l.startsWith(`data:`) && l.includes(`streamNextOffset`));
2175
2191
  const offsets = [];
2176
2192
  for (const line of controlLines) {
2177
- const payload = line.slice(`data: `.length);
2193
+ const payload = line.slice(`data:`.length);
2178
2194
  const data = JSON.parse(payload);
2179
2195
  offsets.push(data[`streamNextOffset`]);
2180
2196
  }
@@ -2195,8 +2211,8 @@ function runConformanceTests(options) {
2195
2211
  let lastOffset = null;
2196
2212
  const { response: response1, received: received1 } = await fetchSSE(`${getBaseUrl()}${streamPath}?offset=-1&live=sse`, { untilContent: `event: control` });
2197
2213
  (0, vitest.expect)(response1.status).toBe(200);
2198
- const controlLine = received1.split(`\n`).find((l) => l.startsWith(`data: `) && l.includes(`streamNextOffset`));
2199
- const controlPayload = controlLine.slice(`data: `.length);
2214
+ const controlLine = received1.split(`\n`).find((l) => l.startsWith(`data:`) && l.includes(`streamNextOffset`));
2215
+ const controlPayload = controlLine.slice(`data:`.length);
2200
2216
  lastOffset = JSON.parse(controlPayload)[`streamNextOffset`];
2201
2217
  (0, vitest.expect)(lastOffset).toBeDefined();
2202
2218
  await fetch(`${getBaseUrl()}${streamPath}`, {
@@ -2260,7 +2276,7 @@ function runConformanceTests(options) {
2260
2276
  url: `${getBaseUrl()}${streamPath}`,
2261
2277
  contentType: `application/json`
2262
2278
  });
2263
- await stream.append({ message: `hello` });
2279
+ await stream.append(JSON.stringify({ message: `hello` }));
2264
2280
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2265
2281
  const data = await response.json();
2266
2282
  (0, vitest.expect)(Array.isArray(data)).toBe(true);
@@ -2272,11 +2288,11 @@ function runConformanceTests(options) {
2272
2288
  url: `${getBaseUrl()}${streamPath}`,
2273
2289
  contentType: `application/json`
2274
2290
  });
2275
- await stream.append([
2291
+ await stream.append(JSON.stringify([
2276
2292
  { id: 1 },
2277
2293
  { id: 2 },
2278
2294
  { id: 3 }
2279
- ]);
2295
+ ]));
2280
2296
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2281
2297
  const data = await response.json();
2282
2298
  (0, vitest.expect)(Array.isArray(data)).toBe(true);
@@ -2292,9 +2308,9 @@ function runConformanceTests(options) {
2292
2308
  url: `${getBaseUrl()}${streamPath}`,
2293
2309
  contentType: `application/json`
2294
2310
  });
2295
- await stream.append({ event: `first` });
2296
- await stream.append({ event: `second` });
2297
- await stream.append({ event: `third` });
2311
+ await stream.append(JSON.stringify({ event: `first` }));
2312
+ await stream.append(JSON.stringify({ event: `second` }));
2313
+ await stream.append(JSON.stringify({ event: `third` }));
2298
2314
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2299
2315
  const data = await response.json();
2300
2316
  (0, vitest.expect)(Array.isArray(data)).toBe(true);
@@ -2310,15 +2326,15 @@ function runConformanceTests(options) {
2310
2326
  url: `${getBaseUrl()}${streamPath}`,
2311
2327
  contentType: `application/json`
2312
2328
  });
2313
- await stream.append({ type: `single` });
2314
- await stream.append([{
2329
+ await stream.append(JSON.stringify({ type: `single` }));
2330
+ await stream.append(JSON.stringify([{
2315
2331
  type: `array`,
2316
2332
  id: 1
2317
2333
  }, {
2318
2334
  type: `array`,
2319
2335
  id: 2
2320
- }]);
2321
- await stream.append({ type: `single-again` });
2336
+ }]));
2337
+ await stream.append(JSON.stringify({ type: `single-again` }));
2322
2338
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2323
2339
  const data = await response.json();
2324
2340
  (0, vitest.expect)(data).toEqual([
@@ -2353,16 +2369,16 @@ function runConformanceTests(options) {
2353
2369
  url: `${getBaseUrl()}${streamPath}`,
2354
2370
  contentType: `application/json`
2355
2371
  });
2356
- await stream.append(`string value`);
2357
- await stream.append(42);
2358
- await stream.append(true);
2359
- await stream.append(null);
2360
- await stream.append({ object: `value` });
2361
- await stream.append([
2372
+ await stream.append(JSON.stringify(`string value`));
2373
+ await stream.append(JSON.stringify(42));
2374
+ await stream.append(JSON.stringify(true));
2375
+ await stream.append(JSON.stringify(null));
2376
+ await stream.append(JSON.stringify({ object: `value` }));
2377
+ await stream.append(JSON.stringify([
2362
2378
  1,
2363
2379
  2,
2364
2380
  3
2365
- ]);
2381
+ ]));
2366
2382
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2367
2383
  const data = await response.json();
2368
2384
  (0, vitest.expect)(data).toEqual([
@@ -2384,14 +2400,14 @@ function runConformanceTests(options) {
2384
2400
  url: `${getBaseUrl()}${streamPath}`,
2385
2401
  contentType: `application/json`
2386
2402
  });
2387
- await stream.append({
2403
+ await stream.append(JSON.stringify({
2388
2404
  user: {
2389
2405
  id: 123,
2390
2406
  name: `Alice`,
2391
2407
  tags: [`admin`, `verified`]
2392
2408
  },
2393
2409
  timestamp: `2024-01-01T00:00:00Z`
2394
- });
2410
+ }));
2395
2411
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2396
2412
  const data = await response.json();
2397
2413
  (0, vitest.expect)(data).toEqual([{
@@ -2409,9 +2425,9 @@ function runConformanceTests(options) {
2409
2425
  url: `${getBaseUrl()}${streamPath}`,
2410
2426
  contentType: `application/json`
2411
2427
  });
2412
- await stream.append({ id: 1 });
2413
- await stream.append({ id: 2 });
2414
- await stream.append({ id: 3 });
2428
+ await stream.append(JSON.stringify({ id: 1 }));
2429
+ await stream.append(JSON.stringify({ id: 2 }));
2430
+ await stream.append(JSON.stringify({ id: 3 }));
2415
2431
  const res = await stream.stream({ live: false });
2416
2432
  const items = await res.json();
2417
2433
  (0, vitest.expect)(items).toEqual([
@@ -2440,7 +2456,7 @@ function runConformanceTests(options) {
2440
2456
  url: `${getBaseUrl()}${streamPath}`,
2441
2457
  contentType: `application/json`
2442
2458
  });
2443
- await stream.append([[1, 2], [3, 4]]);
2459
+ await stream.append(JSON.stringify([[1, 2], [3, 4]]));
2444
2460
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2445
2461
  const data = await response.json();
2446
2462
  (0, vitest.expect)(data).toEqual([[[1, 2], [3, 4]]]);
@@ -2451,11 +2467,11 @@ function runConformanceTests(options) {
2451
2467
  url: `${getBaseUrl()}${streamPath}`,
2452
2468
  contentType: `application/json`
2453
2469
  });
2454
- await stream.append([[
2470
+ await stream.append(JSON.stringify([[
2455
2471
  1,
2456
2472
  2,
2457
2473
  3
2458
- ]]);
2474
+ ]]));
2459
2475
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2460
2476
  const data = await response.json();
2461
2477
  (0, vitest.expect)(data).toEqual([[[
@@ -2471,16 +2487,16 @@ function runConformanceTests(options) {
2471
2487
  url: `${getBaseUrl()}${streamPath}`,
2472
2488
  contentType: `application/json`
2473
2489
  });
2474
- await stream.append([
2490
+ await stream.append(JSON.stringify([
2475
2491
  1,
2476
2492
  2,
2477
2493
  3
2478
- ]);
2479
- await stream.append([
2494
+ ]));
2495
+ await stream.append(JSON.stringify([
2480
2496
  `a`,
2481
2497
  `b`,
2482
2498
  `c`
2483
- ]);
2499
+ ]));
2484
2500
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2485
2501
  const data = await response.json();
2486
2502
  (0, vitest.expect)(data).toEqual([[
@@ -2499,10 +2515,10 @@ function runConformanceTests(options) {
2499
2515
  url: `${getBaseUrl()}${streamPath}`,
2500
2516
  contentType: `application/json`
2501
2517
  });
2502
- await stream.append({ single: 1 });
2503
- await stream.append([{ batch: 2 }, { batch: 3 }]);
2504
- await stream.append([[`nested`, `array`]]);
2505
- await stream.append(42);
2518
+ await stream.append(JSON.stringify({ single: 1 }));
2519
+ await stream.append(JSON.stringify([{ batch: 2 }, { batch: 3 }]));
2520
+ await stream.append(JSON.stringify([[`nested`, `array`]]));
2521
+ await stream.append(JSON.stringify(42));
2506
2522
  const response = await fetch(`${getBaseUrl()}${streamPath}`);
2507
2523
  const data = await response.json();
2508
2524
  (0, vitest.expect)(data).toEqual([
@@ -2516,7 +2532,25 @@ function runConformanceTests(options) {
2516
2532
  });
2517
2533
  (0, vitest.describe)(`Property-Based Tests (fast-check)`, () => {
2518
2534
  (0, vitest.describe)(`Byte-Exactness Property`, () => {
2519
- (0, vitest.test)(`arbitrary byte sequences are preserved exactly`, async () => {
2535
+ const NUM_CONCURRENT_READERS = 7;
2536
+ async function readEntireStream(streamPath) {
2537
+ const accumulated = [];
2538
+ let currentOffset = null;
2539
+ for (let i = 0; i < 100; i++) {
2540
+ const url = currentOffset ? `${getBaseUrl()}${streamPath}?offset=${encodeURIComponent(currentOffset)}` : `${getBaseUrl()}${streamPath}`;
2541
+ const response = await fetch(url, { method: `GET` });
2542
+ (0, vitest.expect)(response.status).toBe(200);
2543
+ const data = new Uint8Array(await response.arrayBuffer());
2544
+ accumulated.push(...data);
2545
+ const nextOffset = response.headers.get(__durable_streams_client.STREAM_OFFSET_HEADER);
2546
+ const upToDate = response.headers.get(__durable_streams_client.STREAM_UP_TO_DATE_HEADER);
2547
+ if (upToDate === `true` && data.length === 0) break;
2548
+ if (nextOffset === currentOffset) break;
2549
+ currentOffset = nextOffset;
2550
+ }
2551
+ return new Uint8Array(accumulated);
2552
+ }
2553
+ (0, vitest.test)(`concurrent readers see consistent data during writes`, async () => {
2520
2554
  await fast_check.assert(fast_check.asyncProperty(
2521
2555
  // Generate 1-10 chunks of arbitrary bytes (1-500 bytes each)
2522
2556
  fast_check.array(fast_check.uint8Array({
@@ -2537,46 +2571,40 @@ function runConformanceTests(options) {
2537
2571
  201,
2538
2572
  204
2539
2573
  ]).toContain(createResponse.status);
2540
- for (const chunk of chunks) {
2541
- const response = await fetch(`${getBaseUrl()}${streamPath}`, {
2542
- method: `POST`,
2543
- headers: { "Content-Type": `application/octet-stream` },
2544
- body: chunk
2545
- });
2546
- (0, vitest.expect)(response.status).toBe(204);
2547
- }
2548
- const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
2549
- const expected = new Uint8Array(totalLength);
2550
- let offset = 0;
2551
- for (const chunk of chunks) {
2552
- expected.set(chunk, offset);
2553
- offset += chunk.length;
2554
- }
2555
- const accumulated = [];
2556
- let currentOffset = null;
2557
- let iterations = 0;
2558
- while (iterations < 100) {
2559
- iterations++;
2560
- const url = currentOffset ? `${getBaseUrl()}${streamPath}?offset=${encodeURIComponent(currentOffset)}` : `${getBaseUrl()}${streamPath}`;
2561
- const response = await fetch(url, { method: `GET` });
2562
- (0, vitest.expect)(response.status).toBe(200);
2563
- const buffer = await response.arrayBuffer();
2564
- const data = new Uint8Array(buffer);
2565
- if (data.length > 0) accumulated.push(...Array.from(data));
2566
- const nextOffset = response.headers.get(__durable_streams_client.STREAM_OFFSET_HEADER);
2567
- const upToDate = response.headers.get(__durable_streams_client.STREAM_UP_TO_DATE_HEADER);
2568
- if (upToDate === `true` && data.length === 0) break;
2569
- if (nextOffset === currentOffset) break;
2570
- currentOffset = nextOffset;
2574
+ const expected = Uint8Array.from(chunks.flatMap((c) => [...c]));
2575
+ let writesComplete = false;
2576
+ const readerPromises = Array.from({ length: NUM_CONCURRENT_READERS }, async () => {
2577
+ const snapshots = [];
2578
+ while (!writesComplete) {
2579
+ const response = await fetch(`${getBaseUrl()}${streamPath}`);
2580
+ snapshots.push(new Uint8Array(await response.arrayBuffer()));
2581
+ await new Promise((r) => setTimeout(r, Math.random() * 3));
2582
+ }
2583
+ return snapshots;
2584
+ });
2585
+ const writerPromise = (async () => {
2586
+ for (const chunk of chunks) {
2587
+ await new Promise((r) => setTimeout(r, Math.random() * 5));
2588
+ const response = await fetch(`${getBaseUrl()}${streamPath}`, {
2589
+ method: `POST`,
2590
+ headers: { "Content-Type": `application/octet-stream` },
2591
+ body: chunk
2592
+ });
2593
+ (0, vitest.expect)(response.status).toBe(204);
2594
+ }
2595
+ writesComplete = true;
2596
+ })();
2597
+ const [readerResults] = await Promise.all([Promise.all(readerPromises), writerPromise]);
2598
+ for (const snapshots of readerResults) for (const snapshot of snapshots) {
2599
+ (0, vitest.expect)(snapshot.length).toBeLessThanOrEqual(expected.length);
2600
+ for (let i = 0; i < snapshot.length; i++) (0, vitest.expect)(snapshot[i]).toBe(expected[i]);
2571
2601
  }
2572
- const result = new Uint8Array(accumulated);
2573
- (0, vitest.expect)(result.length).toBe(expected.length);
2574
- for (let i = 0; i < expected.length; i++) (0, vitest.expect)(result[i]).toBe(expected[i]);
2575
- return true;
2602
+ const finalResult = await readEntireStream(streamPath);
2603
+ (0, vitest.expect)(finalResult).toEqual(expected);
2576
2604
  }
2577
2605
  ), { numRuns: 20 });
2578
2606
  });
2579
- (0, vitest.test)(`single byte values cover full range (0-255)`, async () => {
2607
+ (0, vitest.test)(`single byte values cover full range (0-255) with concurrent readers during write`, async () => {
2580
2608
  await fast_check.assert(fast_check.asyncProperty(
2581
2609
  // Generate a byte value from 0-255
2582
2610
  fast_check.integer({
@@ -2589,18 +2617,24 @@ function runConformanceTests(options) {
2589
2617
  method: `PUT`,
2590
2618
  headers: { "Content-Type": `application/octet-stream` }
2591
2619
  });
2592
- const chunk = new Uint8Array([byteValue]);
2593
- await fetch(`${getBaseUrl()}${streamPath}`, {
2620
+ const expected = new Uint8Array([byteValue]);
2621
+ const readerPromises = Array.from({ length: NUM_CONCURRENT_READERS }, async () => {
2622
+ await new Promise((r) => setTimeout(r, Math.random() * 5));
2623
+ const response = await fetch(`${getBaseUrl()}${streamPath}`);
2624
+ return new Uint8Array(await response.arrayBuffer());
2625
+ });
2626
+ const writerPromise = fetch(`${getBaseUrl()}${streamPath}`, {
2594
2627
  method: `POST`,
2595
2628
  headers: { "Content-Type": `application/octet-stream` },
2596
- body: chunk
2629
+ body: new Uint8Array([byteValue])
2597
2630
  });
2598
- const response = await fetch(`${getBaseUrl()}${streamPath}`);
2599
- const buffer = await response.arrayBuffer();
2600
- const result = new Uint8Array(buffer);
2601
- (0, vitest.expect)(result.length).toBe(1);
2602
- (0, vitest.expect)(result[0]).toBe(byteValue);
2603
- return true;
2631
+ const [readerResults] = await Promise.all([Promise.all(readerPromises), writerPromise]);
2632
+ for (const result of readerResults) {
2633
+ (0, vitest.expect)(result.length).toBeLessThanOrEqual(1);
2634
+ if (result.length === 1) (0, vitest.expect)(result[0]).toBe(byteValue);
2635
+ }
2636
+ const finalResult = await readEntireStream(streamPath);
2637
+ (0, vitest.expect)(finalResult).toEqual(expected);
2604
2638
  }
2605
2639
  ), { numRuns: 50 });
2606
2640
  });