mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
144 lines
4.4 KiB
JavaScript
144 lines
4.4 KiB
JavaScript
|
// deno-fmt-ignore-file
|
||
|
// deno-lint-ignore-file
|
||
|
|
||
|
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||
|
// Taken from Node 20.11.1
|
||
|
// This file is automatically generated by `tests/node_compat/runner/setup.ts`. Do not modify this file manually.
|
||
|
|
||
|
'use strict';
|
||
|
const common = require('../common');
|
||
|
const assert = require('assert');
|
||
|
const fs = require('fs');
|
||
|
const path = require('path');
|
||
|
const cp = require('child_process');
|
||
|
const { spawnSync } = require('child_process');
|
||
|
|
||
|
// This is a sibling test to test/addons/uv-handle-leak.
|
||
|
|
||
|
const bindingPath = path.resolve(
|
||
|
__dirname, '..', 'addons', 'uv-handle-leak', 'build',
|
||
|
`${common.buildType}/binding.node`);
|
||
|
|
||
|
if (!fs.existsSync(bindingPath))
|
||
|
common.skip('binding not built yet');
|
||
|
|
||
|
if (process.argv[2] === 'child') {
|
||
|
|
||
|
const { Worker } = require('worker_threads');
|
||
|
|
||
|
// The worker thread loads and then unloads `bindingPath`. Because of this the
|
||
|
// symbols in `bindingPath` are lost when the worker thread quits, but the
|
||
|
// number of open handles in the worker thread's event loop is assessed in the
|
||
|
// main thread afterwards, and the names of the callbacks associated with the
|
||
|
// open handles is retrieved at that time as well. Thus, we require
|
||
|
// `bindingPath` here so that the symbols and their names survive the life
|
||
|
// cycle of the worker thread.
|
||
|
require(bindingPath);
|
||
|
|
||
|
new Worker(`
|
||
|
const binding = require(${JSON.stringify(bindingPath)});
|
||
|
|
||
|
binding.leakHandle();
|
||
|
binding.leakHandle(0);
|
||
|
binding.leakHandle(0x42);
|
||
|
`, { eval: true });
|
||
|
} else {
|
||
|
const child = cp.spawnSync(process.execPath, [__filename, 'child']);
|
||
|
const stderr = child.stderr.toString();
|
||
|
|
||
|
assert.strictEqual(child.stdout.toString(), '');
|
||
|
|
||
|
const lines = stderr.split('\n');
|
||
|
|
||
|
let state = 'initial';
|
||
|
|
||
|
// Parse output that is formatted like this:
|
||
|
|
||
|
// uv loop at [0x559b65ed5770] has open handles:
|
||
|
// [0x7f2de0018430] timer (active)
|
||
|
// Close callback: 0x7f2df31de220 CloseCallback(uv_handle_s*) [...]
|
||
|
// Data: 0x7f2df33df140 example_instance [...]
|
||
|
// (First field): 0x7f2df33dedc0 vtable for ExampleOwnerClass [...]
|
||
|
// [0x7f2de000b870] timer
|
||
|
// Close callback: 0x7f2df31de220 CloseCallback(uv_handle_s*) [...]
|
||
|
// Data: (nil)
|
||
|
// [0x7f2de000b910] timer
|
||
|
// Close callback: 0x7f2df31de220 CloseCallback(uv_handle_s*) [...]
|
||
|
// Data: 0x42
|
||
|
// uv loop at [0x559b65ed5770] has 3 open handles in total
|
||
|
|
||
|
function isGlibc() {
|
||
|
try {
|
||
|
const lddOut = spawnSync('ldd', [process.execPath]).stdout;
|
||
|
const libcInfo = lddOut.toString().split('\n').map(
|
||
|
(line) => line.match(/libc\.so.+=>\s*(\S+)\s/)).filter((info) => info);
|
||
|
if (libcInfo.length === 0)
|
||
|
return false;
|
||
|
const nmOut = spawnSync('nm', ['-D', libcInfo[0][1]]).stdout;
|
||
|
if (/gnu_get_libc_version/.test(nmOut))
|
||
|
return true;
|
||
|
} catch {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!(common.isFreeBSD ||
|
||
|
common.isAIX ||
|
||
|
common.isIBMi ||
|
||
|
(common.isLinux && !isGlibc()) ||
|
||
|
common.isWindows)) {
|
||
|
assert(stderr.includes('ExampleOwnerClass'), stderr);
|
||
|
assert(stderr.includes('CloseCallback'), stderr);
|
||
|
assert(stderr.includes('example_instance'), stderr);
|
||
|
}
|
||
|
|
||
|
while (lines.length > 0) {
|
||
|
const line = lines.shift().trim();
|
||
|
if (line.length === 0) {
|
||
|
continue; // Skip empty lines.
|
||
|
}
|
||
|
|
||
|
switch (state) {
|
||
|
case 'initial':
|
||
|
assert.match(line, /^uv loop at \[.+\] has open handles:$/);
|
||
|
state = 'handle-start';
|
||
|
break;
|
||
|
case 'handle-start':
|
||
|
if (/^uv loop at \[.+\] has \d+ open handles in total$/.test(line)) {
|
||
|
state = 'source-line';
|
||
|
break;
|
||
|
}
|
||
|
assert.match(line, /^\[.+\] timer( \(active\))?$/);
|
||
|
state = 'close-callback';
|
||
|
break;
|
||
|
case 'close-callback':
|
||
|
assert.match(line, /^Close callback:/);
|
||
|
state = 'data';
|
||
|
break;
|
||
|
case 'data':
|
||
|
assert.match(line, /^Data: .+$/);
|
||
|
state = 'maybe-first-field';
|
||
|
break;
|
||
|
case 'maybe-first-field':
|
||
|
if (!/^\(First field\)/.test(line)) {
|
||
|
lines.unshift(line);
|
||
|
}
|
||
|
state = 'handle-start';
|
||
|
break;
|
||
|
case 'source-line':
|
||
|
assert.match(line, /CheckedUvLoopClose/);
|
||
|
state = 'assertion-failure';
|
||
|
break;
|
||
|
case 'assertion-failure':
|
||
|
assert.match(line, /Assertion failed:/);
|
||
|
state = 'done';
|
||
|
break;
|
||
|
case 'done':
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
assert.strictEqual(state, 'done');
|
||
|
}
|