diff options
author | Anna Henningsen <anna@addaleax.net> | 2018-11-03 17:48:47 +0100 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2018-11-10 21:54:48 +0100 |
commit | d3f02d0da3d574b91a15d3ace10e76014b7574fc (patch) | |
tree | 7982db3b18811ca0cd7d4da5a66c43c6ecf1953e /test | |
parent | fb6c6692a8d2e7e4d86a742216151a6e5e15739b (diff) | |
download | android-node-v8-d3f02d0da3d574b91a15d3ace10e76014b7574fc.tar.gz android-node-v8-d3f02d0da3d574b91a15d3ace10e76014b7574fc.tar.bz2 android-node-v8-d3f02d0da3d574b91a15d3ace10e76014b7574fc.zip |
stream: make `.destroy()` interact better with write queue
Make sure that it is safe to call the callback for `_write()`
even in the presence of `.destroy()` calls during that write.
In particular, letting the write queue continue processing would
previously have thrown an exception, because processing writes
after calling `.destroy()` is forbidden.
One test had to be modified to account for the fact that callbacks
for writes will now always be called, even when the stream
is destroyed during the process.
PR-URL: https://github.com/nodejs/node/pull/24062
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/parallel/test-stream-write-destroy.js | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/test/parallel/test-stream-write-destroy.js b/test/parallel/test-stream-write-destroy.js new file mode 100644 index 0000000000..83b329a6a8 --- /dev/null +++ b/test/parallel/test-stream-write-destroy.js @@ -0,0 +1,59 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const { Writable } = require('stream'); + +// Test interaction between calling .destroy() on a writable and pending +// writes. + +for (const withPendingData of [ false, true ]) { + for (const useEnd of [ false, true ]) { + const callbacks = []; + + const w = new Writable({ + write(data, enc, cb) { + callbacks.push(cb); + }, + // Effectively disable the HWM to observe 'drain' events more easily. + highWaterMark: 1 + }); + + let chunksWritten = 0; + let drains = 0; + let finished = false; + w.on('drain', () => drains++); + w.on('finish', () => finished = true); + + w.write('abc', () => chunksWritten++); + assert.strictEqual(chunksWritten, 0); + assert.strictEqual(drains, 0); + callbacks.shift()(); + assert.strictEqual(chunksWritten, 1); + assert.strictEqual(drains, 1); + + if (withPendingData) { + // Test 2 cases: There either is or is not data still in the write queue. + // (The second write will never actually get executed either way.) + w.write('def', () => chunksWritten++); + } + if (useEnd) { + // Again, test 2 cases: Either we indicate that we want to end the + // writable or not. + w.end('ghi', () => chunksWritten++); + } else { + w.write('ghi', () => chunksWritten++); + } + + assert.strictEqual(chunksWritten, 1); + w.destroy(); + assert.strictEqual(chunksWritten, 1); + callbacks.shift()(); + assert.strictEqual(chunksWritten, 2); + assert.strictEqual(callbacks.length, 0); + assert.strictEqual(drains, 1); + + // When we used `.end()`, we see the 'finished' event if and only if + // we actually finished processing the write queue. + assert.strictEqual(finished, !withPendingData && useEnd); + } +} |