Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/common/assertSnapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...
test({ skip: 'Skipping pseudo-tty tests, as pseudo terminals are not available on Windows.' });
return;
}
let flags = common.parseTestFlags(filename);
let { flags } = common.parseTestMetadata(filename);
if (options.flags) {
flags = [...options.flags, ...flags];
}
Expand Down
63 changes: 47 additions & 16 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,16 @@ const hasSQLite = Boolean(process.versions.sqlite);

const hasQuic = hasCrypto && !!process.config.variables.node_quic;

function parseTestFlags(filename = process.argv[1]) {
// The copyright notice is relatively big and the flags could come afterwards.
/**
* Parse test metadata from the specified file.
* @param {string} filename - The name of the file to parse.
* @returns {{
* flags: string[],
* envs: Record<string, string>
* }} An object containing the parsed flags and environment variables.
*/
function parseTestMetadata(filename = process.argv[1]) {
// The copyright notice is relatively big and the metadata could come afterwards.
const bytesToRead = 1500;
const buffer = Buffer.allocUnsafe(bytesToRead);
const fd = fs.openSync(filename, 'r');
Expand All @@ -68,19 +76,33 @@ function parseTestFlags(filename = process.argv[1]) {
const source = buffer.toString('utf8', 0, bytesRead);

const flagStart = source.search(/\/\/ Flags:\s+--/) + 10;

if (flagStart === 9) {
return [];
let flags = [];
if (flagStart !== 9) {
let flagEnd = source.indexOf('\n', flagStart);
if (source[flagEnd - 1] === '\r') {
flagEnd--;
}
flags = source
.substring(flagStart, flagEnd)
.split(/\s+/)
.filter(Boolean);
}
let flagEnd = source.indexOf('\n', flagStart);
// Normalize different EOL.
if (source[flagEnd - 1] === '\r') {
flagEnd--;

const envStart = source.search(/\/\/ Env:\s+/) + 8;
let envs = {};
if (envStart !== 7) {
let envEnd = source.indexOf('\n', envStart);
if (source[envEnd - 1] === '\r') {
envEnd--;
}
const envArray = source
.substring(envStart, envEnd)
.split(/\s+/)
.filter(Boolean);
envs = Object.fromEntries(envArray.map((env) => env.split('=')));
}
return source
.substring(flagStart, flagEnd)
.split(/\s+/)
.filter(Boolean);

return { flags, envs };
}

// Check for flags. Skip this for workers (both, the `cluster` module and
Expand All @@ -93,7 +115,7 @@ if (process.argv.length === 2 &&
hasCrypto &&
require('cluster').isPrimary &&
fs.existsSync(process.argv[1])) {
const flags = parseTestFlags();
const { flags, envs } = parseTestMetadata();
for (const flag of flags) {
if (!process.execArgv.includes(flag) &&
// If the binary is build without `intl` the inspect option is
Expand All @@ -102,11 +124,20 @@ if (process.argv.length === 2 &&
console.log(
'NOTE: The test started as a child_process using these flags:',
inspect(flags),
'And these environment variables:',
inspect(envs),
'Use NODE_SKIP_FLAG_CHECK to run the test with the original flags.',
);
const { spawnSync } = require('child_process');
const args = [...flags, ...process.execArgv, ...process.argv.slice(1)];
const options = { encoding: 'utf8', stdio: 'inherit' };
const options = {
encoding: 'utf8',
stdio: 'inherit',
env: {
...process.env,
...envs,
},
};
const result = spawnSync(process.execPath, args, options);
if (result.signal) {
process.kill(0, result.signal);
Expand Down Expand Up @@ -912,7 +943,7 @@ const common = {
mustSucceed,
nodeProcessAborted,
PIPE,
parseTestFlags,
parseTestMetadata,
platformTimeout,
printSkipMessage,
pwdCommand,
Expand Down
4 changes: 2 additions & 2 deletions test/common/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const {
mustNotMutateObjectDeep,
mustSucceed,
nodeProcessAborted,
parseTestFlags,
parseTestMetadata,
PIPE,
platformTimeout,
printSkipMessage,
Expand Down Expand Up @@ -86,7 +86,7 @@ export {
mustNotMutateObjectDeep,
mustSucceed,
nodeProcessAborted,
parseTestFlags,
parseTestMetadata,
PIPE,
platformTimeout,
printSkipMessage,
Expand Down
26 changes: 26 additions & 0 deletions test/parallel/test-parse-test-envs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';

// Env: A_SET_ENV_VAR=A_SET_ENV_VAR_VALUE B_SET_ENV_VAR=B_SET_ENV_VAR_VALUE
// Flags: --test-isolation=none --expose-internals

require('../common');
const assert = require('node:assert');
const { describe, it } = require('node:test');


// This test verifies that a test file that requires 'common' can set environment variables
// via comments in the test file, similar to how we set flags via comments.
// Ref: https://github.com/nodejs/node/issues/58179
describe('env var via comment', () => {
it('should set env var A_SET_ENV_VAR', () => {
assert.strictEqual(process.env.A_SET_ENV_VAR, 'A_SET_ENV_VAR_VALUE');
});
it('should set env var B_SET_ENV_VAR', () => {
assert.strictEqual(process.env.B_SET_ENV_VAR, 'B_SET_ENV_VAR_VALUE');
});

it('should interop with flags', () => {
const flag = require('internal/options').getOptionValue('--test-isolation');
assert.strictEqual(flag, 'none');
});
});
Loading