mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
node: update test/common (#17786)
This commit is contained in:
@@ -25,7 +25,7 @@ function replaceWindowsPaths(str) {
|
||||
}
|
||||
|
||||
function replaceFullPaths(str) {
|
||||
return str.replaceAll(path.resolve(__dirname, '../..'), '');
|
||||
return str.replaceAll('\\\'', "'").replaceAll(path.resolve(__dirname, '../..'), '');
|
||||
}
|
||||
|
||||
function transform(...args) {
|
||||
@@ -77,7 +77,11 @@ async function spawnAndAssert(filename, transform = (x) => x, { tty = false, ...
|
||||
test({ skip: 'Skipping pseudo-tty tests, as pseudo terminals are not available on Windows.' });
|
||||
return;
|
||||
}
|
||||
const flags = common.parseTestFlags(filename);
|
||||
let flags = common.parseTestFlags(filename);
|
||||
if (options.flags) {
|
||||
flags = [...options.flags, ...flags];
|
||||
}
|
||||
|
||||
const executable = tty ? (process.env.PYTHON || 'python3') : process.execPath;
|
||||
const args =
|
||||
tty ?
|
||||
|
||||
@@ -27,16 +27,27 @@ function runBenchmark(name, env) {
|
||||
child.on('exit', (code, signal) => {
|
||||
assert.strictEqual(code, 0);
|
||||
assert.strictEqual(signal, null);
|
||||
|
||||
// This bit makes sure that each benchmark file is being sent settings such
|
||||
// that the benchmark file runs just one set of options. This helps keep the
|
||||
// benchmark tests from taking a long time to run. Therefore, each benchmark
|
||||
// file should result in three lines of output: a blank line, a line with
|
||||
// the name of the benchmark file, and a line with the only results that we
|
||||
// get from testing the benchmark file.
|
||||
assert.ok(
|
||||
/^(?:\n.+?\n.+?\n)+$/.test(stdout),
|
||||
`benchmark file not running exactly one configuration in test: ${stdout}`,
|
||||
);
|
||||
// benchmark tests from taking a long time to run. Therefore, stdout should be composed as follows:
|
||||
// The first and last lines should be empty.
|
||||
// Each test should be separated by a blank line.
|
||||
// The first line of each test should contain the test's name.
|
||||
// The second line of each test should contain the configuration for the test.
|
||||
// If the test configuration is not a group, there should be exactly two lines.
|
||||
// Otherwise, it is possible to have more than two lines.
|
||||
|
||||
const splitTests = stdout.split(/\n\s*\n/);
|
||||
|
||||
for (let testIdx = 1; testIdx < splitTests.length - 1; testIdx++) {
|
||||
const lines = splitTests[testIdx].split('\n');
|
||||
assert.ok(/.+/.test(lines[0]));
|
||||
|
||||
if (!lines[1].includes('group="')) {
|
||||
assert.strictEqual(lines.length, 2, `benchmark file not running exactly one configuration in test: ${stdout}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -60,13 +60,14 @@ function checkOutput(str, check) {
|
||||
return { passed: true };
|
||||
}
|
||||
|
||||
function expectSyncExit(child, {
|
||||
function expectSyncExit(caller, spawnArgs, {
|
||||
status,
|
||||
signal,
|
||||
stderr: stderrCheck,
|
||||
stdout: stdoutCheck,
|
||||
trim = false,
|
||||
}) {
|
||||
const child = spawnSync(...spawnArgs);
|
||||
const failures = [];
|
||||
let stderrStr, stdoutStr;
|
||||
if (status !== undefined && child.status !== status) {
|
||||
@@ -83,7 +84,18 @@ function expectSyncExit(child, {
|
||||
console.error(`${tag} --- stdout ---`);
|
||||
console.error(stdoutStr === undefined ? child.stdout.toString() : stdoutStr);
|
||||
console.error(`${tag} status = ${child.status}, signal = ${child.signal}`);
|
||||
throw new Error(`${failures.join('\n')}`);
|
||||
|
||||
const error = new Error(`${failures.join('\n')}`);
|
||||
if (spawnArgs[2]) {
|
||||
error.options = spawnArgs[2];
|
||||
}
|
||||
let command = spawnArgs[0];
|
||||
if (Array.isArray(spawnArgs[1])) {
|
||||
command += ' ' + spawnArgs[1].join(' ');
|
||||
}
|
||||
error.command = command;
|
||||
Error.captureStackTrace(error, caller);
|
||||
throw error;
|
||||
}
|
||||
|
||||
// If status and signal are not matching expectations, fail early.
|
||||
@@ -114,12 +126,11 @@ function expectSyncExit(child, {
|
||||
function spawnSyncAndExit(...args) {
|
||||
const spawnArgs = args.slice(0, args.length - 1);
|
||||
const expectations = args[args.length - 1];
|
||||
const child = spawnSync(...spawnArgs);
|
||||
return expectSyncExit(child, expectations);
|
||||
return expectSyncExit(spawnSyncAndExit, spawnArgs, expectations);
|
||||
}
|
||||
|
||||
function spawnSyncAndExitWithoutError(...args) {
|
||||
return expectSyncExit(spawnSync(...args), {
|
||||
return expectSyncExit(spawnSyncAndExitWithoutError, [...args], {
|
||||
status: 0,
|
||||
signal: null,
|
||||
});
|
||||
@@ -127,8 +138,7 @@ function spawnSyncAndExitWithoutError(...args) {
|
||||
|
||||
function spawnSyncAndAssert(...args) {
|
||||
const expectations = args.pop();
|
||||
const child = spawnSync(...args);
|
||||
return expectSyncExit(child, {
|
||||
return expectSyncExit(spawnSyncAndAssert, [...args], {
|
||||
status: 0,
|
||||
signal: null,
|
||||
...expectations,
|
||||
|
||||
@@ -34,23 +34,6 @@ const modp2buf = Buffer.from([
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
]);
|
||||
|
||||
function testDH({ publicKey: alicePublicKey, privateKey: alicePrivateKey },
|
||||
{ publicKey: bobPublicKey, privateKey: bobPrivateKey },
|
||||
expectedValue) {
|
||||
const buf1 = crypto.diffieHellman({
|
||||
privateKey: alicePrivateKey,
|
||||
publicKey: bobPublicKey,
|
||||
});
|
||||
const buf2 = crypto.diffieHellman({
|
||||
privateKey: bobPrivateKey,
|
||||
publicKey: alicePublicKey,
|
||||
});
|
||||
assert.deepStrictEqual(buf1, buf2);
|
||||
|
||||
if (expectedValue !== undefined)
|
||||
assert.deepStrictEqual(buf1, expectedValue);
|
||||
}
|
||||
|
||||
// Asserts that the size of the given key (in chars or bytes) is within 10% of
|
||||
// the expected size.
|
||||
function assertApproximateSize(key, expectedSize) {
|
||||
@@ -139,7 +122,6 @@ let opensslCli = null;
|
||||
|
||||
module.exports = {
|
||||
modp2buf,
|
||||
testDH,
|
||||
assertApproximateSize,
|
||||
testEncryptDecrypt,
|
||||
testSignVerify,
|
||||
|
||||
@@ -15,7 +15,6 @@ const types = {
|
||||
TXT: 16,
|
||||
ANY: 255,
|
||||
CAA: 257,
|
||||
SRV: 33,
|
||||
};
|
||||
|
||||
const classes = {
|
||||
@@ -197,11 +196,11 @@ function writeDNSPacket(parsed) {
|
||||
|
||||
buffers.push(new Uint16Array([
|
||||
parsed.id,
|
||||
parsed.flags === undefined ? kStandardResponseFlags : parsed.flags,
|
||||
parsed.questions && parsed.questions.length,
|
||||
parsed.answers && parsed.answers.length,
|
||||
parsed.authorityAnswers && parsed.authorityAnswers.length,
|
||||
parsed.additionalRecords && parsed.additionalRecords.length,
|
||||
parsed.flags ?? kStandardResponseFlags,
|
||||
parsed.questions?.length,
|
||||
parsed.answers?.length,
|
||||
parsed.authorityAnswers?.length,
|
||||
parsed.additionalRecords?.length,
|
||||
]));
|
||||
|
||||
for (const q of parsed.questions) {
|
||||
|
||||
@@ -126,7 +126,7 @@ var finalizationRegistry = new FinalizationRegistry(heldValue => {
|
||||
|
||||
function onGC(value, holder) {
|
||||
if (holder?.ongc) {
|
||||
|
||||
|
||||
finalizationRegistry.register(value, { ongc: holder.ongc });
|
||||
}
|
||||
}
|
||||
@@ -137,5 +137,3 @@ module.exports = {
|
||||
checkIfCollectableByCounting,
|
||||
onGC,
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -81,24 +81,6 @@ class SettingsFrame extends Frame {
|
||||
}
|
||||
}
|
||||
|
||||
class DataFrame extends Frame {
|
||||
constructor(id, payload, padlen = 0, final = false) {
|
||||
let len = payload.length;
|
||||
let flags = 0;
|
||||
if (final) flags |= FLAG_EOS;
|
||||
const buffers = [payload];
|
||||
if (padlen > 0) {
|
||||
buffers.unshift(Buffer.from([padlen]));
|
||||
buffers.push(PADDING.slice(0, padlen));
|
||||
len += padlen + 1;
|
||||
flags |= FLAG_PADDED;
|
||||
}
|
||||
super(len, 0, flags, id);
|
||||
buffers.unshift(this[kFrameData]);
|
||||
this[kFrameData] = Buffer.concat(buffers);
|
||||
}
|
||||
}
|
||||
|
||||
class HeadersFrame extends Frame {
|
||||
constructor(id, payload, padlen = 0, final = false) {
|
||||
let len = payload.length;
|
||||
@@ -138,7 +120,6 @@ class AltSvcFrame extends Frame {
|
||||
module.exports = {
|
||||
Frame,
|
||||
AltSvcFrame,
|
||||
DataFrame,
|
||||
HeadersFrame,
|
||||
SettingsFrame,
|
||||
PingFrame,
|
||||
|
||||
@@ -110,7 +110,7 @@ function parseTestFlags(filename = process.argv[1]) {
|
||||
// `worker_threads`) and child processes.
|
||||
// If the binary was built without-ssl then the crypto flags are
|
||||
// invalid (bad option). The test itself should handle this case.
|
||||
if ((process.argv.length === 2 || process.argv.length === 3) &&
|
||||
if (process.argv.length === 2 &&
|
||||
!process.env.NODE_SKIP_FLAG_CHECK &&
|
||||
isMainThread &&
|
||||
hasCrypto &&
|
||||
@@ -259,15 +259,13 @@ const PIPE = (() => {
|
||||
// `$node --abort-on-uncaught-exception $file child`
|
||||
// the process aborts.
|
||||
function childShouldThrowAndAbort() {
|
||||
let testCmd = '';
|
||||
const escapedArgs = escapePOSIXShell`"${process.argv[0]}" --abort-on-uncaught-exception "${process.argv[1]}" child`;
|
||||
if (!isWindows) {
|
||||
// Do not create core files, as it can take a lot of disk space on
|
||||
// continuous testing and developers' machines
|
||||
testCmd += 'ulimit -c 0 && ';
|
||||
escapedArgs[0] = 'ulimit -c 0 && ' + escapedArgs[0];
|
||||
}
|
||||
testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception `;
|
||||
testCmd += `"${process.argv[1]}" child`;
|
||||
const child = exec(testCmd);
|
||||
const child = exec(...escapedArgs);
|
||||
child.on('exit', function onExit(exitCode, signal) {
|
||||
const errMsg = 'Test should have aborted ' +
|
||||
`but instead exited with exit code ${exitCode}` +
|
||||
@@ -400,57 +398,6 @@ if (global.Storage) {
|
||||
);
|
||||
}
|
||||
|
||||
if (global.Bun) {
|
||||
knownGlobals.push(
|
||||
global.addEventListener,
|
||||
global.alert,
|
||||
global.confirm,
|
||||
global.dispatchEvent,
|
||||
global.postMessage,
|
||||
global.prompt,
|
||||
global.removeEventListener,
|
||||
global.reportError,
|
||||
global.Bun,
|
||||
global.File,
|
||||
global.process,
|
||||
global.Blob,
|
||||
global.Buffer,
|
||||
global.BuildError,
|
||||
global.BuildMessage,
|
||||
global.HTMLRewriter,
|
||||
global.Request,
|
||||
global.ResolveError,
|
||||
global.ResolveMessage,
|
||||
global.Response,
|
||||
global.TextDecoder,
|
||||
global.AbortSignal,
|
||||
global.BroadcastChannel,
|
||||
global.CloseEvent,
|
||||
global.DOMException,
|
||||
global.ErrorEvent,
|
||||
global.Event,
|
||||
global.EventTarget,
|
||||
global.FormData,
|
||||
global.Headers,
|
||||
global.MessageChannel,
|
||||
global.MessageEvent,
|
||||
global.MessagePort,
|
||||
global.PerformanceEntry,
|
||||
global.PerformanceObserver,
|
||||
global.PerformanceObserverEntryList,
|
||||
global.PerformanceResourceTiming,
|
||||
global.PerformanceServerTiming,
|
||||
global.PerformanceTiming,
|
||||
global.TextEncoder,
|
||||
global.URL,
|
||||
global.URLSearchParams,
|
||||
global.WebSocket,
|
||||
global.Worker,
|
||||
global.onmessage,
|
||||
global.onerror
|
||||
);
|
||||
}
|
||||
|
||||
function allowGlobals(...allowlist) {
|
||||
knownGlobals = knownGlobals.concat(allowlist);
|
||||
}
|
||||
@@ -1252,15 +1199,6 @@ const common = {
|
||||
get checkoutEOL() {
|
||||
return fs.readFileSync(__filename).includes('\r\n') ? '\r\n' : '\n';
|
||||
},
|
||||
|
||||
get isInsideDirWithUnusualChars() {
|
||||
return __dirname.includes('%') ||
|
||||
(!isWindows && __dirname.includes('\\')) ||
|
||||
__dirname.includes('$') ||
|
||||
__dirname.includes('\n') ||
|
||||
__dirname.includes('\r') ||
|
||||
__dirname.includes('\t');
|
||||
},
|
||||
};
|
||||
|
||||
const validProperties = new Set(Object.keys(common));
|
||||
|
||||
@@ -11,11 +11,11 @@ const {
|
||||
childShouldThrowAndAbort,
|
||||
createZeroFilledFile,
|
||||
enoughTestMem,
|
||||
escapePOSIXShell,
|
||||
expectsError,
|
||||
expectWarning,
|
||||
getArrayBufferViews,
|
||||
getBufferSources,
|
||||
getCallSite,
|
||||
getTTYfd,
|
||||
hasCrypto,
|
||||
hasIntl,
|
||||
@@ -65,11 +65,11 @@ export {
|
||||
createRequire,
|
||||
createZeroFilledFile,
|
||||
enoughTestMem,
|
||||
escapePOSIXShell,
|
||||
expectsError,
|
||||
expectWarning,
|
||||
getArrayBufferViews,
|
||||
getBufferSources,
|
||||
getCallSite,
|
||||
getPort,
|
||||
getTTYfd,
|
||||
hasCrypto,
|
||||
|
||||
@@ -255,8 +255,8 @@ class InspectorSession {
|
||||
const callFrame = message.params.callFrames[0];
|
||||
const location = callFrame.location;
|
||||
const scriptPath = this._scriptsIdsByUrl.get(location.scriptId);
|
||||
assert.strictEqual(scriptPath.toString(),
|
||||
expectedScriptPath.toString(),
|
||||
assert.strictEqual(decodeURIComponent(scriptPath),
|
||||
decodeURIComponent(expectedScriptPath),
|
||||
`${scriptPath} !== ${expectedScriptPath}`);
|
||||
assert.strictEqual(location.lineNumber, line);
|
||||
return true;
|
||||
@@ -271,6 +271,14 @@ class InspectorSession {
|
||||
`break on ${url}:${line}`);
|
||||
}
|
||||
|
||||
waitForPauseOnStart() {
|
||||
return this
|
||||
.waitForNotification(
|
||||
(notification) =>
|
||||
notification.method === 'Debugger.paused' && notification.params.reason === 'Break on start',
|
||||
'break on start');
|
||||
}
|
||||
|
||||
pausedDetails() {
|
||||
return this._pausedDetails;
|
||||
}
|
||||
@@ -309,6 +317,10 @@ class InspectorSession {
|
||||
return notification.method === 'Runtime.executionContextDestroyed' &&
|
||||
notification.params.executionContextId === 1;
|
||||
});
|
||||
await this.waitForDisconnect();
|
||||
}
|
||||
|
||||
async waitForDisconnect() {
|
||||
while ((await this._instance.nextStderrString()) !==
|
||||
'Waiting for the debugger to disconnect...');
|
||||
await this.disconnect();
|
||||
|
||||
23
test/js/node/test/common/net.js
Normal file
23
test/js/node/test/common/net.js
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
const net = require('net');
|
||||
|
||||
const options = { port: 0, reusePort: true };
|
||||
|
||||
function checkSupportReusePort() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = net.createServer().listen(options);
|
||||
server.on('listening', () => {
|
||||
server.close(resolve);
|
||||
});
|
||||
server.on('error', (err) => {
|
||||
console.log('The `reusePort` option is not supported:', err.message);
|
||||
server.close();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkSupportReusePort,
|
||||
options,
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const gcTrackerMap = new WeakMap();
|
||||
const gcTrackerTag = 'NODE_TEST_COMMON_GC_TRACKER';
|
||||
|
||||
function onGC(obj, gcListener) {
|
||||
const async_hooks = require('async_hooks');
|
||||
|
||||
const onGcAsyncHook = async_hooks.createHook({
|
||||
init: common.mustCallAtLeast(function(id, type) {
|
||||
if (this.trackedId === undefined) {
|
||||
assert.strictEqual(type, gcTrackerTag);
|
||||
this.trackedId = id;
|
||||
}
|
||||
}),
|
||||
destroy(id) {
|
||||
assert.notStrictEqual(this.trackedId, -1);
|
||||
if (id === this.trackedId) {
|
||||
this.gcListener.ongc();
|
||||
onGcAsyncHook.disable();
|
||||
}
|
||||
},
|
||||
}).enable();
|
||||
onGcAsyncHook.gcListener = gcListener;
|
||||
|
||||
gcTrackerMap.set(obj, new async_hooks.AsyncResource(gcTrackerTag));
|
||||
obj = null;
|
||||
}
|
||||
|
||||
module.exports = onGC;
|
||||
@@ -59,7 +59,12 @@ function _validateContent(report, fields = []) {
|
||||
|
||||
// Verify that all sections are present as own properties of the report.
|
||||
const sections = ['header', 'nativeStack', 'javascriptStack', 'libuv',
|
||||
'environmentVariables', 'sharedObjects', 'resourceUsage', 'workers'];
|
||||
'sharedObjects', 'resourceUsage', 'workers'];
|
||||
|
||||
if (!process.report.excludeEnv) {
|
||||
sections.push('environmentVariables');
|
||||
}
|
||||
|
||||
if (!isWindows)
|
||||
sections.push('userLimits');
|
||||
|
||||
@@ -105,7 +110,7 @@ function _validateContent(report, fields = []) {
|
||||
'glibcVersionRuntime', 'glibcVersionCompiler', 'cwd',
|
||||
'reportVersion', 'networkInterfaces', 'threadId'];
|
||||
checkForUnknownFields(header, headerFields);
|
||||
assert.strictEqual(header.reportVersion, 3); // Increment as needed.
|
||||
assert.strictEqual(header.reportVersion, 5); // Increment as needed.
|
||||
assert.strictEqual(typeof header.event, 'string');
|
||||
assert.strictEqual(typeof header.trigger, 'string');
|
||||
assert(typeof header.filename === 'string' || header.filename === null);
|
||||
@@ -251,7 +256,7 @@ function _validateContent(report, fields = []) {
|
||||
assert(typeof usage.free_memory, 'string');
|
||||
assert(typeof usage.total_memory, 'string');
|
||||
assert(typeof usage.available_memory, 'string');
|
||||
// This field may not exsit
|
||||
// This field may not exist
|
||||
if (report.resourceUsage.constrained_memory) {
|
||||
assert(typeof report.resourceUsage.constrained_memory, 'string');
|
||||
}
|
||||
@@ -294,19 +299,21 @@ function _validateContent(report, fields = []) {
|
||||
resource.type === 'loop' ? 'undefined' : 'boolean');
|
||||
});
|
||||
|
||||
// Verify the format of the environmentVariables section.
|
||||
for (const [key, value] of Object.entries(report.environmentVariables)) {
|
||||
assert.strictEqual(typeof key, 'string');
|
||||
assert.strictEqual(typeof value, 'string');
|
||||
if (!process.report.excludeEnv) {
|
||||
// Verify the format of the environmentVariables section.
|
||||
for (const [key, value] of Object.entries(report.environmentVariables)) {
|
||||
assert.strictEqual(typeof key, 'string');
|
||||
assert.strictEqual(typeof value, 'string');
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the format of the userLimits section on non-Windows platforms.
|
||||
if (!isWindows) {
|
||||
const userLimitsFields = ['core_file_size_blocks', 'data_seg_size_kbytes',
|
||||
const userLimitsFields = ['core_file_size_blocks', 'data_seg_size_bytes',
|
||||
'file_size_blocks', 'max_locked_memory_bytes',
|
||||
'max_memory_size_kbytes', 'open_files',
|
||||
'max_memory_size_bytes', 'open_files',
|
||||
'stack_size_bytes', 'cpu_time_seconds',
|
||||
'max_user_processes', 'virtual_memory_kbytes'];
|
||||
'max_user_processes', 'virtual_memory_bytes'];
|
||||
checkForUnknownFields(report.userLimits, userLimitsFields);
|
||||
for (const [type, limits] of Object.entries(report.userLimits)) {
|
||||
assert.strictEqual(typeof type, 'string');
|
||||
|
||||
@@ -13,7 +13,7 @@ function addLibraryPath(env) {
|
||||
return;
|
||||
}
|
||||
|
||||
env = env || process.env;
|
||||
env ||= process.env;
|
||||
|
||||
env.LD_LIBRARY_PATH =
|
||||
(env.LD_LIBRARY_PATH ? env.LD_LIBRARY_PATH + path.delimiter : '') +
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
'use strict';
|
||||
require('../common');
|
||||
|
||||
module.exports = function tick(x, cb) {
|
||||
function ontick() {
|
||||
|
||||
@@ -46,8 +46,6 @@ function refresh(useSpawn = false) {
|
||||
}
|
||||
|
||||
function onexit(useSpawn) {
|
||||
if (process.env.KEEP_TEMP) return;
|
||||
|
||||
// Change directory to avoid possible EBUSY
|
||||
if (isMainThread)
|
||||
process.chdir(testRoot);
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
'use strict';
|
||||
const { internalBinding } = require('internal/test/binding');
|
||||
const { JSUDPWrap } = internalBinding('js_udp_wrap');
|
||||
const EventEmitter = require('events');
|
||||
|
||||
// FakeUDPWrap is a testing utility that emulates a UDP connection
|
||||
// for the sake of making UDP tests more deterministic.
|
||||
class FakeUDPWrap extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._handle = new JSUDPWrap();
|
||||
|
||||
this._handle.onreadstart = () => this._startReading();
|
||||
this._handle.onreadstop = () => this._stopReading();
|
||||
this._handle.onwrite =
|
||||
(wrap, buffers, addr) => this._write(wrap, buffers, addr);
|
||||
this._handle.getsockname = (obj) => {
|
||||
Object.assign(obj, { address: '127.0.0.1', family: 'IPv4', port: 1337 });
|
||||
return 0;
|
||||
};
|
||||
|
||||
this.reading = false;
|
||||
this.bufferedReceived = [];
|
||||
this.emitBufferedImmediate = null;
|
||||
}
|
||||
|
||||
_emitBuffered = () => {
|
||||
if (!this.reading) return;
|
||||
if (this.bufferedReceived.length > 0) {
|
||||
this.emitReceived(this.bufferedReceived.shift());
|
||||
this.emitBufferedImmediate = setImmediate(this._emitBuffered);
|
||||
} else {
|
||||
this.emit('wantRead');
|
||||
}
|
||||
};
|
||||
|
||||
_startReading() {
|
||||
this.reading = true;
|
||||
this.emitBufferedImmediate = setImmediate(this._emitBuffered);
|
||||
}
|
||||
|
||||
_stopReading() {
|
||||
this.reading = false;
|
||||
clearImmediate(this.emitBufferedImmediate);
|
||||
}
|
||||
|
||||
_write(wrap, buffers, addr) {
|
||||
this.emit('send', { buffers, addr });
|
||||
setImmediate(() => this._handle.onSendDone(wrap, 0));
|
||||
}
|
||||
|
||||
afterBind() {
|
||||
this._handle.onAfterBind();
|
||||
}
|
||||
|
||||
emitReceived(info) {
|
||||
if (!this.reading) {
|
||||
this.bufferedReceived.push(info);
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
buffers,
|
||||
addr: {
|
||||
family = 4,
|
||||
address = '127.0.0.1',
|
||||
port = 1337,
|
||||
},
|
||||
flags = 0,
|
||||
} = info;
|
||||
|
||||
let familyInt;
|
||||
switch (family) {
|
||||
case 'IPv4': familyInt = 4; break;
|
||||
case 'IPv6': familyInt = 6; break;
|
||||
default: throw new Error('bad family');
|
||||
}
|
||||
|
||||
for (const buffer of buffers) {
|
||||
this._handle.emitReceived(buffer, familyInt, address, port, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeUDPPair() {
|
||||
const serverSide = new FakeUDPWrap();
|
||||
const clientSide = new FakeUDPWrap();
|
||||
|
||||
serverSide.on('send',
|
||||
(chk) => setImmediate(() => clientSide.emitReceived(chk)));
|
||||
clientSide.on('send',
|
||||
(chk) => setImmediate(() => serverSide.emitReceived(chk)));
|
||||
|
||||
return { serverSide, clientSide };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
FakeUDPWrap,
|
||||
makeUDPPair,
|
||||
};
|
||||
@@ -458,8 +458,16 @@ class StatusLoader {
|
||||
|
||||
load() {
|
||||
const dir = path.join(__dirname, '..', 'wpt');
|
||||
const statusFile = path.join(dir, 'status', `${this.path}.json`);
|
||||
const result = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
|
||||
let statusFile = path.join(dir, 'status', `${this.path}.json`);
|
||||
let result;
|
||||
|
||||
if (fs.existsSync(statusFile)) {
|
||||
result = JSON.parse(fs.readFileSync(statusFile, 'utf8'));
|
||||
} else {
|
||||
statusFile = path.join(dir, 'status', `${this.path}.cjs`);
|
||||
result = require(statusFile);
|
||||
}
|
||||
|
||||
this.rules.addRules(result);
|
||||
|
||||
const subDir = fixtures.path('wpt', this.path);
|
||||
@@ -870,22 +878,16 @@ class WPTRunner {
|
||||
|
||||
addTestResult(spec, item) {
|
||||
let result = this.results[spec.filename];
|
||||
if (!result) {
|
||||
result = this.results[spec.filename] = {};
|
||||
}
|
||||
result ||= this.results[spec.filename] = {};
|
||||
if (item.status === kSkip) {
|
||||
// { filename: { skip: 'reason' } }
|
||||
result[kSkip] = item.reason;
|
||||
} else {
|
||||
// { filename: { fail: { expected: [ ... ],
|
||||
// unexpected: [ ... ] } }}
|
||||
if (!result[item.status]) {
|
||||
result[item.status] = {};
|
||||
}
|
||||
result[item.status] ||= {};
|
||||
const key = item.expected ? 'expected' : 'unexpected';
|
||||
if (!result[item.status][key]) {
|
||||
result[item.status][key] = [];
|
||||
}
|
||||
result[item.status][key] ||= [];
|
||||
const hasName = result[item.status][key].includes(item.name);
|
||||
if (!hasName) {
|
||||
result[item.status][key].push(item.name);
|
||||
|
||||
70
test/js/node/test/common/wpt/worker.js
Normal file
70
test/js/node/test/common/wpt/worker.js
Normal file
@@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
|
||||
const { runInNewContext, runInThisContext } = require('vm');
|
||||
const { setFlagsFromString } = require('v8');
|
||||
const { parentPort, workerData } = require('worker_threads');
|
||||
|
||||
const { ResourceLoader } = require(workerData.wptRunner);
|
||||
const resource = new ResourceLoader(workerData.wptPath);
|
||||
|
||||
if (workerData.needsGc) {
|
||||
// See https://github.com/nodejs/node/issues/16595#issuecomment-340288680
|
||||
setFlagsFromString('--expose-gc');
|
||||
globalThis.gc = runInNewContext('gc');
|
||||
}
|
||||
|
||||
globalThis.self = global;
|
||||
globalThis.GLOBAL = {
|
||||
isWindow() { return false; },
|
||||
isShadowRealm() { return false; },
|
||||
};
|
||||
globalThis.require = require;
|
||||
|
||||
// This is a mock for non-fetch tests that use fetch to resolve
|
||||
// a relative fixture file.
|
||||
// Actual Fetch API WPTs are executed in nodejs/undici.
|
||||
globalThis.fetch = function fetch(file) {
|
||||
return resource.readAsFetch(workerData.testRelativePath, file);
|
||||
};
|
||||
|
||||
if (workerData.initScript) {
|
||||
runInThisContext(workerData.initScript);
|
||||
}
|
||||
|
||||
runInThisContext(workerData.harness.code, {
|
||||
filename: workerData.harness.filename,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
add_result_callback((result) => {
|
||||
parentPort.postMessage({
|
||||
type: 'result',
|
||||
result: {
|
||||
status: result.status,
|
||||
name: result.name,
|
||||
message: result.message,
|
||||
stack: result.stack,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Keep the event loop alive
|
||||
const timeout = setTimeout(() => {
|
||||
parentPort.postMessage({
|
||||
type: 'completion',
|
||||
status: { status: 2 },
|
||||
});
|
||||
}, 2 ** 31 - 1); // Max timeout is 2^31-1, when overflown the timeout is set to 1.
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
add_completion_callback((_, status) => {
|
||||
clearTimeout(timeout);
|
||||
parentPort.postMessage({
|
||||
type: 'completion',
|
||||
status,
|
||||
});
|
||||
});
|
||||
|
||||
for (const scriptToRun of workerData.scriptsToRun) {
|
||||
runInThisContext(scriptToRun.code, { filename: scriptToRun.filename });
|
||||
}
|
||||
Reference in New Issue
Block a user