test: fix flaky test-fs-stream-construct

The test is marked flaky on ARM because it times out on Raspberry Pi
devices in CI. Split the single test file into four separate test files
to ease debugging. Add fs.close() to avoid timing out.

Fixes: https://github.com/nodejs/node/issues/33796

PR-URL: https://github.com/nodejs/node/pull/34203
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
This commit is contained in:
Rich Trott 2020-07-04 09:37:02 -07:00
parent ee3416b055
commit 772fdb0cd3
6 changed files with 249 additions and 214 deletions

View File

@ -40,8 +40,6 @@ test-async-hooks-http-parser-destroy: PASS,FLAKY
# https://github.com/nodejs/node/pull/31178
test-crypto-dh-stateless: SKIP
test-crypto-keygen: SKIP
# https://github.com/nodejs/node/issues/33796
test-fs-stream-construct: PASS,FLAKY
[$system==solaris] # Also applies to SmartOS

View File

@ -0,0 +1,32 @@
'use strict';
const common = require('../common');
const fs = require('fs');
const assert = require('assert');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
{
// Compat error.
function ReadStream(...args) {
fs.ReadStream.call(this, ...args);
}
Object.setPrototypeOf(ReadStream.prototype, fs.ReadStream.prototype);
Object.setPrototypeOf(ReadStream, fs.ReadStream);
ReadStream.prototype.open = common.mustCall(function ReadStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, (err, fd) => {
that.emit('error', err);
});
});
const r = new ReadStream('/doesnotexist', { emitClose: true })
.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOENT');
assert.strictEqual(r.destroyed, true);
r.on('close', common.mustCall());
}));
}

View File

@ -0,0 +1,50 @@
'use strict';
const common = require('../common');
const fs = require('fs');
const assert = require('assert');
const debuglog = (arg) => {
console.log(new Date().toLocaleString(), arg);
};
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
{
// Compat error.
debuglog('start test');
function WriteStream(...args) {
debuglog('WriteStream constructor');
fs.WriteStream.call(this, ...args);
}
Object.setPrototypeOf(WriteStream.prototype, fs.WriteStream.prototype);
Object.setPrototypeOf(WriteStream, fs.WriteStream);
WriteStream.prototype.open = common.mustCall(function WriteStream$open() {
debuglog('WriteStream open() callback');
const that = this;
fs.open(that.path, that.flags, that.mode, (err, fd) => {
debuglog('inner fs open() callback');
that.emit('error', err);
});
});
fs.open(`${tmpdir.path}/dummy`, 'wx+', common.mustCall((err, fd) => {
debuglog('fs open() callback');
assert.ifError(err);
fs.close(fd, () => { debuglog(`closed ${fd}`); });
const w = new WriteStream(`${tmpdir.path}/dummy`,
{ flags: 'wx+', emitClose: true })
.on('error', common.mustCall((err) => {
debuglog('error event callback');
assert.strictEqual(err.code, 'EEXIST');
w.destroy();
w.on('close', common.mustCall(() => {
debuglog('close event callback');
}));
}));
}));
debuglog('waiting for callbacks');
}

View File

@ -0,0 +1,70 @@
'use strict';
const common = require('../common');
const fs = require('fs');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
{
// Compat with graceful-fs.
function ReadStream(...args) {
fs.ReadStream.call(this, ...args);
}
Object.setPrototypeOf(ReadStream.prototype, fs.ReadStream.prototype);
Object.setPrototypeOf(ReadStream, fs.ReadStream);
ReadStream.prototype.open = common.mustCall(function ReadStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, (err, fd) => {
if (err) {
if (that.autoClose)
that.destroy();
that.emit('error', err);
} else {
that.fd = fd;
that.emit('open', fd);
that.read();
}
});
});
const r = new ReadStream(fixtures.path('x.txt'))
.on('open', common.mustCall((fd) => {
assert.strictEqual(fd, r.fd);
r.destroy();
}));
}
{
// Compat with graceful-fs.
function WriteStream(...args) {
fs.WriteStream.call(this, ...args);
}
Object.setPrototypeOf(WriteStream.prototype, fs.WriteStream.prototype);
Object.setPrototypeOf(WriteStream, fs.WriteStream);
WriteStream.prototype.open = common.mustCall(function WriteStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, function(err, fd) {
if (err) {
that.destroy();
that.emit('error', err);
} else {
that.fd = fd;
that.emit('open', fd);
}
});
});
const w = new WriteStream(`${tmpdir.path}/dummy`)
.on('open', common.mustCall((fd) => {
assert.strictEqual(fd, w.fd);
w.destroy();
}));
}

View File

@ -0,0 +1,97 @@
'use strict';
const common = require('../common');
const fs = require('fs');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
{
// Compat with old node.
function ReadStream(...args) {
fs.ReadStream.call(this, ...args);
}
Object.setPrototypeOf(ReadStream.prototype, fs.ReadStream.prototype);
Object.setPrototypeOf(ReadStream, fs.ReadStream);
ReadStream.prototype.open = common.mustCall(function() {
fs.open(this.path, this.flags, this.mode, (er, fd) => {
if (er) {
if (this.autoClose) {
this.destroy();
}
this.emit('error', er);
return;
}
this.fd = fd;
this.emit('open', fd);
this.emit('ready');
});
});
let readyCalled = false;
let ticked = false;
const r = new ReadStream(fixtures.path('x.txt'))
.on('ready', common.mustCall(() => {
readyCalled = true;
// Make sure 'ready' is emitted in same tick as 'open'.
assert.strictEqual(ticked, false);
}))
.on('error', common.mustNotCall())
.on('open', common.mustCall((fd) => {
process.nextTick(() => {
ticked = true;
r.destroy();
});
assert.strictEqual(readyCalled, false);
assert.strictEqual(fd, r.fd);
}));
}
{
// Compat with old node.
function WriteStream(...args) {
fs.WriteStream.call(this, ...args);
}
Object.setPrototypeOf(WriteStream.prototype, fs.WriteStream.prototype);
Object.setPrototypeOf(WriteStream, fs.WriteStream);
WriteStream.prototype.open = common.mustCall(function() {
fs.open(this.path, this.flags, this.mode, (er, fd) => {
if (er) {
if (this.autoClose) {
this.destroy();
}
this.emit('error', er);
return;
}
this.fd = fd;
this.emit('open', fd);
this.emit('ready');
});
});
let readyCalled = false;
let ticked = false;
const w = new WriteStream(`${tmpdir.path}/dummy`)
.on('ready', common.mustCall(() => {
readyCalled = true;
// Make sure 'ready' is emitted in same tick as 'open'.
assert.strictEqual(ticked, false);
}))
.on('error', common.mustNotCall())
.on('open', common.mustCall((fd) => {
process.nextTick(() => {
ticked = true;
w.destroy();
});
assert.strictEqual(readyCalled, false);
assert.strictEqual(fd, w.fd);
}));
}

View File

@ -1,212 +0,0 @@
'use strict';
const common = require('../common');
const fs = require('fs');
const assert = require('assert');
const fixtures = require('../common/fixtures');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const examplePath = fixtures.path('x.txt');
{
// Compat with old node.
function ReadStream(...args) {
fs.ReadStream.call(this, ...args);
}
Object.setPrototypeOf(ReadStream.prototype, fs.ReadStream.prototype);
Object.setPrototypeOf(ReadStream, fs.ReadStream);
ReadStream.prototype.open = common.mustCall(function() {
fs.open(this.path, this.flags, this.mode, (er, fd) => {
if (er) {
if (this.autoClose) {
this.destroy();
}
this.emit('error', er);
return;
}
this.fd = fd;
this.emit('open', fd);
this.emit('ready');
});
});
let readyCalled = false;
let ticked = false;
const r = new ReadStream(examplePath)
.on('ready', common.mustCall(() => {
readyCalled = true;
// Make sure 'ready' is emitted in same tick as 'open'.
assert.strictEqual(ticked, false);
}))
.on('error', common.mustNotCall())
.on('open', common.mustCall((fd) => {
process.nextTick(() => {
ticked = true;
r.destroy();
});
assert.strictEqual(readyCalled, false);
assert.strictEqual(fd, r.fd);
}));
}
{
// Compat with old node.
function WriteStream(...args) {
fs.WriteStream.call(this, ...args);
}
Object.setPrototypeOf(WriteStream.prototype, fs.WriteStream.prototype);
Object.setPrototypeOf(WriteStream, fs.WriteStream);
WriteStream.prototype.open = common.mustCall(function() {
fs.open(this.path, this.flags, this.mode, (er, fd) => {
if (er) {
if (this.autoClose) {
this.destroy();
}
this.emit('error', er);
return;
}
this.fd = fd;
this.emit('open', fd);
this.emit('ready');
});
});
let readyCalled = false;
let ticked = false;
const w = new WriteStream(`${tmpdir.path}/dummy`)
.on('ready', common.mustCall(() => {
readyCalled = true;
// Make sure 'ready' is emitted in same tick as 'open'.
assert.strictEqual(ticked, false);
}))
.on('error', common.mustNotCall())
.on('open', common.mustCall((fd) => {
process.nextTick(() => {
ticked = true;
w.destroy();
});
assert.strictEqual(readyCalled, false);
assert.strictEqual(fd, w.fd);
}));
}
{
// Compat with graceful-fs.
function ReadStream(...args) {
fs.ReadStream.call(this, ...args);
}
Object.setPrototypeOf(ReadStream.prototype, fs.ReadStream.prototype);
Object.setPrototypeOf(ReadStream, fs.ReadStream);
ReadStream.prototype.open = common.mustCall(function ReadStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, (err, fd) => {
if (err) {
if (that.autoClose)
that.destroy();
that.emit('error', err);
} else {
that.fd = fd;
that.emit('open', fd);
that.read();
}
});
});
const r = new ReadStream(examplePath)
.on('open', common.mustCall((fd) => {
assert.strictEqual(fd, r.fd);
r.destroy();
}));
}
{
// Compat with graceful-fs.
function WriteStream(...args) {
fs.WriteStream.call(this, ...args);
}
Object.setPrototypeOf(WriteStream.prototype, fs.WriteStream.prototype);
Object.setPrototypeOf(WriteStream, fs.WriteStream);
WriteStream.prototype.open = common.mustCall(function WriteStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, function(err, fd) {
if (err) {
that.destroy();
that.emit('error', err);
} else {
that.fd = fd;
that.emit('open', fd);
}
});
});
const w = new WriteStream(`${tmpdir.path}/dummy2`)
.on('open', common.mustCall((fd) => {
assert.strictEqual(fd, w.fd);
w.destroy();
}));
}
{
// Compat error.
function ReadStream(...args) {
fs.ReadStream.call(this, ...args);
}
Object.setPrototypeOf(ReadStream.prototype, fs.ReadStream.prototype);
Object.setPrototypeOf(ReadStream, fs.ReadStream);
ReadStream.prototype.open = common.mustCall(function ReadStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, (err, fd) => {
that.emit('error', err);
});
});
const r = new ReadStream('/doesnotexist', { emitClose: true })
.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ENOENT');
assert.strictEqual(r.destroyed, true);
r.on('close', common.mustCall());
}));
}
{
// Compat error.
function WriteStream(...args) {
fs.WriteStream.call(this, ...args);
}
Object.setPrototypeOf(WriteStream.prototype, fs.WriteStream.prototype);
Object.setPrototypeOf(WriteStream, fs.WriteStream);
WriteStream.prototype.open = common.mustCall(function WriteStream$open() {
const that = this;
fs.open(that.path, that.flags, that.mode, (err, fd) => {
that.emit('error', err);
});
});
fs.open(`${tmpdir.path}/dummy3`, 'wx+', common.mustCall((err) => {
assert(!err);
const w = new WriteStream(`${tmpdir.path}/dummy3`,
{ flags: 'wx+', emitClose: true })
.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'EEXIST');
w.destroy();
w.on('close', common.mustCall());
}));
}));
}