summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2018-11-03 17:48:47 +0100
committerAnna Henningsen <anna@addaleax.net>2018-11-10 21:54:48 +0100
commitd3f02d0da3d574b91a15d3ace10e76014b7574fc (patch)
tree7982db3b18811ca0cd7d4da5a66c43c6ecf1953e /test
parentfb6c6692a8d2e7e4d86a742216151a6e5e15739b (diff)
downloadandroid-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.js59
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);
+ }
+}