diff --git a/test/addons/openssl-client-cert-engine/test.js b/test/addons/openssl-client-cert-engine/test.js index e843e4bf433bff..c6dc9a239214e1 100644 --- a/test/addons/openssl-client-cert-engine/test.js +++ b/test/addons/openssl-client-cert-engine/test.js @@ -1,5 +1,6 @@ 'use strict'; const common = require('../../common'); +const { collectStream } = require('../../common/streams'); const fixture = require('../../common/fixtures'); if (!common.hasCrypto) @@ -44,13 +45,7 @@ const server = https.createServer(serverOptions, common.mustCall((req, res) => { }; const req = https.request(clientOptions, common.mustCall((response) => { - let body = ''; - response.setEncoding('utf8'); - response.on('data', (chunk) => { - body += chunk; - }); - - response.on('end', common.mustCall(() => { + collectStream(response).then(common.mustCall((body) => { assert.strictEqual(body, 'hello world'); server.close(); })); diff --git a/test/addons/openssl-key-engine/test.js b/test/addons/openssl-key-engine/test.js index 2cd7ddabc17095..0a19e738a694ee 100644 --- a/test/addons/openssl-key-engine/test.js +++ b/test/addons/openssl-key-engine/test.js @@ -1,5 +1,6 @@ 'use strict'; const common = require('../../common'); +const { collectStream } = require('../../common/streams'); const fixture = require('../../common/fixtures'); if (!common.hasCrypto) @@ -46,13 +47,7 @@ const server = https.createServer(serverOptions, common.mustCall((req, res) => { }; const req = https.request(clientOptions, common.mustCall((response) => { - let body = ''; - response.setEncoding('utf8'); - response.on('data', (chunk) => { - body += chunk; - }); - - response.on('end', common.mustCall(() => { + collectStream(response).then(common.mustCall((body) => { assert.strictEqual(body, 'hello world'); server.close(); })); diff --git a/test/common/README.md b/test/common/README.md index 5479a39d8c215c..c31a0d7cc316a1 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -19,6 +19,7 @@ This directory contains modules used to test the Node.js implementation. * [Internet module](#internet-module) * [ongc module](#ongc-module) * [Report module](#report-module) +* [Streams module](#streams-module) * [tick module](#tick-module) * [tmpdir module](#tmpdir-module) * [WPT module](#wpt-module) @@ -904,6 +905,65 @@ Validates the schema of a diagnostic report file whose path is specified in Validates the schema of a diagnostic report whose content is specified in `report`. If the report fails validation, an exception is thrown. +## Streams Module + +The `streams` module provides helper functions for stream manipulation. + +### `collectChildStreams(child[, waitFor])` + +* return [<Promise>][] + +Uses `collectStream` to collect `child.stdout`, `child.stderr` streams if +available, optionally waits for `waitFor` argument and resolves with an +object `{ stdout, stderr, data }` where `stdout`, `stderr` are strings of +respective collected streams and `data` is the result of `waitFor` or +`undefined`. + +```js +const common = require('../common'); +const { spawn } = require('child_process'); +const { once } = require('events'); + +const child = spawn(...common.pwdCommand); +common.collectChildStreams(child, once(child, 'exit')) + .then(({ stdout, stderr, data: [code, signal] }) => { + // ... + }); +``` + +### `collectStream(readable[, callback])` + +* return [<Promise>][] + +Uses async iterator to collect the data from the `readable` into a string and +returns it via Promise or callback if provided. Always sets encoding to `'utf8'`. + +```js +const common = require('../common'); +const http = require('assert'); +const assert = require('assert'); + +http.request({ /* path, port */ }, (res) => { + common.collectStream(res).then((body) => { + assert.strictEqual(body, 'hello'); + }); +}); +``` + +Or using callbacks: +```js +const common = require('../common'); +const http = require('assert'); +const assert = require('assert'); + +http.request({ /* path, port */ }, (res) => { + common.collectStream(res, (err, body) => { + assert.ifError(err); + assert.strictEqual(body, 'hello'); + }); +}); +``` + ## tick Module The `tick` module provides a helper function that can be used to call a callback @@ -958,6 +1018,7 @@ See [the WPT tests README][] for details. [<Error>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error [<Function>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function [<Object>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object +[<Promise>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise [<RegExp>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp [<bigint>]: https://github.com/tc39/proposal-bigint [<boolean>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type diff --git a/test/common/streams.js b/test/common/streams.js new file mode 100644 index 00000000000000..96d58fc44b0014 --- /dev/null +++ b/test/common/streams.js @@ -0,0 +1,32 @@ +/* eslint-disable node-core/require-common-first, node-core/required-modules */ +'use strict'; + +async function collectStream(readable, callback) { + let data = ''; + try { + readable.setEncoding('utf8'); + for await (const chunk of readable) + data += chunk; + if (typeof callback === 'function') + process.nextTick(callback, null, data); + return data; + } catch (err) { + if (typeof callback === 'function') { + process.nextTick(callback, err); + } else { + throw err; + } + } +} + +function collectChildStreams(child, waitFor) { + const stdout = child.stdout && collectStream(child.stdout); + const stderr = child.stderr && collectStream(child.stderr); + return Promise.all([stdout, stderr, waitFor]) + .then(([stdout, stderr, data]) => ({ stdout, stderr, data })); +} + +module.exports = { + collectChildStreams, + collectStream, +}; diff --git a/test/parallel/test-cli-node-options.js b/test/parallel/test-cli-node-options.js index 49f8371a1aaf08..521c747baedd59 100644 --- a/test/parallel/test-cli-node-options.js +++ b/test/parallel/test-cli-node-options.js @@ -9,6 +9,7 @@ const assert = require('assert'); const exec = require('child_process').execFile; const { Worker } = require('worker_threads'); +const { collectStream } = require('../common/streams'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); @@ -112,15 +113,6 @@ function expect( workerTest(opts, command, wantsError, test('worker')); } -async function collectStream(readable) { - readable.setEncoding('utf8'); - let data = ''; - for await (const chunk of readable) { - data += chunk; - } - return data; -} - function workerTest(opts, command, wantsError, test) { let workerError = null; const worker = new Worker(command, { diff --git a/test/parallel/test-tracing-no-crash.js b/test/parallel/test-tracing-no-crash.js index 0ae402f5288cca..fe6f551abb8dd3 100644 --- a/test/parallel/test-tracing-no-crash.js +++ b/test/parallel/test-tracing-no-crash.js @@ -1,22 +1,18 @@ 'use strict'; const common = require('../common'); +const { collectChildStreams } = require('../common/streams'); const assert = require('assert'); +const { once } = require('events'); const { spawn } = require('child_process'); -function CheckNoSignalAndErrorCodeOne(code, signal) { - assert.strictEqual(signal, null); - assert.strictEqual(code, 1); -} - const child = spawn(process.execPath, [ '--trace-event-categories', 'madeup', '-e', 'throw new Error()' ], { stdio: [ 'inherit', 'inherit', 'pipe' ] }); -child.on('exit', common.mustCall(CheckNoSignalAndErrorCodeOne)); -let stderr; -child.stderr.setEncoding('utf8'); -child.stderr.on('data', (chunk) => stderr += chunk); -child.stderr.on('end', common.mustCall(() => { - assert(stderr.includes('throw new Error()'), stderr); - assert(!stderr.includes('Could not open trace file'), stderr); -})); +collectChildStreams(child, once(child, 'exit')) + .then(common.mustCall(({ stderr, data: [code, signal] }) => { + assert(stderr.includes('throw new Error()'), stderr); + assert(!stderr.includes('Could not open trace file'), stderr); + assert.strictEqual(signal, null); + assert.strictEqual(code, 1); + }));