0
0
mirror of https://github.com/nodejs/node.git synced 2024-12-01 16:10:02 +01:00
nodejs/test/parallel/test-stream-duplex-destroy.js
Mathias Buus 5e3f51648e stream: updated streams error handling
This improves error handling for streams in a few ways.

1. It ensures that no user defined methods (_read, _write, ...) are run
after .destroy has been called.
2. It introduces an explicit error to tell the user if they are write to
write, etc to the stream after it has been destroyed.
3. It makes streams always emit close as the last thing after they have
been destroyed
4. Changes the default _destroy to not gracefully end streams.

It also updates net, http2, zlib and fs to the new error handling.

PR-URL: https://github.com/nodejs/node/pull/18438
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2018-03-06 13:31:56 +01:00

197 lines
4.1 KiB
JavaScript

'use strict';
const common = require('../common');
const { Duplex } = require('stream');
const assert = require('assert');
const { inherits } = require('util');
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {}
});
duplex.resume();
duplex.on('end', common.mustNotCall());
duplex.on('finish', common.mustNotCall());
duplex.on('close', common.mustCall());
duplex.destroy();
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {}
});
duplex.resume();
const expected = new Error('kaboom');
duplex.on('end', common.mustNotCall());
duplex.on('finish', common.mustNotCall());
duplex.on('error', common.mustCall((err) => {
assert.strictEqual(err, expected);
}));
duplex.destroy(expected);
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {}
});
duplex._destroy = common.mustCall(function(err, cb) {
assert.strictEqual(err, expected);
cb(err);
});
const expected = new Error('kaboom');
duplex.on('finish', common.mustNotCall('no finish event'));
duplex.on('error', common.mustCall((err) => {
assert.strictEqual(err, expected);
}));
duplex.destroy(expected);
assert.strictEqual(duplex.destroyed, true);
}
{
const expected = new Error('kaboom');
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {},
destroy: common.mustCall(function(err, cb) {
assert.strictEqual(err, expected);
cb();
})
});
duplex.resume();
duplex.on('end', common.mustNotCall('no end event'));
duplex.on('finish', common.mustNotCall('no finish event'));
// error is swallowed by the custom _destroy
duplex.on('error', common.mustNotCall('no error event'));
duplex.on('close', common.mustCall());
duplex.destroy(expected);
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {}
});
duplex._destroy = common.mustCall(function(err, cb) {
assert.strictEqual(err, null);
cb();
});
duplex.destroy();
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {}
});
duplex.resume();
duplex._destroy = common.mustCall(function(err, cb) {
assert.strictEqual(err, null);
process.nextTick(() => {
this.push(null);
this.end();
cb();
});
});
const fail = common.mustNotCall('no finish or end event');
duplex.on('finish', fail);
duplex.on('end', fail);
duplex.destroy();
duplex.removeListener('end', fail);
duplex.removeListener('finish', fail);
duplex.on('end', common.mustCall());
duplex.on('finish', common.mustCall());
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {}
});
const expected = new Error('kaboom');
duplex._destroy = common.mustCall(function(err, cb) {
assert.strictEqual(err, null);
cb(expected);
});
duplex.on('finish', common.mustNotCall('no finish event'));
duplex.on('end', common.mustNotCall('no end event'));
duplex.on('error', common.mustCall((err) => {
assert.strictEqual(err, expected);
}));
duplex.destroy();
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {},
allowHalfOpen: true
});
duplex.resume();
duplex.on('finish', common.mustNotCall());
duplex.on('end', common.mustNotCall());
duplex.destroy();
assert.strictEqual(duplex.destroyed, true);
}
{
const duplex = new Duplex({
write(chunk, enc, cb) { cb(); },
read() {},
});
duplex.destroyed = true;
assert.strictEqual(duplex.destroyed, true);
// the internal destroy() mechanism should not be triggered
duplex.on('finish', common.mustNotCall());
duplex.on('end', common.mustNotCall());
duplex.destroy();
}
{
function MyDuplex() {
assert.strictEqual(this.destroyed, false);
this.destroyed = false;
Duplex.call(this);
}
inherits(MyDuplex, Duplex);
new MyDuplex();
}