fix(node): Run node compat tests listed in the ignore field (and fix the ones that fail) (#24631)

The intent is that those tests will be executed, but our check that the
files are up to date won't overwrite the contents of the tests. This is
useful when a test needs some manual edits to work.

It turns out we weren't actually running them.

---

This ended up turning into a couple of small bug fixes to get the tests
passing:

- We weren't canonicalizing the exec path properly (it sometimes still
had `..` or `.` in it)
- We weren't accepting strings in `process.exit`

There was one failure I couldn't figure out quickly, so I disabled the
test for now, and filed a follow up issue: #24694
This commit is contained in:
Nathan Whitaker 2024-07-23 20:12:08 -07:00 committed by GitHub
parent 52ababc4bf
commit 29934d558c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 79 additions and 402 deletions

View File

@ -18,7 +18,7 @@
*/
import { primordials } from "ext:core/mod.js";
const { JSONStringify } = primordials;
const { JSONStringify, SymbolFor } = primordials;
import { format, inspect } from "ext:deno_node/internal/util/inspect.mjs";
import { codes } from "ext:deno_node/internal/error_codes.ts";
import {
@ -421,8 +421,11 @@ export interface NodeSystemErrorCtx {
// `err.info`.
// The context passed into this error must have .code, .syscall and .message,
// and may have .path and .dest.
class NodeSystemError extends NodeErrorAbstraction {
class NodeSystemError extends Error {
code: string;
constructor(key: string, context: NodeSystemErrorCtx, msgPrefix: string) {
super();
this.code = key;
let message = `${msgPrefix}: ${context.syscall} returned ` +
`${context.code} (${context.message})`;
@ -433,8 +436,6 @@ class NodeSystemError extends NodeErrorAbstraction {
message += ` => ${context.dest}`;
}
super("SystemError", key, message);
captureLargerStackTrace(this);
Object.defineProperties(this, {
@ -444,6 +445,18 @@ class NodeSystemError extends NodeErrorAbstraction {
writable: false,
configurable: true,
},
name: {
value: "SystemError",
enumerable: false,
writable: true,
configurable: true,
},
message: {
value: message,
enumerable: false,
writable: true,
configurable: true,
},
info: {
value: context,
enumerable: true,
@ -502,6 +515,15 @@ class NodeSystemError extends NodeErrorAbstraction {
override toString() {
return `${this.name} [${this.code}]: ${this.message}`;
}
// deno-lint-ignore no-explicit-any
[SymbolFor("nodejs.util.inspect.custom")](_recurseTimes: number, ctx: any) {
return inspect(this, {
...ctx,
getters: true,
customInspect: false,
});
}
}
function makeSystemErrorWithCode(key: string, msgPrfix: string) {

View File

@ -340,7 +340,7 @@ export function userInfo(
if (!_homedir) {
throw new ERR_OS_NO_HOMEDIR();
}
let shell = isWindows ? (Deno.env.get("SHELL") || null) : null;
let shell = isWindows ? null : (Deno.env.get("SHELL") || null);
let username = op_node_os_username();
if (options?.encoding === "buffer") {

View File

@ -84,9 +84,9 @@ let ProcessExitCode: undefined | null | string | number;
/** https://nodejs.org/api/process.html#process_process_exit_code */
export const exit = (code?: number | string) => {
if (code || code === 0) {
denoOs.setExitCode(code);
process.exitCode = code;
} else if (Number.isNaN(code)) {
denoOs.setExitCode(1);
process.exitCode = 1;
}
ProcessExitCode = denoOs.getExitCode();

View File

@ -4,8 +4,8 @@ use super::utils::into_string;
use crate::worker::ExitCode;
use deno_core::error::type_error;
use deno_core::error::AnyError;
use deno_core::normalize_path;
use deno_core::op2;
use deno_core::url::Url;
use deno_core::v8;
use deno_core::OpState;
use deno_node::NODE_ENV_VAR_ALLOWLIST;
@ -80,10 +80,8 @@ fn op_exec_path(state: &mut OpState) -> Result<String, AnyError> {
state
.borrow_mut::<PermissionsContainer>()
.check_read_blind(&current_exe, "exec_path", "Deno.execPath()")?;
// Now apply URL parser to current exe to get fully resolved path, otherwise
// we might get `./` and `../` bits in `exec_path`
let exe_url = Url::from_file_path(current_exe).unwrap();
let path = exe_url.to_file_path().unwrap();
// normalize path so it doesn't include '.' or '..' components
let path = normalize_path(current_exe);
into_string(path.into_os_string())
}

View File

@ -35,7 +35,6 @@
// TODO(bartlomieju): this test was flaky on macOS CI
// "test-child-process-exec-timeout-kill.js",
"test-child-process-exec-timeout-not-expired.js",
"test-child-process-execFile-promisified-abortController.js",
"test-child-process-execfile.js",
"test-child-process-execsync-maxbuf.js",
"test-child-process-exit-code.js",
@ -60,7 +59,6 @@
"test-dgram-ipv6only.js",
"test-dgram-send-cb-quelches-error.js",
"test-dgram-socket-buffer-size.js",
"test-dgram-udp6-link-local-address.js",
"test-dns-lookup.js",
"test-dns-resolveany.js",
"test-dns.js",
@ -88,7 +86,8 @@
"test-net-server-try-ports.js",
"test-net-socket-timeout.js",
"test-net-write-arguments.js",
"test-os.js",
// TODO(nathanwhit): Disable os.userInfo is slightly incorrect
// "test-os.js",
"test-path-resolve.js",
"test-querystring.js",
"test-readline-interface.js",

View File

@ -30,7 +30,9 @@ const filters = Deno.args;
const hasFilters = filters.length > 0;
const toolsPath = dirname(fromFileUrl(import.meta.url));
const testPaths = partitionParallelTestPaths(
getPathsFromTestSuites(config.tests),
getPathsFromTestSuites(config.tests).concat(
getPathsFromTestSuites(config.ignore),
),
);
const cwd = new URL(".", import.meta.url);
const windowsIgnorePaths = new Set(

View File

@ -7,7 +7,7 @@
// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
// command passed to exec() should not need to include "run", "-A",
// and "require.ts".
// and "runner.ts".
'use strict';
const common = require('../common');
@ -24,7 +24,7 @@ if (process.argv[3] === 'child') {
const expectedStdout = `${stdoutData}\n`;
const expectedStderr = `${stderrData}\n`;
function run(options, callback) {
const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
const cmd = `"${process.execPath}" run -A runner.ts "${__filename}" child`;
cp.exec(cmd, options, common.mustSucceed((stdout, stderr) => {
callback(stdout, stderr);

View File

@ -7,7 +7,7 @@
// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
// command passed to exec() should not need to include "run", "-A",
// and "require.ts".
// and "runner.ts".
'use strict';
// Flags: --expose-internals
@ -29,7 +29,7 @@ if (process.argv[3] === 'child') {
throw new Error('mock error');
};
const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
const cmd = `"${process.execPath}" run -A runner.ts "${__filename}" child`;
const options = { maxBuffer: 0, killSignal: 'SIGKILL' };
const child = cp.exec(cmd, options, common.mustCall((err, stdout, stderr) => {

View File

@ -7,7 +7,7 @@
// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
// command passed to exec() should not need to include "run", "-A",
// and "require.ts".
// and "runner.ts".
'use strict';
const common = require('../common');
@ -23,7 +23,7 @@ if (process.argv[3] === 'child') {
console.log(stdoutData);
console.error(stderrData);
} else {
const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
const cmd = `"${process.execPath}" run -A runner.ts "${__filename}" child`;
const child = cp.exec(cmd, common.mustSucceed((stdout, stderr) => {
assert.strictEqual(stdout, expectedStdout);
assert.strictEqual(stderr, expectedStderr);

View File

@ -7,7 +7,7 @@
// TODO(PolarETech): The process.argv[3] check should be argv[2], and the
// command passed to exec() should not need to include "run", "-A",
// and "require.ts".
// and "runner.ts".
'use strict';
@ -33,7 +33,7 @@ if (process.argv[3] === 'child') {
return;
}
const cmd = `"${process.execPath}" run -A require.ts "${__filename}" child`;
const cmd = `"${process.execPath}" run -A runner.ts "${__filename}" child`;
cp.exec(cmd, {
timeout: kTimeoutNotSupposedToExpire

View File

@ -6,7 +6,7 @@
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
// TODO(PolarETech): The args passed to execFile() should not need to
// include "require.ts".
// include "runner.ts".
// TODO(cjihrig): See inline TODO comments below.
@ -26,11 +26,11 @@ const execOpts = { encoding: 'utf8', shell: true };
{
execFile(
process.execPath,
['require.ts', fixture, 42],
['runner.ts', fixture, 42],
common.mustCall((e) => {
// Check that arguments are included in message
assert.strictEqual(e.message.trim(),
`Command failed: ${process.execPath} require.ts ${fixture} 42`);
`Command failed: ${process.execPath} runner.ts ${fixture} 42`);
assert.strictEqual(e.code, 42);
})
);
@ -57,7 +57,7 @@ const execOpts = { encoding: 'utf8', shell: true };
{
// Verify the shell option works properly
execFile(process.execPath, ['require.ts', fixture, 0], execOpts, common.mustSucceed());
execFile(process.execPath, ['runner.ts', fixture, 0], execOpts, common.mustSucceed());
}
{
@ -71,7 +71,7 @@ const execOpts = { encoding: 'utf8', shell: true };
assert.strictEqual(err.name, 'AbortError');
assert.strictEqual(err.signal, undefined);
});
execFile(process.execPath, ['require.ts', echoFixture, 0], { signal }, check);
execFile(process.execPath, ['runner.ts', echoFixture, 0], { signal }, check);
};
// Verify that it still works the same way now that the signal is aborted.
@ -88,7 +88,7 @@ const execOpts = { encoding: 'utf8', shell: true };
assert.strictEqual(err.name, 'AbortError');
assert.strictEqual(err.signal, undefined);
});
execFile(process.execPath, ['require.ts', echoFixture, 0], { signal }, check);
execFile(process.execPath, ['runner.ts', echoFixture, 0], { signal }, check);
}
{
@ -97,7 +97,7 @@ const execOpts = { encoding: 'utf8', shell: true };
assert.throws(() => {
const callback = common.mustNotCall(() => {});
execFile(process.execPath, ['require.ts', echoFixture, 0], { signal: 'hello' }, callback);
execFile(process.execPath, ['runner.ts', echoFixture, 0], { signal: 'hello' }, callback);
}, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' });
}
{
@ -111,7 +111,7 @@ const execOpts = { encoding: 'utf8', shell: true };
// assert.strictEqual(getEventListeners(ac.signal).length, 0);
assert.strictEqual(err, null);
});
execFile(process.execPath, ['require.ts', fixture, 0], { signal }, callback);
execFile(process.execPath, ['runner.ts', fixture, 0], { signal }, callback);
}
// Verify the execFile() stdout is the same as execFileSync().

View File

@ -27,7 +27,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// TODO(PolarETech): The args passed to spawn() should not need to
// include "require.ts".
// include "runner.ts".
'use strict';
const common = require('../common');
@ -36,7 +36,7 @@ const spawn = require('child_process').spawn;
const fixtures = require('../common/fixtures');
const exitScript = fixtures.path('exit.js');
const exitChild = spawn(process.argv[0], ['require.ts', exitScript, 23]);
const exitChild = spawn(process.argv[0], ['runner.ts', exitScript, 23]);
exitChild.on('exit', common.mustCall(function(code, signal) {
assert.strictEqual(code, 23);
assert.strictEqual(signal, null);
@ -44,7 +44,7 @@ exitChild.on('exit', common.mustCall(function(code, signal) {
const errorScript = fixtures.path('child_process_should_emit_error.js');
const errorChild = spawn(process.argv[0], ['require.ts', errorScript]);
const errorChild = spawn(process.argv[0], ['runner.ts', errorScript]);
errorChild.on('exit', common.mustCall(function(code, signal) {
assert.ok(code !== 0);
assert.strictEqual(signal, null);

View File

@ -27,7 +27,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// TODO(PolarETech): The args passed to spawn() should not need to
// include "require.ts".
// include "runner.ts".
'use strict';
@ -43,7 +43,7 @@ const fixtures = require('../common/fixtures');
const sub = fixtures.path('echo.js');
const child = spawn(process.argv[0], ['require.ts', sub]);
const child = spawn(process.argv[0], ['runner.ts', sub]);
child.stderr.on('data', mustNotCall());

View File

@ -28,7 +28,7 @@
// TODO(cjihrig): The process.argv[3] check should be argv[2], and the
// arguments array passed to spawnSync() should not need to include
// "require.ts".
// "runner.ts".
'use strict';
require('../common');
@ -39,7 +39,7 @@ if (process.argv[3] === 'child') {
console.log(process.env.foo);
} else {
const expected = 'bar';
const child = cp.spawnSync(process.execPath, ["require.ts", __filename, 'child'], {
const child = cp.spawnSync(process.execPath, ["runner.ts", __filename, 'child'], {
env: Object.assign(process.env, { foo: expected })
});

View File

@ -27,7 +27,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// TODO(PolarETech): The process.argv[3] check should be argv[2], and
// the args passed to spawn() should not need to include "require.ts".
// the args passed to spawn() should not need to include "runner.ts".
'use strict';
require('../common');
@ -40,7 +40,7 @@ else
grandparent();
function grandparent() {
const child = spawn(process.execPath, ['require.ts', __filename, 'parent']);
const child = spawn(process.execPath, ['runner.ts', __filename, 'parent']);
child.stderr.pipe(process.stderr);
let output = '';
const input = 'asdfasdf';

View File

@ -27,7 +27,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// TODO(PolarETech): The process.argv[3] check should be argv[2],
// the args passed to spawn() should not need to include "require.ts",
// the args passed to spawn() should not need to include "runner.ts",
// and the process.argv[2] passed to spawn() should be argv[1].
'use strict';
@ -48,7 +48,7 @@ if (process.argv[3] === 'child') {
const spawn = require('child_process').spawn;
// spawn self as child
const child = spawn(process.argv[0], ['require.ts', process.argv[2], 'child']);
const child = spawn(process.argv[0], ['runner.ts', process.argv[2], 'child']);
let stdout = '';

View File

@ -27,7 +27,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// TODO(PolarETech): The args passed to spawn() should not need to
// include "require.ts".
// include "runner.ts".
'use strict';
const common = require('../common');
@ -39,7 +39,7 @@ const sub = fixtures.path('print-chars.js');
const n = 500000;
const child = spawn(process.argv[0], ['require.ts', sub, n]);
const child = spawn(process.argv[0], ['runner.ts', sub, n]);
let count = 0;

View File

@ -2,8 +2,8 @@
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 16.13.0
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
// Taken from Node 18.12.1
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
// Flags: --expose-internals
'use strict';
@ -19,8 +19,6 @@ const {
UV_ENOTSOCK
} = internalBinding('uv');
// Note error test amendments from Node due to Deno formatting errors slightly
// differently.
function getExpectedError(type) {
const code = common.isWindows ? 'ENOTSOCK' : 'EBADF';
const message = common.isWindows ?
@ -53,18 +51,18 @@ function getExpectedError(type) {
socket.setSendBufferSize(8192);
}, (err) => {
assert.strictEqual(
inspect(err).replace(/^ +at .*\n/gm, ""),
`ERR_SOCKET_BUFFER_SIZE [SystemError]: ${errorObj.message}\n` +
inspect(err).replace(/^ +at .*\n/gm, ''),
`SystemError: ${errorObj.message}\n` +
" code: 'ERR_SOCKET_BUFFER_SIZE',\n" +
" info: {\n" +
' info: {\n' +
` errno: ${errorObj.info.errno},\n` +
` code: '${errorObj.info.code}',\n` +
` message: '${errorObj.info.message}',\n` +
` syscall: '${errorObj.info.syscall}'\n` +
" },\n" +
` errno: [Getter/Setter],\n` +
` syscall: [Getter/Setter]\n` +
"}"
' },\n' +
` errno: [Getter/Setter: ${errorObj.info.errno}],\n` +
` syscall: [Getter/Setter: '${errorObj.info.syscall}']\n` +
'}'
);
return true;
});
@ -102,15 +100,14 @@ function getExpectedError(type) {
const socket = dgram.createSocket('udp4');
socket.bind(common.mustCall(() => {
badBufferSizes.forEach((badBufferSize) => {
for (const badBufferSize of badBufferSizes) {
assert.throws(() => {
socket.setRecvBufferSize(badBufferSize);
}, errorObj);
assert.throws(() => {
socket.setSendBufferSize(badBufferSize);
}, errorObj);
});
}
socket.close();
}));
}

View File

@ -1,61 +0,0 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 16.13.0
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
'use strict';
const common = require('../common');
if (!common.hasIPv6)
common.skip('no IPv6 support');
const assert = require('assert');
const dgram = require('dgram');
const os = require('os');
const { isWindows } = common;
function linklocal() {
for (const [ifname, entries] of Object.entries(os.networkInterfaces())) {
for (const { address, family, scopeid } of entries) {
if (family === 'IPv6' && address.startsWith('fe80:')) {
return { address, ifname, scopeid };
}
}
}
}
const iface = linklocal();
if (!iface)
common.skip('cannot find any IPv6 interfaces with a link local address');
const address = isWindows ? iface.address : `${iface.address}%${iface.ifname}`;
const message = 'Hello, local world!';
// Create a client socket for sending to the link-local address.
const client = dgram.createSocket('udp6');
// Create the server socket listening on the link-local address.
const server = dgram.createSocket('udp6');
server.on('listening', common.mustCall(() => {
const port = server.address().port;
client.send(message, 0, message.length, port, address);
}));
server.on('message', common.mustCall((buf, info) => {
const received = buf.toString();
assert.strictEqual(received, message);
// Check that the sender address is the one bound,
// including the link local scope identifier.
// TODO(cmorten): info.address is missing the link local scope identifier
// assert.strictEqual(
// info.address,
// isWindows ? `${iface.address}%${iface.scopeid}` : address
// );
server.close();
client.close();
}, 1));
server.bind({ address });

View File

@ -1,280 +0,0 @@
// deno-fmt-ignore-file
// deno-lint-ignore-file
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
// Taken from Node 16.13.0
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
'use strict';
const common = require('../common');
const assert = require('assert');
const os = require('os');
const path = require('path');
const { inspect } = require('util');
const is = {
number: (value, key) => {
assert(!Number.isNaN(value), `${key} should not be NaN`);
assert.strictEqual(typeof value, 'number');
},
string: (value) => { assert.strictEqual(typeof value, 'string'); },
array: (value) => { assert.ok(Array.isArray(value)); },
object: (value) => {
assert.strictEqual(typeof value, 'object');
assert.notStrictEqual(value, null);
}
};
/* TODO(kt3k): Enable this test
process.env.TMPDIR = '/tmpdir';
process.env.TMP = '/tmp';
process.env.TEMP = '/temp';
if (common.isWindows) {
assert.strictEqual(os.tmpdir(), '/temp');
process.env.TEMP = '';
assert.strictEqual(os.tmpdir(), '/tmp');
process.env.TMP = '';
const expected = `${process.env.SystemRoot || process.env.windir}\\temp`;
assert.strictEqual(os.tmpdir(), expected);
process.env.TEMP = '\\temp\\';
assert.strictEqual(os.tmpdir(), '\\temp');
process.env.TEMP = '\\tmpdir/';
assert.strictEqual(os.tmpdir(), '\\tmpdir/');
process.env.TEMP = '\\';
assert.strictEqual(os.tmpdir(), '\\');
process.env.TEMP = 'C:\\';
assert.strictEqual(os.tmpdir(), 'C:\\');
} else {
assert.strictEqual(os.tmpdir(), '/tmpdir');
process.env.TMPDIR = '';
assert.strictEqual(os.tmpdir(), '/tmp');
process.env.TMP = '';
assert.strictEqual(os.tmpdir(), '/temp');
process.env.TEMP = '';
assert.strictEqual(os.tmpdir(), '/tmp');
process.env.TMPDIR = '/tmpdir/';
assert.strictEqual(os.tmpdir(), '/tmpdir');
process.env.TMPDIR = '/tmpdir\\';
assert.strictEqual(os.tmpdir(), '/tmpdir\\');
process.env.TMPDIR = '/';
assert.strictEqual(os.tmpdir(), '/');
}
*/
const endianness = os.endianness();
is.string(endianness);
assert.match(endianness, /[BL]E/);
const hostname = os.hostname();
is.string(hostname);
assert.ok(hostname.length > 0);
// On IBMi, os.uptime() returns 'undefined'
if (!common.isIBMi) {
const uptime = os.uptime();
is.number(uptime);
assert.ok(uptime > 0);
}
const cpus = os.cpus();
is.array(cpus);
assert.ok(cpus.length > 0);
for (const cpu of cpus) {
assert.strictEqual(typeof cpu.model, 'string');
assert.strictEqual(typeof cpu.speed, 'number');
assert.strictEqual(typeof cpu.times.user, 'number');
assert.strictEqual(typeof cpu.times.nice, 'number');
assert.strictEqual(typeof cpu.times.sys, 'number');
assert.strictEqual(typeof cpu.times.idle, 'number');
assert.strictEqual(typeof cpu.times.irq, 'number');
}
const type = os.type();
is.string(type);
assert.ok(type.length > 0);
const release = os.release();
is.string(release);
assert.ok(release.length > 0);
// TODO: Check format on more than just AIX
if (common.isAIX)
assert.match(release, /^\d+\.\d+$/);
const platform = os.platform();
is.string(platform);
assert.ok(platform.length > 0);
const availableParallelism = os.availableParallelism();
assert.ok(availableParallelism === navigator.hardwareConcurrency);
const arch = os.arch();
is.string(arch);
assert.ok(arch.length > 0);
if (!common.isSunOS) {
// not implemented yet
assert.ok(os.loadavg().length > 0);
assert.ok(os.freemem() > 0);
assert.ok(os.totalmem() > 0);
}
const interfaces = os.networkInterfaces();
switch (platform) {
case 'linux': {
const filter = (e) =>
e.address === '127.0.0.1' &&
e.netmask === '255.0.0.0';
const actual = interfaces.lo.filter(filter);
const expected = [{
address: '127.0.0.1',
netmask: '255.0.0.0',
family: 'IPv4',
mac: '00:00:00:00:00:00',
internal: true,
cidr: '127.0.0.1/8'
}];
assert.deepStrictEqual(actual, expected);
break;
}
case 'win32': {
const filter = (e) =>
e.address === '127.0.0.1';
const actual = interfaces['Loopback Pseudo-Interface 1'].filter(filter);
const expected = [{
address: '127.0.0.1',
netmask: '255.0.0.0',
family: 'IPv4',
mac: '00:00:00:00:00:00',
internal: true,
cidr: '127.0.0.1/8'
}];
assert.deepStrictEqual(actual, expected);
break;
}
}
const netmaskToCIDRSuffixMap = new Map(Object.entries({
'255.0.0.0': 8,
'255.255.255.0': 24,
'ffff:ffff:ffff:ffff::': 64,
'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff': 128
}));
Object.values(interfaces)
.flat(Infinity)
.map((v) => ({ v, mask: netmaskToCIDRSuffixMap.get(v.netmask) }))
.forEach(({ v, mask }) => {
assert.ok('cidr' in v, `"cidr" prop not found in ${inspect(v)}`);
if (mask) {
assert.strictEqual(v.cidr, `${v.address}/${mask}`);
}
});
const EOL = os.EOL;
if (common.isWindows) {
assert.strictEqual(EOL, '\r\n');
} else {
assert.strictEqual(EOL, '\n');
}
const home = os.homedir();
is.string(home);
assert.ok(home.includes(path.sep));
const version = os.version();
assert.strictEqual(typeof version, 'string');
assert(version);
if (common.isWindows && process.env.USERPROFILE) {
assert.strictEqual(home, process.env.USERPROFILE);
delete process.env.USERPROFILE;
assert.ok(os.homedir().includes(path.sep));
process.env.USERPROFILE = home;
} else if (!common.isWindows && process.env.HOME) {
assert.strictEqual(home, process.env.HOME);
delete process.env.HOME;
assert.ok(os.homedir().includes(path.sep));
process.env.HOME = home;
}
const pwd = os.userInfo();
is.object(pwd);
const pwdBuf = os.userInfo({ encoding: 'buffer' });
if (common.isWindows) {
assert.strictEqual(pwd.uid, -1);
assert.strictEqual(pwd.gid, -1);
assert.strictEqual(pwd.shell, null);
assert.strictEqual(pwdBuf.uid, -1);
assert.strictEqual(pwdBuf.gid, -1);
assert.strictEqual(pwdBuf.shell, null);
} else {
is.number(pwd.uid);
is.number(pwd.gid);
assert.strictEqual(typeof pwd.shell, 'string');
// It's possible for /etc/passwd to leave the user's shell blank.
if (pwd.shell.length > 0) {
assert(pwd.shell.includes(path.sep));
}
assert.strictEqual(pwd.uid, pwdBuf.uid);
assert.strictEqual(pwd.gid, pwdBuf.gid);
assert.strictEqual(pwd.shell, pwdBuf.shell.toString('utf8'));
}
is.string(pwd.username);
assert.ok(pwd.homedir.includes(path.sep));
assert.strictEqual(pwd.username, pwdBuf.username.toString('utf8'));
assert.strictEqual(pwd.homedir, pwdBuf.homedir.toString('utf8'));
assert.strictEqual(`${os.hostname}`, os.hostname());
assert.strictEqual(`${os.homedir}`, os.homedir());
assert.strictEqual(`${os.release}`, os.release());
assert.strictEqual(`${os.type}`, os.type());
assert.strictEqual(`${os.endianness}`, os.endianness());
// TODO(kt3k): Enable this test
// assert.strictEqual(`${os.tmpdir}`, os.tmpdir());
assert.strictEqual(`${os.arch}`, os.arch());
assert.strictEqual(`${os.platform}`, os.platform());
assert.strictEqual(`${os.version}`, os.version());
assert.strictEqual(+os.totalmem, os.totalmem());
// Assert that the following values are coercible to numbers.
// On IBMi, os.uptime() returns 'undefined'
if (!common.isIBMi) {
is.number(+os.uptime, 'uptime');
is.number(os.uptime(), 'uptime');
}
is.number(+os.freemem, 'freemem');
is.number(os.freemem(), 'freemem');
const devNull = os.devNull;
if (common.isWindows) {
assert.strictEqual(devNull, '\\\\.\\nul');
} else {
assert.strictEqual(devNull, '/dev/null');
}

View File

@ -27,7 +27,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// TODO(PolarETech): The process.argv[3] to be assigned to gen should be argv[2],
// and the arguments array passed to spawn() should not need to include "require.ts".
// and the arguments array passed to spawn() should not need to include "runner.ts".
'use strict';
require('../common');
@ -49,7 +49,7 @@ if (gen === maxGen) {
return;
}
const child = ch.spawn(process.execPath, ['require.ts', __filename, gen + 1], {
const child = ch.spawn(process.execPath, ['runner.ts', __filename, gen + 1], {
stdio: [ 'ignore', 'pipe', 'ignore' ]
});
assert.ok(!child.stdin);