Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
test: deflake fastutf8stream destroy and reopen tests
Both tests read the destination file with no ordering guarantee against
the fs.write() that Utf8Stream still has in flight, so under load the
read can observe an empty file.

In test-fastutf8stream-destroy the read is issued right after destroy().
In test-fastutf8stream-reopen it is ordered on 'drain', documented as
emitted when the buffer has drained enough to allow continued writing,
which says nothing about the bytes being observable in the file. The
reopen path also emits a 'drain' of its own from a nextTick before the
write has landed.

Order both reads on 'write' instead, documented as emitted when a write
operation has completed and emitted from #release() once the underlying
write returned. In sync mode it is emitted from within write(), so the
listener is attached before the write call.

No data is lost by Utf8Stream here: re-reading the file after a failed
assertion shows the expected content. This corrects an expectation of
the tests, not the runtime.

Signed-off-by: Christian Aurich <christian.aurichzm@gmail.com>
  • Loading branch information
christianaurichzm committed Aug 26, 2026
commit db8a01272eafef5f8c20553f87e9d1a2ea8e62b8
7 changes: 5 additions & 2 deletions test/parallel/test-fastutf8stream-destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ function getTempFile() {

assert.throws(() => stream.write('hello world\n'), Error);

readFile(dest, 'utf8', common.mustSucceed((data) => {
assert.strictEqual(data, 'hello world\n');
// Reading now would race the fs.write() still in flight.
stream.once('write', common.mustCall(() => {
readFile(dest, 'utf8', common.mustSucceed((data) => {
assert.strictEqual(data, 'hello world\n');
}));
}));

stream.on('finish', common.mustNotCall());
Expand Down
15 changes: 9 additions & 6 deletions test/parallel/test-fastutf8stream-reopen.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ function runTests(sync) {
stream.reopen();

stream.once('ready', common.mustCall(() => {
assert.ok(stream.write('after reopen\n'));

stream.once('drain', common.mustCall(() => {
// 'drain' can come from reopen() before this write completes. 'write'
// is emitted synchronously in sync mode, so attach before writing.
stream.once('write', common.mustCall(() => {
readFile(after, 'utf8', common.mustSucceed((data) => {
assert.strictEqual(data, 'hello world\nsomething else\n');
readFile(dest, 'utf8', common.mustSucceed((data) => {
Expand All @@ -54,6 +54,8 @@ function runTests(sync) {
}));
}));
}));

assert.ok(stream.write('after reopen\n'));
}));
}));
}
Expand Down Expand Up @@ -85,9 +87,8 @@ function runTests(sync) {
assert.strictEqual(stream.file, after);

stream.once('ready', common.mustCall(() => {
assert.ok(stream.write('after reopen\n'));

stream.once('drain', common.mustCall(() => {
// As above: 'drain' can come from reopen() before the write completes.
stream.once('write', common.mustCall(() => {
readFile(dest, 'utf8', common.mustSucceed((data) => {
assert.strictEqual(data, 'hello world\nsomething else\n');
readFile(after, 'utf8', common.mustSucceed((data) => {
Expand All @@ -96,6 +97,8 @@ function runTests(sync) {
}));
}));
}));

assert.ok(stream.write('after reopen\n'));
}));
}));
}
Expand Down
Loading