@durable-streams/server-conformance-tests 0.1.4 → 0.1.5

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-DK3GDgwo.cjs');
1
+ const require_src = require('./src-BJQjRfnf.cjs');
2
2
 
3
3
  exports.runConformanceTests = require_src.runConformanceTests
package/dist/index.d.cts CHANGED
@@ -2,6 +2,8 @@
2
2
  interface ConformanceTestOptions {
3
3
  /** Base URL of the server to test */
4
4
  baseUrl: string;
5
+ /** Timeout for long-poll tests in milliseconds (default: 20000) */
6
+ longPollTimeoutMs?: number;
5
7
  }
6
8
  /**
7
9
  * Run the full conformance test suite against a server
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  interface ConformanceTestOptions {
3
3
  /** Base URL of the server to test */
4
4
  baseUrl: string;
5
+ /** Timeout for long-poll tests in milliseconds (default: 20000) */
6
+ longPollTimeoutMs?: number;
5
7
  }
6
8
  /**
7
9
  * Run the full conformance test suite against a server
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { runConformanceTests } from "./src-DcbQ_SIQ.js";
1
+ import { runConformanceTests } from "./src-BtF2jQ-Q.js";
2
2
 
3
3
  export { runConformanceTests };
@@ -84,6 +84,7 @@ function parseSSEEvents(sseText) {
84
84
  */
85
85
  function runConformanceTests(options) {
86
86
  const getBaseUrl = () => options.baseUrl;
87
+ const getLongPollTestTimeoutMs = () => (options.longPollTimeoutMs ?? 2e4) + 1e3;
87
88
  (0, vitest.describe)(`Basic Stream Operations`, () => {
88
89
  (0, vitest.test)(`should create a stream`, async () => {
89
90
  const streamPath = `/v1/stream/create-test-${Date.now()}`;
@@ -252,13 +253,14 @@ function runConformanceTests(options) {
252
253
  const readPromise = (async () => {
253
254
  const res = await stream.stream({ live: `long-poll` });
254
255
  await new Promise((resolve) => {
255
- const unsubscribe = res.subscribeBytes(async (chunk) => {
256
+ const unsubscribe = res.subscribeBytes((chunk) => {
256
257
  if (chunk.data.length > 0) receivedData.push(new TextDecoder().decode(chunk.data));
257
258
  if (receivedData.length >= 1) {
258
259
  unsubscribe();
259
260
  res.cancel();
260
261
  resolve();
261
262
  }
263
+ return Promise.resolve();
262
264
  });
263
265
  });
264
266
  })();
@@ -266,7 +268,7 @@ function runConformanceTests(options) {
266
268
  await stream.append(`new data`);
267
269
  await readPromise;
268
270
  (0, vitest.expect)(receivedData).toContain(`new data`);
269
- }, 1e4);
271
+ }, getLongPollTestTimeoutMs());
270
272
  (0, vitest.test)(`should return immediately if data already exists`, async () => {
271
273
  const streamPath = `/v1/stream/longpoll-immediate-test-${Date.now()}`;
272
274
  const stream = await __durable_streams_client.DurableStream.create({
@@ -1059,7 +1061,7 @@ function runConformanceTests(options) {
1059
1061
  clearTimeout(timeoutId);
1060
1062
  if (e instanceof Error && e.name !== `AbortError`) throw e;
1061
1063
  }
1062
- }, 1e4);
1064
+ }, getLongPollTestTimeoutMs());
1063
1065
  });
1064
1066
  (0, vitest.describe)(`TTL and Expiry Edge Cases`, () => {
1065
1067
  (0, vitest.test)(`should reject TTL with leading zeros`, async () => {
@@ -82,6 +82,7 @@ function parseSSEEvents(sseText) {
82
82
  */
83
83
  function runConformanceTests(options) {
84
84
  const getBaseUrl = () => options.baseUrl;
85
+ const getLongPollTestTimeoutMs = () => (options.longPollTimeoutMs ?? 2e4) + 1e3;
85
86
  describe(`Basic Stream Operations`, () => {
86
87
  test(`should create a stream`, async () => {
87
88
  const streamPath = `/v1/stream/create-test-${Date.now()}`;
@@ -250,13 +251,14 @@ function runConformanceTests(options) {
250
251
  const readPromise = (async () => {
251
252
  const res = await stream.stream({ live: `long-poll` });
252
253
  await new Promise((resolve) => {
253
- const unsubscribe = res.subscribeBytes(async (chunk) => {
254
+ const unsubscribe = res.subscribeBytes((chunk) => {
254
255
  if (chunk.data.length > 0) receivedData.push(new TextDecoder().decode(chunk.data));
255
256
  if (receivedData.length >= 1) {
256
257
  unsubscribe();
257
258
  res.cancel();
258
259
  resolve();
259
260
  }
261
+ return Promise.resolve();
260
262
  });
261
263
  });
262
264
  })();
@@ -264,7 +266,7 @@ function runConformanceTests(options) {
264
266
  await stream.append(`new data`);
265
267
  await readPromise;
266
268
  expect(receivedData).toContain(`new data`);
267
- }, 1e4);
269
+ }, getLongPollTestTimeoutMs());
268
270
  test(`should return immediately if data already exists`, async () => {
269
271
  const streamPath = `/v1/stream/longpoll-immediate-test-${Date.now()}`;
270
272
  const stream = await DurableStream.create({
@@ -1057,7 +1059,7 @@ function runConformanceTests(options) {
1057
1059
  clearTimeout(timeoutId);
1058
1060
  if (e instanceof Error && e.name !== `AbortError`) throw e;
1059
1061
  }
1060
- }, 1e4);
1062
+ }, getLongPollTestTimeoutMs());
1061
1063
  });
1062
1064
  describe(`TTL and Expiry Edge Cases`, () => {
1063
1065
  test(`should reject TTL with leading zeros`, async () => {
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const require_src = require('./src-DK3GDgwo.cjs');
2
+ const require_src = require('./src-BJQjRfnf.cjs');
3
3
 
4
4
  //#region src/test-runner.ts
5
5
  const baseUrl = process.env.CONFORMANCE_TEST_URL;
@@ -1,4 +1,4 @@
1
- import { runConformanceTests } from "./src-DcbQ_SIQ.js";
1
+ import { runConformanceTests } from "./src-BtF2jQ-Q.js";
2
2
 
3
3
  //#region src/test-runner.ts
4
4
  const baseUrl = process.env.CONFORMANCE_TEST_URL;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@durable-streams/server-conformance-tests",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Conformance test suite for Durable Streams server implementations",
5
5
  "author": "Durable Stream contributors",
6
6
  "license": "Apache-2.0",
package/src/index.ts CHANGED
@@ -17,6 +17,8 @@ import {
17
17
  export interface ConformanceTestOptions {
18
18
  /** Base URL of the server to test */
19
19
  baseUrl: string
20
+ /** Timeout for long-poll tests in milliseconds (default: 20000) */
21
+ longPollTimeoutMs?: number
20
22
  }
21
23
 
22
24
  /**
@@ -144,6 +146,8 @@ export function runConformanceTests(options: ConformanceTestOptions): void {
144
146
  // Access options.baseUrl directly instead of destructuring to support
145
147
  // mutable config objects (needed for dynamic port assignment)
146
148
  const getBaseUrl = () => options.baseUrl
149
+ const getLongPollTestTimeoutMs = () =>
150
+ (options.longPollTimeoutMs ?? 20_000) + 1_000
147
151
 
148
152
  // ============================================================================
149
153
  // Basic Stream Operations
@@ -380,42 +384,47 @@ export function runConformanceTests(options: ConformanceTestOptions): void {
380
384
  // ============================================================================
381
385
 
382
386
  describe(`Long-Poll Operations`, () => {
383
- test(`should wait for new data with long-poll`, async () => {
384
- const streamPath = `/v1/stream/longpoll-test-${Date.now()}`
385
- const stream = await DurableStream.create({
386
- url: `${getBaseUrl()}${streamPath}`,
387
- contentType: `text/plain`,
388
- })
387
+ test(
388
+ `should wait for new data with long-poll`,
389
+ async () => {
390
+ const streamPath = `/v1/stream/longpoll-test-${Date.now()}`
391
+ const stream = await DurableStream.create({
392
+ url: `${getBaseUrl()}${streamPath}`,
393
+ contentType: `text/plain`,
394
+ })
389
395
 
390
- const receivedData: Array<string> = []
396
+ const receivedData: Array<string> = []
391
397
 
392
- // Start reading in long-poll mode
393
- const readPromise = (async () => {
394
- const res = await stream.stream({ live: `long-poll` })
395
- await new Promise<void>((resolve) => {
396
- const unsubscribe = res.subscribeBytes(async (chunk) => {
397
- if (chunk.data.length > 0) {
398
- receivedData.push(new TextDecoder().decode(chunk.data))
399
- }
400
- if (receivedData.length >= 1) {
401
- unsubscribe()
402
- res.cancel()
403
- resolve()
404
- }
398
+ // Start reading in long-poll mode
399
+ const readPromise = (async () => {
400
+ const res = await stream.stream({ live: `long-poll` })
401
+ await new Promise<void>((resolve) => {
402
+ const unsubscribe = res.subscribeBytes((chunk) => {
403
+ if (chunk.data.length > 0) {
404
+ receivedData.push(new TextDecoder().decode(chunk.data))
405
+ }
406
+ if (receivedData.length >= 1) {
407
+ unsubscribe()
408
+ res.cancel()
409
+ resolve()
410
+ }
411
+ return Promise.resolve()
412
+ })
405
413
  })
406
- })
407
- })()
414
+ })()
408
415
 
409
- // Wait a bit for the long-poll to be active
410
- await new Promise((resolve) => setTimeout(resolve, 500))
416
+ // Wait a bit for the long-poll to be active
417
+ await new Promise((resolve) => setTimeout(resolve, 500))
411
418
 
412
- // Append data while long-poll is waiting
413
- await stream.append(`new data`)
419
+ // Append data while long-poll is waiting
420
+ await stream.append(`new data`)
414
421
 
415
- await readPromise
422
+ await readPromise
416
423
 
417
- expect(receivedData).toContain(`new data`)
418
- }, 10000)
424
+ expect(receivedData).toContain(`new data`)
425
+ },
426
+ getLongPollTestTimeoutMs()
427
+ )
419
428
 
420
429
  test(`should return immediately if data already exists`, async () => {
421
430
  const streamPath = `/v1/stream/longpoll-immediate-test-${Date.now()}`
@@ -1631,58 +1640,62 @@ export function runConformanceTests(options: ConformanceTestOptions): void {
1631
1640
  expect(parseInt(cursor2!, 10)).toBeGreaterThan(parseInt(cursor1!, 10))
1632
1641
  })
1633
1642
 
1634
- test(`should return Stream-Cursor, Stream-Up-To-Date and Stream-Next-Offset on 204 timeout`, async () => {
1635
- const streamPath = `/v1/stream/longpoll-204-headers-test-${Date.now()}`
1636
-
1637
- await fetch(`${getBaseUrl()}${streamPath}`, {
1638
- method: `PUT`,
1639
- headers: { "Content-Type": `text/plain` },
1640
- })
1641
-
1642
- // Get the current tail offset
1643
- const headResponse = await fetch(`${getBaseUrl()}${streamPath}`, {
1644
- method: `HEAD`,
1645
- })
1646
- const tailOffset = headResponse.headers.get(STREAM_OFFSET_HEADER)
1647
- expect(tailOffset).toBeDefined()
1643
+ test(
1644
+ `should return Stream-Cursor, Stream-Up-To-Date and Stream-Next-Offset on 204 timeout`,
1645
+ async () => {
1646
+ const streamPath = `/v1/stream/longpoll-204-headers-test-${Date.now()}`
1648
1647
 
1649
- // Long-poll at tail offset with a short timeout
1650
- // We use AbortController to limit wait time on our side
1651
- const controller = new AbortController()
1652
- const timeoutId = setTimeout(() => controller.abort(), 5000)
1648
+ await fetch(`${getBaseUrl()}${streamPath}`, {
1649
+ method: `PUT`,
1650
+ headers: { "Content-Type": `text/plain` },
1651
+ })
1653
1652
 
1654
- try {
1655
- const response = await fetch(
1656
- `${getBaseUrl()}${streamPath}?offset=${tailOffset}&live=long-poll`,
1657
- {
1658
- method: `GET`,
1659
- signal: controller.signal,
1660
- }
1661
- )
1653
+ // Get the current tail offset
1654
+ const headResponse = await fetch(`${getBaseUrl()}${streamPath}`, {
1655
+ method: `HEAD`,
1656
+ })
1657
+ const tailOffset = headResponse.headers.get(STREAM_OFFSET_HEADER)
1658
+ expect(tailOffset).toBeDefined()
1659
+
1660
+ // Long-poll at tail offset with a short timeout
1661
+ // We use AbortController to limit wait time on our side
1662
+ const controller = new AbortController()
1663
+ const timeoutId = setTimeout(() => controller.abort(), 5000)
1664
+
1665
+ try {
1666
+ const response = await fetch(
1667
+ `${getBaseUrl()}${streamPath}?offset=${tailOffset}&live=long-poll`,
1668
+ {
1669
+ method: `GET`,
1670
+ signal: controller.signal,
1671
+ }
1672
+ )
1662
1673
 
1663
- clearTimeout(timeoutId)
1674
+ clearTimeout(timeoutId)
1664
1675
 
1665
- // If we get a 204, verify headers
1666
- if (response.status === 204) {
1667
- expect(response.headers.get(STREAM_OFFSET_HEADER)).toBeDefined()
1668
- expect(response.headers.get(STREAM_UP_TO_DATE_HEADER)).toBe(`true`)
1676
+ // If we get a 204, verify headers
1677
+ if (response.status === 204) {
1678
+ expect(response.headers.get(STREAM_OFFSET_HEADER)).toBeDefined()
1679
+ expect(response.headers.get(STREAM_UP_TO_DATE_HEADER)).toBe(`true`)
1669
1680
 
1670
- // Server MUST return Stream-Cursor even on 204 timeout
1671
- const cursor = response.headers.get(`Stream-Cursor`)
1672
- expect(cursor).toBeDefined()
1673
- expect(/^\d+$/.test(cursor!)).toBe(true)
1674
- }
1675
- // If we get a 200 (data arrived somehow), that's also valid
1676
- expect([200, 204]).toContain(response.status)
1677
- } catch (e) {
1678
- clearTimeout(timeoutId)
1679
- // AbortError is expected if server timeout is longer than our 5s
1680
- if (e instanceof Error && e.name !== `AbortError`) {
1681
- throw e
1681
+ // Server MUST return Stream-Cursor even on 204 timeout
1682
+ const cursor = response.headers.get(`Stream-Cursor`)
1683
+ expect(cursor).toBeDefined()
1684
+ expect(/^\d+$/.test(cursor!)).toBe(true)
1685
+ }
1686
+ // If we get a 200 (data arrived somehow), that's also valid
1687
+ expect([200, 204]).toContain(response.status)
1688
+ } catch (e) {
1689
+ clearTimeout(timeoutId)
1690
+ // AbortError is expected if server timeout is longer than our 5s
1691
+ if (e instanceof Error && e.name !== `AbortError`) {
1692
+ throw e
1693
+ }
1694
+ // Test passes - server just has a longer timeout than our abort
1682
1695
  }
1683
- // Test passes - server just has a longer timeout than our abort
1684
- }
1685
- }, 10000)
1696
+ },
1697
+ getLongPollTestTimeoutMs()
1698
+ )
1686
1699
  })
1687
1700
 
1688
1701
  // ============================================================================