Skip to content
File

Blob: src/workerd/api/tests/abortable-fetch-test.js

javascript121 lines
1// Copyright (c) 2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import { strictEqual, ok } from 'node:assert';
5 
6// Test for the AbortSignal and AbortController standard Web API implementations.
7// The implementation for these are in api/basics.{h|c++}
8 
9export const abortControllerAlreadyAborted = {
10 async test(ctrl, env) {
11 const ac = new AbortController();
12 ac.abort();
13 try {
14 const _result = await env.subrequest.fetch('http://example.org', {
15 signal: ac.signal,
16 });
17 throw new Error('should have failed');
18 } catch (err) {
19 strictEqual(err.message, 'The operation was aborted');
20 }
21 },
22};
23 
24export const alreadyAborted = {
25 async test(ctrl, env) {
26 const signal = AbortSignal.abort('boom');
27 try {
28 await env.subrequest.fetch('http://example.org', { signal });
29 throw new Error('should have failed');
30 } catch (err) {
31 strictEqual(err, 'boom');
32 }
33 },
34};
35 
36export const timedAbort = {
37 async test(ctrl, env) {
38 const signal = AbortSignal.timeout(100);
39 try {
40 await env.subrequest.fetch('http://example.org', { signal });
41 throw new Error('should have failed');
42 } catch (err) {
43 strictEqual(err.message, 'The operation was aborted due to timeout');
44 }
45 },
46};
47 
48export const abortControllerSyncAbort = {
49 async test(ctrl, env) {
50 const ac = new AbortController();
51 try {
52 const promise = env.subrequest.fetch('http://example.org', {
53 signal: ac.signal,
54 });
55 ac.abort();
56 await promise;
57 throw new Error('should have failed');
58 } catch (err) {
59 strictEqual(err.message, 'The operation was aborted');
60 }
61 },
62};
63 
64export const asyncSubrequest = {
65 async test(ctrl, env) {
66 try {
67 await env.subrequest.fetch('http://example.org/sub');
68 throw new Error('should have failed');
69 } catch (err) {
70 strictEqual(err.message, 'The operation was aborted due to timeout');
71 }
72 },
73};
74 
75export const syncSubrequest = {
76 async test(ctrl, env) {
77 try {
78 await env.subrequest.fetch('http://example.org/subsync');
79 throw new Error('should have failed');
80 } catch (err) {
81 strictEqual(err.message, 'The operation was aborted');
82 }
83 },
84};
85 
86export const requestAbortSignal = {
87 test() {
88 // The request object has an AbortSignal, even if never used.
89 const req1 = new Request('');
90 ok(Reflect.has(req1, 'signal'));
91 
92 // request.signal should be the one passed in.
93 const ac = new AbortController();
94 const req2 = new Request('', { signal: ac.signal });
95 strictEqual(req2.signal, ac.signal);
96 },
97};
98 
99export default {
100 async fetch(request, env) {
101 if (request.url.endsWith('/sub')) {
102 // Verifies that a fetch subrequest returned as the response can be canceled
103 // asynchronously successfully.
104 const signal = AbortSignal.timeout(100);
105 return env.subrequest.fetch('http://example.org', { signal });
106 } else if (request.url.endsWith('/subsync')) {
107 // Verifies that a fetch subrequest returned as the response can be synchronously
108 // aborted.
109 const ac = new AbortController();
110 const resp = env.subrequest.fetch('http://example.org', {
111 signal: ac.signal,
112 });
113 ac.abort();
114 return resp;
115 } else {
116 await scheduler.wait(10000);
117 return new Response('ok');
118 }
119 },
120};