test: add parseTestMetadata support · nodejs/node@e517792
@@ -58,8 +58,16 @@ const hasSQLite = Boolean(process.versions.sqlite);
58585959const hasQuic = hasCrypto && !!process.config.variables.node_quic;
606061-function parseTestFlags(filename = process.argv[1]) {
62-// The copyright notice is relatively big and the flags could come afterwards.
61+/**
62+ * Parse test metadata from the specified file.
63+ * @param {string} filename - The name of the file to parse.
64+ * @returns {{
65+ * flags: string[],
66+ * envs: Record<string, string>
67+ * }} An object containing the parsed flags and environment variables.
68+ */
69+function parseTestMetadata(filename = process.argv[1]) {
70+// The copyright notice is relatively big and the metadata could come afterwards.
6371const bytesToRead = 1500;
6472const buffer = Buffer.allocUnsafe(bytesToRead);
6573const fd = fs.openSync(filename, 'r');
@@ -68,19 +76,33 @@ function parseTestFlags(filename = process.argv[1]) {
6876const source = buffer.toString('utf8', 0, bytesRead);
69777078const flagStart = source.search(/\/\/ Flags:\s+--/) + 10;
71-72-if (flagStart === 9) {
73-return [];
79+let flags = [];
80+if (flagStart !== 9) {
81+let flagEnd = source.indexOf('\n', flagStart);
82+if (source[flagEnd - 1] === '\r') {
83+flagEnd--;
84+}
85+flags = source
86+.substring(flagStart, flagEnd)
87+.split(/\s+/)
88+.filter(Boolean);
7489}
75-let flagEnd = source.indexOf('\n', flagStart);
76-// Normalize different EOL.
77-if (source[flagEnd - 1] === '\r') {
78-flagEnd--;
90+91+const envStart = source.search(/\/\/ Env:\s+/) + 8;
92+let envs = {};
93+if (envStart !== 7) {
94+let envEnd = source.indexOf('\n', envStart);
95+if (source[envEnd - 1] === '\r') {
96+envEnd--;
97+}
98+const envArray = source
99+.substring(envStart, envEnd)
100+.split(/\s+/)
101+.filter(Boolean);
102+envs = Object.fromEntries(envArray.map((env) => env.split('=')));
79103}
80-return source
81-.substring(flagStart, flagEnd)
82-.split(/\s+/)
83-.filter(Boolean);
104+105+return { flags, envs };
84106}
8510786108// Check for flags. Skip this for workers (both, the `cluster` module and
@@ -93,7 +115,7 @@ if (process.argv.length === 2 &&
93115hasCrypto &&
94116require('cluster').isPrimary &&
95117fs.existsSync(process.argv[1])) {
96-const flags = parseTestFlags();
118+const { flags, envs } = parseTestMetadata();
97119for (const flag of flags) {
98120if (!process.execArgv.includes(flag) &&
99121// If the binary is build without `intl` the inspect option is
@@ -102,11 +124,20 @@ if (process.argv.length === 2 &&
102124console.log(
103125'NOTE: The test started as a child_process using these flags:',
104126inspect(flags),
127+'And these environment variables:',
128+inspect(envs),
105129'Use NODE_SKIP_FLAG_CHECK to run the test with the original flags.',
106130);
107131const { spawnSync } = require('child_process');
108132const args = [...flags, ...process.execArgv, ...process.argv.slice(1)];
109-const options = { encoding: 'utf8', stdio: 'inherit' };
133+const options = {
134+encoding: 'utf8',
135+stdio: 'inherit',
136+env: {
137+ ...process.env,
138+ ...envs,
139+},
140+};
110141const result = spawnSync(process.execPath, args, options);
111142if (result.signal) {
112143process.kill(0, result.signal);
@@ -912,7 +943,7 @@ const common = {
912943 mustSucceed,
913944 nodeProcessAborted,
914945PIPE,
915-parseTestFlags,
946+parseTestMetadata,
916947 platformTimeout,
917948 printSkipMessage,
918949 pwdCommand,