2023-02-07 17:43:57 +00:00
|
|
|
// Flags: --expose-gc
|
|
|
|
'use strict';
|
|
|
|
|
2024-08-26 22:20:18 +00:00
|
|
|
require('../common');
|
2023-02-07 17:43:57 +00:00
|
|
|
const { aborted } = require('util');
|
2024-08-26 22:20:18 +00:00
|
|
|
const {
|
|
|
|
match,
|
|
|
|
rejects,
|
|
|
|
strictEqual,
|
|
|
|
} = require('assert');
|
2023-02-07 17:43:57 +00:00
|
|
|
const { getEventListeners } = require('events');
|
2024-08-26 22:20:18 +00:00
|
|
|
const { inspect } = require('util');
|
2023-02-07 17:43:57 +00:00
|
|
|
|
2024-08-26 22:20:18 +00:00
|
|
|
const {
|
|
|
|
test,
|
|
|
|
} = require('node:test');
|
|
|
|
|
|
|
|
test('Aborted works when provided a resource', async () => {
|
2023-02-07 17:43:57 +00:00
|
|
|
const ac = new AbortController();
|
2024-08-26 22:20:18 +00:00
|
|
|
const promise = aborted(ac.signal, {});
|
2023-02-07 17:43:57 +00:00
|
|
|
ac.abort();
|
2024-08-26 22:20:18 +00:00
|
|
|
await promise;
|
|
|
|
strictEqual(ac.signal.aborted, true);
|
|
|
|
strictEqual(getEventListeners(ac.signal, 'abort').length, 0);
|
|
|
|
});
|
2023-02-07 17:43:57 +00:00
|
|
|
|
2024-08-26 22:20:18 +00:00
|
|
|
test('Aborted with gc cleanup', async () => {
|
2023-02-07 17:43:57 +00:00
|
|
|
// Test aborted with gc cleanup
|
|
|
|
const ac = new AbortController();
|
2024-08-26 22:20:18 +00:00
|
|
|
|
|
|
|
const abortedPromise = aborted(ac.signal, {});
|
|
|
|
const { promise, resolve } = Promise.withResolvers();
|
|
|
|
|
2023-02-07 17:43:57 +00:00
|
|
|
setImmediate(() => {
|
|
|
|
global.gc();
|
|
|
|
ac.abort();
|
2024-08-26 22:20:18 +00:00
|
|
|
strictEqual(ac.signal.aborted, true);
|
|
|
|
strictEqual(getEventListeners(ac.signal, 'abort').length, 0);
|
|
|
|
resolve();
|
2023-02-07 17:43:57 +00:00
|
|
|
});
|
|
|
|
|
2024-08-26 22:20:18 +00:00
|
|
|
await promise;
|
|
|
|
|
|
|
|
// Ensure that the promise is still pending
|
|
|
|
match(inspect(abortedPromise), /<pending>/);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('Fails with error if not provided AbortSignal', async () => {
|
|
|
|
await Promise.all([{}, null, undefined, Symbol(), [], 1, 0, 1n, true, false, 'a', () => {}].map((sig) =>
|
|
|
|
rejects(aborted(sig, {}), {
|
2023-02-07 17:43:57 +00:00
|
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
|
|
})
|
2024-08-26 22:20:18 +00:00
|
|
|
));
|
|
|
|
});
|
2023-02-07 17:43:57 +00:00
|
|
|
|
2024-08-26 22:20:18 +00:00
|
|
|
test('Fails if not provided a resource', async () => {
|
2023-02-07 17:43:57 +00:00
|
|
|
// Fails if not provided a resource
|
|
|
|
const ac = new AbortController();
|
2024-08-26 22:20:18 +00:00
|
|
|
await Promise.all([null, undefined, 0, 1, 0n, 1n, Symbol(), '', 'a'].map((resource) =>
|
|
|
|
rejects(aborted(ac.signal, resource), {
|
2023-02-07 17:43:57 +00:00
|
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
|
|
})
|
2024-08-26 22:20:18 +00:00
|
|
|
));
|
|
|
|
});
|
|
|
|
|
|
|
|
// To allow this case to be more flexibly tested on runtimes that do not have
|
|
|
|
// child_process.spawn, we lazily require it and skip the test if it is not
|
|
|
|
// present.
|
|
|
|
|
|
|
|
let spawn;
|
|
|
|
function lazySpawn() {
|
|
|
|
if (spawn === undefined) {
|
|
|
|
try {
|
|
|
|
spawn = require('child_process').spawn;
|
|
|
|
} catch {
|
|
|
|
// Ignore if spawn does not exist.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return spawn;
|
2023-02-07 17:43:57 +00:00
|
|
|
}
|
|
|
|
|
2024-08-26 22:20:18 +00:00
|
|
|
test('Does not hang forever', { skip: !lazySpawn() }, async () => {
|
|
|
|
const { promise, resolve } = Promise.withResolvers();
|
2023-02-07 17:43:57 +00:00
|
|
|
const childProcess = spawn(process.execPath, ['--input-type=module']);
|
2024-08-26 22:20:18 +00:00
|
|
|
childProcess.on('exit', (code) => {
|
|
|
|
strictEqual(code, 13);
|
|
|
|
resolve();
|
|
|
|
});
|
2023-02-07 17:43:57 +00:00
|
|
|
childProcess.stdin.end(`
|
|
|
|
import { aborted } from 'node:util';
|
|
|
|
await aborted(new AbortController().signal, {});
|
|
|
|
`);
|
2024-08-26 22:20:18 +00:00
|
|
|
await promise;
|
|
|
|
});
|