@durable-streams/server-conformance-tests 0.1.3 → 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/cli.cjs +11 -10
- package/dist/cli.js +11 -10
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/{src-DK3GDgwo.cjs → src-BJQjRfnf.cjs} +5 -3
- package/dist/{src-DcbQ_SIQ.js → src-BtF2jQ-Q.js} +5 -3
- package/dist/test-runner.cjs +1 -1
- package/dist/test-runner.js +1 -1
- package/package.json +3 -2
- package/src/cli.ts +23 -38
- package/src/index.ts +88 -75
package/dist/cli.cjs
CHANGED
|
@@ -86,14 +86,19 @@ function getTestRunnerPath() {
|
|
|
86
86
|
if ((0, node_fs.existsSync)(runnerInDist)) return runnerInDist;
|
|
87
87
|
return runnerInSrc;
|
|
88
88
|
}
|
|
89
|
+
function findVitestBinary() {
|
|
90
|
+
const possiblePaths = [
|
|
91
|
+
(0, node_path.join)(__dirname$1, `..`, `node_modules`, `.bin`, `vitest`),
|
|
92
|
+
(0, node_path.join)(__dirname$1, `..`, `..`, `..`, `..`, `.bin`, `vitest`),
|
|
93
|
+
(0, node_path.join)(__dirname$1, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`)
|
|
94
|
+
];
|
|
95
|
+
for (const vitestPath of possiblePaths) if ((0, node_fs.existsSync)(vitestPath)) return vitestPath;
|
|
96
|
+
return `vitest`;
|
|
97
|
+
}
|
|
89
98
|
function runTests(baseUrl) {
|
|
90
99
|
return new Promise((resolvePromise) => {
|
|
91
100
|
const runnerPath = getTestRunnerPath();
|
|
92
|
-
const
|
|
93
|
-
const vitestBinAlt = (0, node_path.join)(__dirname$1, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`);
|
|
94
|
-
let vitestPath = `vitest`;
|
|
95
|
-
if ((0, node_fs.existsSync)(vitestBin)) vitestPath = vitestBin;
|
|
96
|
-
else if ((0, node_fs.existsSync)(vitestBinAlt)) vitestPath = vitestBinAlt;
|
|
101
|
+
const vitestPath = findVitestBinary();
|
|
97
102
|
const args = [
|
|
98
103
|
`run`,
|
|
99
104
|
runnerPath,
|
|
@@ -130,11 +135,7 @@ async function runWatch(baseUrl, watchPaths) {
|
|
|
130
135
|
const DEBOUNCE_MS = 300;
|
|
131
136
|
const spawnTests = () => {
|
|
132
137
|
const runnerPath = getTestRunnerPath();
|
|
133
|
-
const
|
|
134
|
-
const vitestBinAlt = (0, node_path.join)(__dirname$1, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`);
|
|
135
|
-
let vitestPath = `vitest`;
|
|
136
|
-
if ((0, node_fs.existsSync)(vitestBin)) vitestPath = vitestBin;
|
|
137
|
-
else if ((0, node_fs.existsSync)(vitestBinAlt)) vitestPath = vitestBinAlt;
|
|
138
|
+
const vitestPath = findVitestBinary();
|
|
138
139
|
const args = [
|
|
139
140
|
`run`,
|
|
140
141
|
runnerPath,
|
package/dist/cli.js
CHANGED
|
@@ -84,14 +84,19 @@ function getTestRunnerPath() {
|
|
|
84
84
|
if (existsSync(runnerInDist)) return runnerInDist;
|
|
85
85
|
return runnerInSrc;
|
|
86
86
|
}
|
|
87
|
+
function findVitestBinary() {
|
|
88
|
+
const possiblePaths = [
|
|
89
|
+
join(__dirname, `..`, `node_modules`, `.bin`, `vitest`),
|
|
90
|
+
join(__dirname, `..`, `..`, `..`, `..`, `.bin`, `vitest`),
|
|
91
|
+
join(__dirname, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`)
|
|
92
|
+
];
|
|
93
|
+
for (const vitestPath of possiblePaths) if (existsSync(vitestPath)) return vitestPath;
|
|
94
|
+
return `vitest`;
|
|
95
|
+
}
|
|
87
96
|
function runTests(baseUrl) {
|
|
88
97
|
return new Promise((resolvePromise) => {
|
|
89
98
|
const runnerPath = getTestRunnerPath();
|
|
90
|
-
const
|
|
91
|
-
const vitestBinAlt = join(__dirname, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`);
|
|
92
|
-
let vitestPath = `vitest`;
|
|
93
|
-
if (existsSync(vitestBin)) vitestPath = vitestBin;
|
|
94
|
-
else if (existsSync(vitestBinAlt)) vitestPath = vitestBinAlt;
|
|
99
|
+
const vitestPath = findVitestBinary();
|
|
95
100
|
const args = [
|
|
96
101
|
`run`,
|
|
97
102
|
runnerPath,
|
|
@@ -128,11 +133,7 @@ async function runWatch(baseUrl, watchPaths) {
|
|
|
128
133
|
const DEBOUNCE_MS = 300;
|
|
129
134
|
const spawnTests = () => {
|
|
130
135
|
const runnerPath = getTestRunnerPath();
|
|
131
|
-
const
|
|
132
|
-
const vitestBinAlt = join(__dirname, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`);
|
|
133
|
-
let vitestPath = `vitest`;
|
|
134
|
-
if (existsSync(vitestBin)) vitestPath = vitestBin;
|
|
135
|
-
else if (existsSync(vitestBinAlt)) vitestPath = vitestBinAlt;
|
|
136
|
+
const vitestPath = findVitestBinary();
|
|
136
137
|
const args = [
|
|
137
138
|
`run`,
|
|
138
139
|
runnerPath,
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -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(
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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(
|
|
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
|
-
},
|
|
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
|
-
},
|
|
1062
|
+
}, getLongPollTestTimeoutMs());
|
|
1061
1063
|
});
|
|
1062
1064
|
describe(`TTL and Expiry Edge Cases`, () => {
|
|
1063
1065
|
test(`should reject TTL with leading zeros`, async () => {
|
package/dist/test-runner.cjs
CHANGED
package/dist/test-runner.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@durable-streams/server-conformance-tests",
|
|
3
|
-
"version": "0.1.
|
|
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",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"module": "./dist/index.js",
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"bin": {
|
|
26
|
+
"server-conformance-tests": "./dist/cli.js",
|
|
26
27
|
"durable-streams-server-conformance": "./dist/cli.js",
|
|
27
28
|
"durable-streams-server-conformance-dev": "./bin/conformance-dev.mjs"
|
|
28
29
|
},
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
],
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"fast-check": "^4.4.0",
|
|
50
|
-
"vitest": "^
|
|
51
|
+
"vitest": "^4.0.0",
|
|
51
52
|
"@durable-streams/client": "0.1.2"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
package/src/cli.ts
CHANGED
|
@@ -131,28 +131,31 @@ function getTestRunnerPath(): string {
|
|
|
131
131
|
return runnerInSrc
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
// Find vitest binary in various possible locations
|
|
135
|
+
function findVitestBinary(): string {
|
|
136
|
+
const possiblePaths = [
|
|
137
|
+
// Package's own node_modules (bundled dependency)
|
|
138
|
+
join(__dirname, `..`, `node_modules`, `.bin`, `vitest`),
|
|
139
|
+
// Hoisted location for scoped packages (@scope/package-name/dist -> node_modules/.bin)
|
|
140
|
+
join(__dirname, `..`, `..`, `..`, `..`, `.bin`, `vitest`),
|
|
141
|
+
// Monorepo root node_modules (for development)
|
|
142
|
+
join(__dirname, `..`, `..`, `..`, `node_modules`, `.bin`, `vitest`),
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
for (const vitestPath of possiblePaths) {
|
|
146
|
+
if (existsSync(vitestPath)) {
|
|
147
|
+
return vitestPath
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Fallback to vitest in PATH
|
|
152
|
+
return `vitest`
|
|
153
|
+
}
|
|
154
|
+
|
|
134
155
|
function runTests(baseUrl: string): Promise<number> {
|
|
135
156
|
return new Promise((resolvePromise) => {
|
|
136
157
|
const runnerPath = getTestRunnerPath()
|
|
137
|
-
|
|
138
|
-
// Find vitest binary
|
|
139
|
-
const vitestBin = join(__dirname, `..`, `node_modules`, `.bin`, `vitest`)
|
|
140
|
-
const vitestBinAlt = join(
|
|
141
|
-
__dirname,
|
|
142
|
-
`..`,
|
|
143
|
-
`..`,
|
|
144
|
-
`..`,
|
|
145
|
-
`node_modules`,
|
|
146
|
-
`.bin`,
|
|
147
|
-
`vitest`
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
let vitestPath = `vitest`
|
|
151
|
-
if (existsSync(vitestBin)) {
|
|
152
|
-
vitestPath = vitestBin
|
|
153
|
-
} else if (existsSync(vitestBinAlt)) {
|
|
154
|
-
vitestPath = vitestBinAlt
|
|
155
|
-
}
|
|
158
|
+
const vitestPath = findVitestBinary()
|
|
156
159
|
|
|
157
160
|
const args = [
|
|
158
161
|
`run`,
|
|
@@ -199,25 +202,7 @@ async function runWatch(
|
|
|
199
202
|
|
|
200
203
|
const spawnTests = (): ChildProcess => {
|
|
201
204
|
const runnerPath = getTestRunnerPath()
|
|
202
|
-
|
|
203
|
-
// Find vitest binary
|
|
204
|
-
const vitestBin = join(__dirname, `..`, `node_modules`, `.bin`, `vitest`)
|
|
205
|
-
const vitestBinAlt = join(
|
|
206
|
-
__dirname,
|
|
207
|
-
`..`,
|
|
208
|
-
`..`,
|
|
209
|
-
`..`,
|
|
210
|
-
`node_modules`,
|
|
211
|
-
`.bin`,
|
|
212
|
-
`vitest`
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
let vitestPath = `vitest`
|
|
216
|
-
if (existsSync(vitestBin)) {
|
|
217
|
-
vitestPath = vitestBin
|
|
218
|
-
} else if (existsSync(vitestBinAlt)) {
|
|
219
|
-
vitestPath = vitestBinAlt
|
|
220
|
-
}
|
|
205
|
+
const vitestPath = findVitestBinary()
|
|
221
206
|
|
|
222
207
|
const args = [
|
|
223
208
|
`run`,
|
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(
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
|
|
396
|
+
const receivedData: Array<string> = []
|
|
391
397
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
-
|
|
410
|
-
|
|
416
|
+
// Wait a bit for the long-poll to be active
|
|
417
|
+
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
411
418
|
|
|
412
|
-
|
|
413
|
-
|
|
419
|
+
// Append data while long-poll is waiting
|
|
420
|
+
await stream.append(`new data`)
|
|
414
421
|
|
|
415
|
-
|
|
422
|
+
await readPromise
|
|
416
423
|
|
|
417
|
-
|
|
418
|
-
|
|
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(
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
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
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1648
|
+
await fetch(`${getBaseUrl()}${streamPath}`, {
|
|
1649
|
+
method: `PUT`,
|
|
1650
|
+
headers: { "Content-Type": `text/plain` },
|
|
1651
|
+
})
|
|
1653
1652
|
|
|
1654
|
-
|
|
1655
|
-
const
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
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
|
-
|
|
1674
|
+
clearTimeout(timeoutId)
|
|
1664
1675
|
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
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
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
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
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1696
|
+
},
|
|
1697
|
+
getLongPollTestTimeoutMs()
|
|
1698
|
+
)
|
|
1686
1699
|
})
|
|
1687
1700
|
|
|
1688
1701
|
// ============================================================================
|