mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: https://github.com/nodejs/node/pull/64716 Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Aviv Keller <me@aviv.sh>
72 lines
2.5 KiB
JavaScript
72 lines
2.5 KiB
JavaScript
// Flags: --experimental-quic --no-warnings
|
|
|
|
// stream.destroy(error, options) validates `options` up front, before
|
|
// any side effects. A malformed `options` argument must throw without
|
|
// mutating `#destroying`, emitting wire frames, invoking `onerror`,
|
|
// or settling the `closed` promise. After the throw, the stream is
|
|
// still alive and a subsequent destroy with valid options must
|
|
// succeed.
|
|
|
|
import { hasQuic, skip, mustCall, mustNotCall } from '../common/index.mjs';
|
|
import assert from 'node:assert';
|
|
|
|
if (!hasQuic) {
|
|
skip('QUIC is not enabled');
|
|
}
|
|
|
|
const { listen, connect } = await import('../common/quic.mjs');
|
|
|
|
const serverEndpoint = await listen(mustCall(() => true));
|
|
|
|
const clientSession = await connect(serverEndpoint.address);
|
|
await clientSession.opened;
|
|
|
|
const stream = await clientSession.createBidirectionalStream();
|
|
|
|
stream.onerror = mustNotCall(
|
|
'stream.onerror must not fire when destroy() throws on bad options');
|
|
|
|
// 1. options is not an object -> throws ERR_INVALID_ARG_TYPE.
|
|
assert.throws(() => stream.destroy(new Error('x'), 'not an object'), {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
});
|
|
assert.strictEqual(stream.destroyed, false);
|
|
|
|
// 2. options.code is the wrong type -> throws ERR_INVALID_ARG_TYPE.
|
|
assert.throws(() => stream.destroy(new Error('x'), { code: 'oops' }), {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
});
|
|
assert.strictEqual(stream.destroyed, false);
|
|
|
|
assert.throws(() => stream.destroy(new Error('x'), { code: true }), {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
});
|
|
assert.strictEqual(stream.destroyed, false);
|
|
|
|
// 3. options.reason is the wrong type -> throws ERR_INVALID_ARG_TYPE.
|
|
assert.throws(() => stream.destroy(new Error('x'), { reason: 42 }), {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
});
|
|
assert.strictEqual(stream.destroyed, false);
|
|
|
|
// Switch to the real error handler before the final destroy so the
|
|
// `mustNotCall` above does not fire on the legitimate teardown.
|
|
const finalError = new Error('final destroy');
|
|
stream.onerror = mustCall((err) => { assert.strictEqual(err, finalError); });
|
|
|
|
const clientClosedAssertion = assert.rejects(stream.closed, finalError);
|
|
|
|
// 4. Valid options accepted: bigint code.
|
|
stream.destroy(finalError, { code: 0x10n, reason: 'cleanup' });
|
|
assert.strictEqual(stream.destroyed, true);
|
|
|
|
// 5. Re-entry with arbitrarily bad options is a no-op (the
|
|
// re-entrancy guard returns before validation runs).
|
|
stream.destroy(new Error('after-destroy'), { code: 'still-bad' });
|
|
assert.strictEqual(stream.destroyed, true);
|
|
|
|
await clientClosedAssertion;
|
|
|
|
await clientSession.close();
|
|
await serverEndpoint.close();
|