diff --git a/test/parallel/test-async-hooks-http-parser-destroy.js b/test/parallel/test-async-hooks-http-parser-destroy.js index d2e1071c280d66..794f53ff8c4a21 100644 --- a/test/parallel/test-async-hooks-http-parser-destroy.js +++ b/test/parallel/test-async-hooks-http-parser-destroy.js @@ -1,6 +1,5 @@ 'use strict'; -const common = require('../common'); -const Countdown = require('../common/countdown'); +require('../common'); const assert = require('assert'); const async_hooks = require('async_hooks'); const http = require('http'); @@ -12,50 +11,58 @@ const http = require('http'); const N = 50; const KEEP_ALIVE = 100; -const createdIds = []; -const destroyedIds = []; +// XXX (trott): 'destroy' event can happen more than once for some asyncIds. +// Using a Set for now to work around the bug, but it can be simplified perhaps +// once https://github.com/nodejs/node/issues/26961 is fixed. +const createdIds = new Set(); +const destroyedIds = new Set(); async_hooks.createHook({ - init: common.mustCallAtLeast((asyncId, type) => { + init: (asyncId, type) => { if (type === 'HTTPPARSER') { - createdIds.push(asyncId); + createdIds.add(asyncId); } - }, N), + }, destroy: (asyncId) => { - destroyedIds.push(asyncId); + if (createdIds.has(asyncId)) { + destroyedIds.add(asyncId); + // Each HTTP request results in two createdIds and two destroyedIds. + if (destroyedIds.size === N * 2) + server.close(); + } } }).enable(); -const server = http.createServer(function(req, res) { - res.end('Hello'); -}); +const server = http.createServer((req, res) => { res.end('Hello'); }); const keepAliveAgent = new http.Agent({ keepAlive: true, keepAliveMsecs: KEEP_ALIVE, }); -const countdown = new Countdown(N, () => { - server.close(() => { - // Give the server sockets time to close (which will also free their - // associated parser objects) after the server has been closed. - setTimeout(() => { - createdIds.forEach((createdAsyncId) => { - assert.ok(destroyedIds.indexOf(createdAsyncId) >= 0); - }); - }, KEEP_ALIVE * 2); - }); -}); - -server.listen(0, function() { +server.listen(0, () => { for (let i = 0; i < N; ++i) { - (function makeRequest() { - http.get({ - port: server.address().port, - agent: keepAliveAgent - }, function(res) { - countdown.dec(); - res.resume(); - }); - })(); + http.get( + { port: server.address().port, agent: keepAliveAgent }, + (res) => { res.resume(); } + ); } }); + +function checkOnExit() { + assert.deepStrictEqual(destroyedIds, createdIds); + // Each HTTP request results in two createdIds and two destroyedIds. + assert.strictEqual(createdIds.size, N * 2); +} + +// Ordinary exit. +process.on('exit', checkOnExit); + +// Test runner tools/test.py will send SIGTERM if timeout. +// Signals aren't received in workers, but that's OK. The test will still fail +// if it times out. It just won't provide the additional information that this +// handler does. +process.on('SIGTERM', () => { + console.error('Received SIGTERM. (Timed out?)'); + checkOnExit(); + process.exit(1); +});