From 7f90f6364900b5b73b56eecec7c7bd2094f4eb34 Mon Sep 17 00:00:00 2001 From: Aras Abbasi Date: Mon, 12 Feb 2024 12:01:44 +0100 Subject: [PATCH] chore: migrate a batch of tests to node test runner (#2737) --- test/client-connect.js | 46 ++-- test/client-idempotent-body.js | 17 +- test/client-keep-alive.js | 478 +++++++++++++++++---------------- test/dispatcher.js | 6 +- test/errors.js | 32 +-- test/examples.js | 35 ++- test/headers-as-array.js | 94 ++++--- test/headers-crlf.js | 57 ++-- test/http-100.js | 195 +++++++------- test/inflight-and-close.js | 54 ++-- 10 files changed, 547 insertions(+), 467 deletions(-) diff --git a/test/client-connect.js b/test/client-connect.js index 4917a526d0e..e002a42c571 100644 --- a/test/client-connect.js +++ b/test/client-connect.js @@ -1,14 +1,16 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') +const { once } = require('node:events') const { Client, errors } = require('..') const http = require('node:http') const EE = require('node:events') const { kBusy } = require('../lib/core/symbols') // TODO: move to test/node-test/client-connect.js -test('connect aborted after connect', (t) => { - t.plan(3) +test('connect aborted after connect', async (t) => { + t = tspl(t, { plan: 3 }) const signal = new EE() const server = http.createServer((req, res) => { @@ -17,22 +19,26 @@ test('connect aborted after connect', (t) => { server.on('connect', (req, c, firstBodyChunk) => { signal.emit('abort') }) - t.teardown(server.close.bind(server)) - - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - pipelining: 3 - }) - t.teardown(client.destroy.bind(client)) - - client.connect({ - path: '/', - signal, - opaque: 'asd' - }, (err, { opaque }) => { - t.equal(opaque, 'asd') - t.ok(err instanceof errors.RequestAbortedError) - }) - t.equal(client[kBusy], true) + after(() => server.close()) + + server.listen(0) + + await once(server, 'listening') + + const client = new Client(`http://localhost:${server.address().port}`, { + pipelining: 3 }) + after(() => client.close()) + + client.connect({ + path: '/', + signal, + opaque: 'asd' + }, (err, { opaque }) => { + t.strictEqual(opaque, 'asd') + t.ok(err instanceof errors.RequestAbortedError) + }) + t.strictEqual(client[kBusy], true) + + await t.completed }) diff --git a/test/client-idempotent-body.js b/test/client-idempotent-body.js index 0575b6b8ebd..07004cb8296 100644 --- a/test/client-idempotent-body.js +++ b/test/client-idempotent-body.js @@ -1,11 +1,12 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { Client } = require('..') const { createServer } = require('node:http') -test('idempotent retry', (t) => { - t.plan(11) +test('idempotent retry', async (t) => { + t = tspl(t, { plan: 11 }) const body = 'world' const server = createServer((req, res) => { @@ -13,17 +14,17 @@ test('idempotent retry', (t) => { req.on('data', data => { buf += data }).on('end', () => { - t.strictSame(buf, body) + t.strictEqual(buf, body) res.end() }) }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 2 }) - t.teardown(client.close.bind(client)) + after(() => client.close()) const _err = new Error() @@ -36,8 +37,10 @@ test('idempotent retry', (t) => { }, () => { throw _err }, (err) => { - t.equal(err, _err) + t.strictEqual(err, _err) }) } }) + + await t.completed }) diff --git a/test/client-keep-alive.js b/test/client-keep-alive.js index 15e432c7b2c..b521624caec 100644 --- a/test/client-keep-alive.js +++ b/test/client-keep-alive.js @@ -1,6 +1,8 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') +const { once } = require('node:events') const { Client } = require('..') const timers = require('../lib/timers') const { kConnect } = require('../lib/core/symbols') @@ -8,8 +10,8 @@ const { createServer } = require('node:net') const http = require('node:http') const FakeTimers = require('@sinonjs/fake-timers') -test('keep-alive header', (t) => { - t.plan(2) +test('keep-alive header', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -18,41 +20,41 @@ test('keep-alive header', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) - - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 4e3) - client.on('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + after(() => server.close()) + + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 4e3) + client.on('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() }) + await t.completed }) -test('keep-alive header 0', (t) => { - t.plan(2) +test('keep-alive header 0', async (t) => { + t = tspl(t, { plan: 2 }) const clock = FakeTimers.install() - t.teardown(clock.uninstall.bind(clock)) + after(() => clock.uninstall()) const orgTimers = { ...timers } Object.assign(timers, { setTimeout, clearTimeout }) - t.teardown(() => { - Object.assign(timers, orgTimers) - }) + after(() => { Object.assign(timers, orgTimers) }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -61,31 +63,33 @@ test('keep-alive header 0', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - keepAliveTimeoutThreshold: 500 - }) - t.teardown(client.destroy.bind(client)) + server.listen(0) - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - client.on('disconnect', () => { - t.ok(true, 'pass') - }) - clock.tick(600) - }).resume() - }) + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { + keepAliveTimeoutThreshold: 500 }) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + client.on('disconnect', () => { + t.ok(true, 'pass') + }) + clock.tick(600) + }).resume() + }) + await t.completed }) -test('keep-alive header 1', (t) => { - t.plan(2) +test('keep-alive header 1', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -94,32 +98,34 @@ test('keep-alive header 1', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) - - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 0) - client.on('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + after(() => server.close()) + + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 0) + client.on('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() }) + await t.completed }) -test('keep-alive header no postfix', (t) => { - t.plan(2) +test('keep-alive header no postfix', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -128,32 +134,34 @@ test('keep-alive header no postfix', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) - - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 4e3) - client.on('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + after(() => server.close()) + + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 4e3) + client.on('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() }) + await t.completed }) -test('keep-alive not timeout', (t) => { - t.plan(2) +test('keep-alive not timeout', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -162,34 +170,36 @@ test('keep-alive not timeout', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - keepAliveTimeout: 1e3 - }) - t.teardown(client.destroy.bind(client)) + server.listen(0) - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 3e3) - client.on('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { + keepAliveTimeout: 1e3 }) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 3e3) + client.on('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() + }) + await t.completed }) -test('keep-alive threshold', (t) => { - t.plan(2) +test('keep-alive threshold', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -198,35 +208,37 @@ test('keep-alive threshold', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - keepAliveTimeout: 30e3, - keepAliveTimeoutThreshold: 29e3 - }) - t.teardown(client.destroy.bind(client)) + server.listen(0) - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 5e3) - client.on('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { + keepAliveTimeout: 30e3, + keepAliveTimeoutThreshold: 29e3 }) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 5e3) + client.on('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() + }) + await t.completed }) -test('keep-alive max keepalive', (t) => { - t.plan(2) +test('keep-alive max keepalive', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((socket) => { socket.write('HTTP/1.1 200 OK\r\n') @@ -235,35 +247,37 @@ test('keep-alive max keepalive', (t) => { socket.write('Connection: keep-alive\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - keepAliveTimeout: 30e3, - keepAliveMaxTimeout: 1e3 - }) - t.teardown(client.destroy.bind(client)) + server.listen(0) - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 3e3) - client.on('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { + keepAliveTimeout: 30e3, + keepAliveMaxTimeout: 1e3 }) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 3e3) + client.on('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() + }) + await t.completed }) -test('connection close', (t) => { - t.plan(4) +test('connection close', async (t) => { + t = tspl(t, { plan: 4 }) let close = false const server = createServer((socket) => { @@ -276,84 +290,88 @@ test('connection close', (t) => { socket.write('Connection: close\r\n') socket.write('\r\n\r\n') }) - t.teardown(server.close.bind(server)) + after(() => server.close()) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - pipelining: 2 - }) - t.teardown(client.destroy.bind(client)) + server.listen(0) - client[kConnect](() => { - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 3e3) - client.once('disconnect', () => { - close = false - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { + pipelining: 2 + }) + after(() => client.close()) - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - const timeout = setTimeout(() => { - t.fail() - }, 3e3) - client.once('disconnect', () => { - t.ok(true, 'pass') - clearTimeout(timeout) - }) - }).resume() - }) + client[kConnect](() => { + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 3e3) + client.once('disconnect', () => { + close = false + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() + }) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + const timeout = setTimeout(() => { + t.fail() + }, 3e3) + client.once('disconnect', () => { + t.ok(true, 'pass') + clearTimeout(timeout) + }) + }).resume() }) }) + await t.completed }) -test('Disable keep alive', (t) => { - t.plan(7) +test('Disable keep alive', async (t) => { + t = tspl(t, { plan: 7 }) const ports = [] const server = http.createServer((req, res) => { - t.notOk(ports.includes(req.socket.remotePort)) + t.strictEqual(ports.includes(req.socket.remotePort), false) ports.push(req.socket.remotePort) - t.match(req.headers, { connection: 'close' }) + t.strictEqual(req.headers.connection, 'close') res.writeHead(200, { connection: 'close' }) res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 0 }) - t.teardown(client.destroy.bind(client)) + server.listen(0) - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - client.request({ - path: '/', - method: 'GET' - }, (err, { body }) => { - t.error(err) - body.on('end', () => { - t.ok(true, 'pass') - }).resume() - }) - }).resume() - }) + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { pipelining: 0 }) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + client.request({ + path: '/', + method: 'GET' + }, (err, { body }) => { + t.ifError(err) + body.on('end', () => { + t.ok(true, 'pass') + }).resume() + }) + }).resume() }) + await t.completed }) diff --git a/test/dispatcher.js b/test/dispatcher.js index 22750a1e81c..d004c5e5e27 100644 --- a/test/dispatcher.js +++ b/test/dispatcher.js @@ -1,14 +1,14 @@ 'use strict' -const t = require('tap') -const { test } = t +const { tspl } = require('@matteo.collina/tspl') +const { test } = require('node:test') const Dispatcher = require('../lib/dispatcher') class PoorImplementation extends Dispatcher {} test('dispatcher implementation', (t) => { - t.plan(6) + t = tspl(t, { plan: 6 }) const dispatcher = new Dispatcher() t.throws(() => dispatcher.dispatch(), Error, 'throws on unimplemented dispatch') diff --git a/test/errors.js b/test/errors.js index a6f17ef9b09..e34b406a905 100644 --- a/test/errors.js +++ b/test/errors.js @@ -1,7 +1,7 @@ 'use strict' -const t = require('tap') -const { test } = t +const { tspl } = require('@matteo.collina/tspl') +const { describe, test } = require('node:test') const errors = require('../lib/core/errors') @@ -31,51 +31,47 @@ const scenarios = [ ] scenarios.forEach(scenario => { - test(scenario.name, t => { + describe(scenario.name, () => { const SAMPLE_MESSAGE = 'sample message' const errorWithDefaultMessage = () => new scenario.ErrorClass() const errorWithProvidedMessage = () => new scenario.ErrorClass(SAMPLE_MESSAGE) test('should use default message', t => { - t.plan(1) + t = tspl(t, { plan: 1 }) const error = errorWithDefaultMessage() - t.equal(error.message, scenario.defaultMessage) + t.strictEqual(error.message, scenario.defaultMessage) }) test('should use provided message', t => { - t.plan(1) + t = tspl(t, { plan: 1 }) const error = errorWithProvidedMessage() - t.equal(error.message, SAMPLE_MESSAGE) + t.strictEqual(error.message, SAMPLE_MESSAGE) }) test('should have proper fields', t => { - t.plan(6) + t = tspl(t, { plan: 6 }) const errorInstances = [errorWithDefaultMessage(), errorWithProvidedMessage()] errorInstances.forEach(error => { - t.equal(error.name, scenario.name) - t.equal(error.code, scenario.code) + t.strictEqual(error.name, scenario.name) + t.strictEqual(error.code, scenario.code) t.ok(error.stack) }) }) - - t.end() }) }) -test('Default HTTPParseError Codes', t => { +describe('Default HTTPParseError Codes', () => { test('code and data should be undefined when not set', t => { - t.plan(2) + t = tspl(t, { plan: 2 }) const error = new errors.HTTPParserError('HTTPParserError') - t.equal(error.code, undefined) - t.equal(error.data, undefined) + t.strictEqual(error.code, undefined) + t.strictEqual(error.data, undefined) }) - - t.end() }) diff --git a/test/examples.js b/test/examples.js index 7096970662f..d344236b68d 100644 --- a/test/examples.js +++ b/test/examples.js @@ -1,10 +1,14 @@ 'use strict' +const { tspl } = require('@matteo.collina/tspl') const { createServer } = require('node:http') -const { test } = require('tap') +const { test, after } = require('node:test') +const { once } = require('node:events') const examples = require('../examples/request.js') test('request examples', async (t) => { + t = tspl(t, { plan: 7 }) + let lastReq const exampleServer = createServer((req, res) => { lastReq = req @@ -32,28 +36,33 @@ test('request examples', async (t) => { res.end('{"error":"an error"}') }) - t.teardown(exampleServer.close.bind(exampleServer)) - t.teardown(errorServer.close.bind(errorServer)) + after(() => exampleServer.close()) + after(() => errorServer.close()) + + exampleServer.listen(0) + errorServer.listen(0) - await exampleServer.listen(0) - await errorServer.listen(0) + await Promise.all([ + once(exampleServer, 'listening'), + once(errorServer, 'listening') + ]) await examples.getRequest(exampleServer.address().port) - t.equal(lastReq.method, 'GET') + t.strictEqual(lastReq.method, 'GET') await examples.postJSONRequest(exampleServer.address().port) - t.equal(lastReq.method, 'POST') - t.equal(lastReq.headers['content-type'], 'application/json') + t.strictEqual(lastReq.method, 'POST') + t.strictEqual(lastReq.headers['content-type'], 'application/json') await examples.postFormRequest(exampleServer.address().port) - t.equal(lastReq.method, 'POST') - t.equal(lastReq.headers['content-type'], 'application/x-www-form-urlencoded') + t.strictEqual(lastReq.method, 'POST') + t.strictEqual(lastReq.headers['content-type'], 'application/x-www-form-urlencoded') await examples.deleteRequest(exampleServer.address().port) - t.equal(lastReq.method, 'DELETE') + t.strictEqual(lastReq.method, 'DELETE') await examples.deleteRequest(errorServer.address().port) - t.equal(lastReq.method, 'DELETE') + t.strictEqual(lastReq.method, 'DELETE') - t.end() + await t.completed }) diff --git a/test/headers-as-array.js b/test/headers-as-array.js index e50605332e5..693979e92b7 100644 --- a/test/headers-as-array.js +++ b/test/headers-as-array.js @@ -1,102 +1,122 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { Client, errors } = require('..') const { createServer } = require('node:http') -test('handle headers as array', (t) => { - t.plan(1) +test('handle headers as array', async (t) => { + t = tspl(t, { plan: 3 }) const headers = ['a', '1', 'b', '2', 'c', '3'] const server = createServer((req, res) => { - t.match(req.headers, { a: '1', b: '2', c: '3' }) + t.strictEqual(req.headers.a, '1') + t.strictEqual(req.headers.b, '2') + t.strictEqual(req.headers.c, '3') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers - }, () => {}) + }, () => { }) }) + + await t.completed }) -test('handle multi-valued headers as array', (t) => { - t.plan(1) +test('handle multi-valued headers as array', async (t) => { + t = tspl(t, { plan: 4 }) const headers = ['a', '1', 'b', '2', 'c', '3', 'd', '4', 'd', '5'] const server = createServer((req, res) => { - t.match(req.headers, { a: '1', b: '2', c: '3', d: '4, 5' }) + t.strictEqual(req.headers.a, '1') + t.strictEqual(req.headers.b, '2') + t.strictEqual(req.headers.c, '3') + t.strictEqual(req.headers.d, '4, 5') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers - }, () => {}) + }, () => { }) }) + + await t.completed }) -test('handle headers with array', (t) => { - t.plan(1) +test('handle headers with array', async (t) => { + t = tspl(t, { plan: 4 }) const headers = { a: '1', b: '2', c: '3', d: ['4'] } const server = createServer((req, res) => { - t.match(req.headers, { a: '1', b: '2', c: '3', d: '4' }) + t.strictEqual(req.headers.a, '1') + t.strictEqual(req.headers.b, '2') + t.strictEqual(req.headers.c, '3') + t.strictEqual(req.headers.d, '4') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers - }, () => {}) + }, () => { }) }) + + await t.completed }) -test('handle multi-valued headers', (t) => { - t.plan(1) +test('handle multi-valued headers', async (t) => { + t = tspl(t, { plan: 4 }) const headers = { a: '1', b: '2', c: '3', d: ['4', '5'] } const server = createServer((req, res) => { - t.match(req.headers, { a: '1', b: '2', c: '3', d: '4, 5' }) + t.strictEqual(req.headers.a, '1') + t.strictEqual(req.headers.b, '2') + t.strictEqual(req.headers.c, '3') + t.strictEqual(req.headers.d, '4, 5') res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.close()) client.request({ path: '/', method: 'GET', headers - }, () => {}) + }, () => { }) }) + + await t.completed }) -test('fail if headers array is odd', (t) => { - t.plan(2) +test('fail if headers array is odd', async (t) => { + t = tspl(t, { plan: 2 }) const headers = ['a', '1', 'b', '2', 'c', '3', 'd'] const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -104,20 +124,22 @@ test('fail if headers array is odd', (t) => { headers }, (err) => { t.ok(err instanceof errors.InvalidArgumentError) - t.equal(err.message, 'headers array must be even') + t.strictEqual(err.message, 'headers array must be even') }) }) + + await t.completed }) -test('fail if headers is not an object or an array', (t) => { - t.plan(2) +test('fail if headers is not an object or an array', async (t) => { + t = tspl(t, { plan: 2 }) const headers = 'not an object or an array' const server = createServer((req, res) => { res.end() }) - t.teardown(server.close.bind(server)) + after(() => server.close()) server.listen(0, () => { const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) + after(() => client.close()) client.request({ path: '/', @@ -125,7 +147,9 @@ test('fail if headers is not an object or an array', (t) => { headers }, (err) => { t.ok(err instanceof errors.InvalidArgumentError) - t.equal(err.message, 'headers must be an object or an array') + t.strictEqual(err.message, 'headers must be an object or an array') }) }) + + await t.completed }) diff --git a/test/headers-crlf.js b/test/headers-crlf.js index d41e924aca1..8660259dbbd 100644 --- a/test/headers-crlf.js +++ b/test/headers-crlf.js @@ -1,36 +1,41 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') +const { once } = require('node:events') const { Client } = require('..') const { createServer } = require('node:http') -test('CRLF Injection in Nodejs ‘undici’ via host', (t) => { - t.plan(1) +test('CRLF Injection in Nodejs ‘undici’ via host', async (t) => { + t = tspl(t, { plan: 1 }) const server = createServer(async (req, res) => { res.end() }) - t.teardown(server.close.bind(server)) - - server.listen(0, async () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.close.bind(client)) - - const unsanitizedContentTypeInput = '12 \r\n\r\naaa:aaa' - - try { - const { body } = await client.request({ - path: '/', - method: 'POST', - headers: { - 'content-type': 'application/json', - host: unsanitizedContentTypeInput - }, - body: 'asd' - }) - await body.dump() - } catch (err) { - t.same(err.code, 'UND_ERR_INVALID_ARG') - } - }) + after(() => server.close()) + + server.listen(0) + + await once(server, 'listening') + + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + const unsanitizedContentTypeInput = '12 \r\n\r\naaa:aaa' + + try { + const { body } = await client.request({ + path: '/', + method: 'POST', + headers: { + 'content-type': 'application/json', + host: unsanitizedContentTypeInput + }, + body: 'asd' + }) + await body.dump() + } catch (err) { + t.strictEqual(err.code, 'UND_ERR_INVALID_ARG') + } + await t.completed }) diff --git a/test/http-100.js b/test/http-100.js index 434b53a5c2f..43e75a02e10 100644 --- a/test/http-100.js +++ b/test/http-100.js @@ -1,41 +1,46 @@ 'use strict' -const { test } = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test, after } = require('node:test') const { Client } = require('..') const { createServer } = require('node:http') const net = require('node:net') +const { once } = require('node:events') -test('ignore informational response', (t) => { - t.plan(2) +test('ignore informational response', async (t) => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.writeProcessing() req.pipe(res) }) - t.teardown(server.close.bind(server)) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'POST', - body: 'hello' - }, (err, response) => { - t.error(err) - const bufs = [] - response.body.on('data', (buf) => { - bufs.push(buf) - }) - response.body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) - }) + after(() => server.close()) + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'POST', + body: 'hello' + }, (err, response) => { + t.ifError(err) + const bufs = [] + response.body.on('data', (buf) => { + bufs.push(buf) + }) + response.body.on('end', () => { + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) + + await t.completed }) -test('error 103 body', (t) => { - t.plan(2) +test('error 103 body', async (t) => { + t = tspl(t, { plan: 2 }) const server = net.createServer((socket) => { socket.write('HTTP/1.1 103 Early Hints\r\n') @@ -43,99 +48,107 @@ test('error 103 body', (t) => { socket.write('\r\n') socket.write('a\r\n') }) - t.teardown(server.close.bind(server)) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'GET' - }, (err) => { - t.equal(err.code, 'HPE_INVALID_CONSTANT') - }) - client.on('disconnect', () => { - t.ok(true, 'pass') - }) + after(() => server.close()) + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err) => { + t.strictEqual(err.code, 'HPE_INVALID_CONSTANT') }) + client.on('disconnect', () => { + t.ok(true, 'pass') + }) + await t.completed }) -test('error 100 body', (t) => { - t.plan(2) +test('error 100 body', async (t) => { + t = tspl(t, { plan: 2 }) const server = net.createServer((socket) => { socket.write('HTTP/1.1 100 Early Hints\r\n') socket.write('\r\n') }) - t.teardown(server.close.bind(server)) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'GET' - }, (err) => { - t.equal(err.message, 'bad response') - }) - client.on('disconnect', () => { - t.ok(true, 'pass') - }) + after(() => server.close()) + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err) => { + t.strictEqual(err.message, 'bad response') }) + client.on('disconnect', () => { + t.ok(true, 'pass') + }) + await t.completed }) -test('error 101 upgrade', (t) => { - t.plan(2) +test('error 101 upgrade', async (t) => { + t = tspl(t, { plan: 2 }) const server = net.createServer((socket) => { socket.write('HTTP/1.1 101 Switching Protocols\r\nUpgrade: example/1\r\nConnection: Upgrade\r\n') socket.write('\r\n') }) - t.teardown(server.close.bind(server)) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'GET' - }, (err) => { - t.equal(err.message, 'bad upgrade') - }) - client.on('disconnect', () => { - t.ok(true, 'pass') - }) + after(() => server.close()) + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`) + after(() => client.close()) + + client.request({ + path: '/', + method: 'GET' + }, (err) => { + t.strictEqual(err.message, 'bad upgrade') }) + client.on('disconnect', () => { + t.ok(true, 'pass') + }) + await t.completed }) -test('1xx response without timeouts', t => { - t.plan(2) +test('1xx response without timeouts', async t => { + t = tspl(t, { plan: 2 }) const server = createServer((req, res) => { res.writeProcessing() setTimeout(() => req.pipe(res), 2000) }) - t.teardown(server.close.bind(server)) - server.listen(0, () => { - const client = new Client(`http://localhost:${server.address().port}`, { - bodyTimeout: 0, - headersTimeout: 0 + after(() => server.close()) + server.listen(0) + + await once(server, 'listening') + const client = new Client(`http://localhost:${server.address().port}`, { + bodyTimeout: 0, + headersTimeout: 0 + }) + after(() => client.close()) + + client.request({ + path: '/', + method: 'POST', + body: 'hello' + }, (err, response) => { + t.ifError(err) + const bufs = [] + response.body.on('data', (buf) => { + bufs.push(buf) }) - t.teardown(client.destroy.bind(client)) - - client.request({ - path: '/', - method: 'POST', - body: 'hello' - }, (err, response) => { - t.error(err) - const bufs = [] - response.body.on('data', (buf) => { - bufs.push(buf) - }) - response.body.on('end', () => { - t.equal('hello', Buffer.concat(bufs).toString('utf8')) - }) + response.body.on('end', () => { + t.strictEqual('hello', Buffer.concat(bufs).toString('utf8')) }) }) + await t.completed }) diff --git a/test/inflight-and-close.js b/test/inflight-and-close.js index 576a8c568ff..075cdba1668 100644 --- a/test/inflight-and-close.js +++ b/test/inflight-and-close.js @@ -1,31 +1,37 @@ 'use strict' -const t = require('tap') +const { tspl } = require('@matteo.collina/tspl') +const { test } = require('node:test') const { request } = require('..') const http = require('node:http') -const server = http.createServer((req, res) => { - res.writeHead(200) - res.end('Response body') - res.socket.end() // Close the connection immediately with every response -}).listen(0, '127.0.0.1', function () { - const url = `http://127.0.0.1:${this.address().port}` - request(url) - .then(({ statusCode, headers, body }) => { - t.ok(true, 'first response') - body.resume() - body.on('close', function () { - t.ok(true, 'first body closed') - }) - return request(url) - .then(({ statusCode, headers, body }) => { - t.ok(true, 'second response') - body.resume() - body.on('close', function () { - server.close() - }) +test('inflight and close', async (t) => { + t = tspl(t, { plan: 3 }) + + const server = http.createServer((req, res) => { + res.writeHead(200) + res.end('Response body') + res.socket.end() // Close the connection immediately with every response + }).listen(0, '127.0.0.1', function () { + const url = `http://127.0.0.1:${this.address().port}` + request(url) + .then(({ statusCode, headers, body }) => { + t.ok(true, 'first response') + body.resume() + body.on('close', function () { + t.ok(true, 'first body closed') }) - }).catch((err) => { - t.error(err) - }) + return request(url) + .then(({ statusCode, headers, body }) => { + t.ok(true, 'second response') + body.resume() + body.on('close', function () { + server.close() + }) + }) + }).catch((err) => { + t.ifError(err) + }) + }) + await t.completed })