Skip to content

Commit 46255a2

Browse files
authored
add more tests related to http modules (#4537)
* add more tests related to http modules * add a test to compare get with dynamically imported * cleanup http-client-nodejs-test
1 parent dd2aa1c commit 46255a2

File tree

6 files changed

+271
-79
lines changed

6 files changed

+271
-79
lines changed

src/workerd/api/node/tests/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,8 @@ wd_test(
376376
"PONG_SERVER_PORT",
377377
"ASD_SERVER_PORT",
378378
"DEFAULT_HEADERS_EXIST_PORT",
379+
"REQUEST_ARGUMENTS_PORT",
380+
"HELLO_WORLD_SERVER_PORT",
379381
],
380382
)
381383

src/workerd/api/node/tests/http-client-nodejs-server.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,37 @@ asdServer.listen(process.env.ASD_SERVER_PORT, () => reportPort(asdServer));
6262
reportPort(defaultHeadersExistServer)
6363
);
6464
}
65+
66+
const requestArgumentsServer = http.createServer((req, res) => {
67+
assert.strictEqual(req.url, '/testpath');
68+
res.end();
69+
});
70+
requestArgumentsServer.listen(process.env.REQUEST_ARGUMENTS_PORT, () =>
71+
reportPort(requestArgumentsServer)
72+
);
73+
74+
const helloWorldServer = http.createServer((req, res) => {
75+
res.removeHeader('Date');
76+
res.setHeader('Keep-Alive', 'timeout=1');
77+
78+
switch (req.url.slice(1)) {
79+
case 'join-duplicate-headers':
80+
res.writeHead(200, [
81+
'authorization',
82+
'3',
83+
'authorization',
84+
'4',
85+
'cookie',
86+
'foo',
87+
'cookie',
88+
'bar',
89+
]);
90+
res.end();
91+
break;
92+
default:
93+
res.end();
94+
}
95+
});
96+
helloWorldServer.listen(process.env.HELLO_WORLD_SERVER_PORT, () =>
97+
reportPort(helloWorldServer)
98+
);

src/workerd/api/node/tests/http-client-nodejs-test.js

Lines changed: 221 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@
33
// https://opensource.org/licenses/Apache-2.0
44

55
import http from 'node:http';
6-
import https from 'node:https';
7-
import { strictEqual, ok, throws } from 'node:assert';
6+
import { strictEqual, ok, throws, deepStrictEqual } from 'node:assert';
87
import { once } from 'node:events';
8+
import { mock } from 'node:test';
9+
import { get } from 'node:http';
910

1011
export const checkPortsSetCorrectly = {
1112
test(_ctrl, env) {
1213
const keys = [
1314
'PONG_SERVER_PORT',
1415
'ASD_SERVER_PORT',
1516
'DEFAULT_HEADERS_EXIST_PORT',
17+
'REQUEST_ARGUMENTS_PORT',
18+
'HELLO_WORLD_SERVER_PORT',
1619
];
1720
for (const key of keys) {
1821
strictEqual(typeof env[key], 'string');
@@ -94,6 +97,33 @@ export const testHttpClientResDestroyed = {
9497
// },
9598
// };
9699

100+
// TODO(soon): Handle this edge case.
101+
// Test is taken from test/parallel/test-http-client-close-event.js
102+
// export const testHttpClientCloseEvent = {
103+
// async test(_ctrl, env) {
104+
// const { promise, resolve, reject } = Promise.withResolvers();
105+
// const req = http.get({ port: env.PONG_SERVER_PORT }, () => {
106+
// reject(new Error('Should not have called this callback'));
107+
// });
108+
109+
// const errFn = mock.fn((err) => {
110+
// strictEqual(err.constructor, Error);
111+
// strictEqual(err.message, 'socket hang up');
112+
// strictEqual(err.code, 'ECONNRESET');
113+
// });
114+
// req.on('error', errFn);
115+
116+
// req.on('close', () => {
117+
// strictEqual(req.destroyed, true);
118+
// strictEqual(errFn.mock.callCount(), 1);
119+
// resolve();
120+
// });
121+
122+
// req.destroy();
123+
// await promise;
124+
// },
125+
// };
126+
97127
// Test is taken from test/parallel/test-http-client-default-headers-exist.js
98128
export const testHttpClientDefaultHeadersExist = {
99129
async test(_ctrl, env) {
@@ -193,6 +223,50 @@ export const testHttpClientHeadersHostArray = {
193223
},
194224
};
195225

226+
// Test is taken from test/parallel/test-http-client-input-function.js
227+
export const testHttpClientInputFunction = {
228+
async test(_ctrl, env) {
229+
const { promise, resolve } = Promise.withResolvers();
230+
const req = new http.ClientRequest(
231+
{ port: env.PONG_SERVER_PORT },
232+
(response) => {
233+
let body = '';
234+
response.setEncoding('utf8');
235+
response.on('data', (chunk) => {
236+
body += chunk;
237+
});
238+
239+
response.on('end', () => {
240+
strictEqual(body, 'pong');
241+
resolve();
242+
});
243+
}
244+
);
245+
246+
req.end();
247+
await promise;
248+
},
249+
};
250+
251+
// Test is taken from test/parallel/test-http-client-invalid-path.js
252+
export const testHttpClientInvalidPath = {
253+
async test() {
254+
throws(
255+
() => {
256+
http
257+
.request({
258+
path: '/thisisinvalid\uffe2',
259+
})
260+
.end();
261+
},
262+
{
263+
code: 'ERR_UNESCAPED_CHARACTERS',
264+
name: 'TypeError',
265+
}
266+
);
267+
},
268+
};
269+
196270
// Test is taken from test/parallel/test-http-client-unescaped-path.js
197271
export const testHttpClientUnescapedPath = {
198272
async test() {
@@ -213,6 +287,127 @@ export const testHttpClientUnescapedPath = {
213287
},
214288
};
215289

290+
// Test is taken from test/parallel/test-http-request-arguments.js
291+
export const testHttpRequestArguments = {
292+
async test(_ctrl, env) {
293+
const { promise, resolve } = Promise.withResolvers();
294+
http.get(
295+
'http://example.com/testpath',
296+
{ hostname: 'localhost', port: env.REQUEST_ARGUMENTS_PORT },
297+
(res) => {
298+
res.resume();
299+
resolve();
300+
}
301+
);
302+
await promise;
303+
},
304+
};
305+
306+
// Test is taken from test/parallel/test-http-request-dont-override-options.js
307+
export const testHttpRequestDontOverrideOptions = {
308+
async test(_ctrl, env) {
309+
const { promise, resolve } = Promise.withResolvers();
310+
const agent = new http.Agent();
311+
agent.defaultPort = env.PONG_SERVER_PORT;
312+
313+
// Options marked as explicitly undefined for readability
314+
// in this test, they should STAY undefined as options should not
315+
// be mutable / modified
316+
const options = {
317+
host: undefined,
318+
hostname: 'localhost',
319+
port: undefined,
320+
defaultPort: undefined,
321+
path: undefined,
322+
method: undefined,
323+
agent: agent,
324+
};
325+
326+
http
327+
.request(options, function (res) {
328+
res.resume();
329+
strictEqual(options.host, undefined);
330+
strictEqual(options.hostname, 'localhost');
331+
strictEqual(options.port, undefined);
332+
strictEqual(options.defaultPort, undefined);
333+
strictEqual(options.path, undefined);
334+
strictEqual(options.method, undefined);
335+
resolve();
336+
})
337+
.end();
338+
await promise;
339+
},
340+
};
341+
342+
// Test is taken from test/parallel/test-http-request-host-header.js
343+
export const testHttpRequestHostHeader = {
344+
async test(_ctrl, env) {
345+
// From RFC 7230 5.4 https://datatracker.ietf.org/doc/html/rfc7230#section-5.4
346+
// A server MUST respond with a 400 (Bad Request) status code to any
347+
// HTTP/1.1 request message that lacks a Host header field
348+
const { promise, resolve } = Promise.withResolvers();
349+
http.get(
350+
{ port: env.HEADER_VALIDATION_SERVER_PORT, headers: [] },
351+
(res) => {
352+
strictEqual(res.statusCode, 400);
353+
strictEqual(res.headers.connection, 'close');
354+
resolve();
355+
}
356+
);
357+
await promise;
358+
},
359+
};
360+
361+
// Test is taken from test/parallel/test-http-request-invalid-method-error.js
362+
export const testHttpRequestInvalidMethodError = {
363+
async test() {
364+
throws(() => http.request({ method: '\0' }), {
365+
code: 'ERR_INVALID_HTTP_TOKEN',
366+
name: 'TypeError',
367+
message: 'Method must be a valid HTTP token ["\u0000"]',
368+
});
369+
},
370+
};
371+
372+
// Test is taken from test/parallel/test-http-request-join-authorization-headers.js
373+
export const testHttpRequestJoinAuthorizationHeaders = {
374+
async test(_ctrl, env) {
375+
const { promise, resolve } = Promise.withResolvers();
376+
http.get(
377+
{
378+
port: env.HELLO_WORLD_SERVER_PORT,
379+
method: 'POST',
380+
headers: [
381+
'authorization',
382+
'1',
383+
'authorization',
384+
'2',
385+
'cookie',
386+
'foo',
387+
'cookie',
388+
'bar',
389+
],
390+
joinDuplicateHeaders: true,
391+
path: '/join-duplicate-headers',
392+
},
393+
(res) => {
394+
strictEqual(res.statusCode, 200);
395+
strictEqual(res.headers.authorization, '3, 4');
396+
strictEqual(res.headers.cookie, 'foo; bar');
397+
resolve();
398+
}
399+
);
400+
await promise;
401+
},
402+
};
403+
404+
export const testGetExport = {
405+
async test() {
406+
const { get: getFn } = await import('node:http');
407+
deepStrictEqual(get, getFn);
408+
},
409+
};
410+
216411
// Relevant Node.js tests
217412
// - [ ] test/parallel/test-http-client-abort-destroy.js
218413
// - [ ] test/parallel/test-http-client-abort-event.js
@@ -230,26 +425,21 @@ export const testHttpClientUnescapedPath = {
230425
// - [ ] test/parallel/test-http-client-agent-end-close-event.js
231426
// - [ ] test/parallel/test-http-client-agent.js
232427
// - [ ] test/parallel/test-http-client-check-http-token.js
233-
// - [ ] test/parallel/test-http-client-close-event.js
428+
// - [x] test/parallel/test-http-client-close-event.js
234429
// - [ ] test/parallel/test-http-client-close-with-default-agent.js
235430
// - [x] test/parallel/test-http-client-default-headers-exist.js
236431
// - [x] test/parallel/test-http-client-defaults.js
237432
// - [x] test/parallel/test-http-client-encoding.js
238-
// - [ ] test/parallel/test-http-client-error-rawbytes.js
239433
// - [ ] test/parallel/test-http-client-finished.js
240434
// - [ ] test/parallel/test-http-client-get-url.js
241435
// - [ ] test/parallel/test-http-client-headers-array.js
242436
// - [x] test/parallel/test-http-client-headers-host-array.js
243-
// - [ ] test/parallel/test-http-client-immediate-error.js
244437
// - [ ] test/parallel/test-http-client-incomingmessage-destroy.js
245-
// - [ ] test/parallel/test-http-client-input-function.js
246-
// - [ ] test/parallel/test-http-client-insecure-http-parser-error.js
247-
// - [ ] test/parallel/test-http-client-invalid-path.js
438+
// - [x] test/parallel/test-http-client-input-function.js
439+
// - [x] test/parallel/test-http-client-invalid-path.js
248440
// - [ ] test/parallel/test-http-client-keep-alive-hint.js
249441
// - [ ] test/parallel/test-http-client-keep-alive-release-before-finish.js
250442
// - [ ] test/parallel/test-http-client-override-global-agent.js
251-
// - [ ] test/parallel/test-http-client-parse-error.js
252-
// - [ ] test/parallel/test-http-client-pipe-end.js
253443
// - [ ] test/parallel/test-http-client-race-2.js
254444
// - [ ] test/parallel/test-http-client-race.js
255445
// - [ ] test/parallel/test-http-client-read-in-error.js
@@ -260,9 +450,7 @@ export const testHttpClientUnescapedPath = {
260450
// - [ ] test/parallel/test-http-client-req-error-dont-double-fire.js
261451
// - [x] test/parallel/test-http-client-request-options.js
262452
// - [x] test/parallel/test-http-client-res-destroyed.js
263-
// - [ ] test/parallel/test-http-client-response-domain.js
264453
// - [x] test/parallel/test-http-client-response-timeout.js
265-
// - [ ] test/parallel/test-http-client-set-timeout-after-end.js
266454
// - [x] test/parallel/test-http-client-set-timeout.js
267455
// - [ ] test/parallel/test-http-client-spurious-aborted.js
268456
// - [ ] test/parallel/test-http-client-timeout-agent.js
@@ -275,8 +463,26 @@ export const testHttpClientUnescapedPath = {
275463
// - [ ] test/parallel/test-http-client-timeout-with-data.js
276464
// - [ ] test/parallel/test-http-client-timeout.js
277465
// - [x] test/parallel/test-http-client-unescaped-path.js
466+
// - [x] test/parallel/test-http-request-arguments.js
467+
// - [x] test/parallel/test-http-request-dont-override-options.js
468+
// - [ ] test/parallel/test-http-request-end-twice.js
469+
// - [ ] test/parallel/test-http-request-end.js
470+
// - [x] test/parallel/test-http-request-host-header.js
471+
// - [x] test/parallel/test-http-request-invalid-method-error.js
472+
// - [x] test/parallel/test-http-request-join-authorization-headers.js
473+
// - [ ] test/parallel/test-http-request-large-payload.js
474+
// - [ ] test/parallel/test-http-request-smuggling-content-length.js
278475

279476
// Tests doesn't make sense for workerd:
280-
// - [ ] test/parallel/test-http-client-with-create-connection.js
281-
// - [ ] test/parallel/test-http-client-upload-buf.js
282-
// - [ ] test/parallel/test-http-client-upload.js
477+
// - test/parallel/test-http-client-error-rawbytes.js
478+
// - test/parallel/test-http-client-immediate-error.js
479+
// - test/parallel/test-http-client-insecure-http-parser-error.js
480+
// - test/parallel/test-http-client-parse-error.js
481+
// - test/parallel/test-http-client-pipe-end.js
482+
// - test/parallel/test-http-client-response-domain.js
483+
// - test/parallel/test-http-client-set-timeout-after-end.js
484+
// - test/parallel/test-http-client-upload-buf.js
485+
// - test/parallel/test-http-client-upload.js
486+
// - test/parallel/test-http-client-with-create-connection.js
487+
// - test/parallel/test-http-request-method-delete-payload.js
488+
// - test/parallel/test-http-request-methods.js

src/workerd/api/node/tests/http-client-nodejs-test.wd-test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const unitTests :Workerd.Config = (
1313
(name = "PONG_SERVER_PORT", fromEnvironment = "PONG_SERVER_PORT"),
1414
(name = "ASD_SERVER_PORT", fromEnvironment = "ASD_SERVER_PORT"),
1515
(name = "DEFAULT_HEADERS_EXIST_PORT", fromEnvironment = "DEFAULT_HEADERS_EXIST_PORT"),
16+
(name = "REQUEST_ARGUMENTS_PORT", fromEnvironment = "REQUEST_ARGUMENTS_PORT"),
17+
(name = "HELLO_WORLD_SERVER_PORT", fromEnvironment = "HELLO_WORLD_SERVER_PORT"),
1618
],
1719
)
1820
),

src/workerd/api/node/tests/http-nodejs-server.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,6 @@ const helloWorldServer = http.createServer((req, res) => {
5050
res.writeHead(200, { 'Content-Length': '0' });
5151
res.end();
5252
break;
53-
case 'join-duplicate-headers':
54-
res.writeHead(200, [
55-
'authorization',
56-
'3',
57-
'authorization',
58-
'4',
59-
'cookie',
60-
'foo',
61-
'cookie',
62-
'bar',
63-
]);
64-
res.end();
65-
break;
6653
default:
6754
res.end();
6855
}

0 commit comments

Comments
 (0)