Skip to content

Commit

Permalink
fs,net: emitting ready for fs streams and network sockets in addition…
Browse files Browse the repository at this point in the history
… to the event names they currently use.

Currently, various internal streams have different events that indicate that the
underlying resource has successfully been established. This commit adds ready event
for fs and net sockets to standardize on emitting ready for all of these streams.

Fixes: nodejs#19304
  • Loading branch information
sameer-coder committed Mar 17, 2018
1 parent 197fbbe commit 204d89d
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1984,6 +1984,7 @@ ReadStream.prototype.open = function() {

self.fd = fd;
self.emit('open', fd);
self.emit('ready', fd);
// start the flow of data.
self.read();
});
Expand Down Expand Up @@ -2141,6 +2142,7 @@ WriteStream.prototype.open = function() {

this.fd = fd;
this.emit('open', fd);
this.emit('ready', fd);
});
};

Expand Down
1 change: 1 addition & 0 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,7 @@ function afterConnect(status, handle, req, readable, writable) {
self._unrefTimer();

self.emit('connect');
self.emit('ready');

// start the first read, or get an immediate EOF.
// this doesn't actually consume any bytes, because len=0.
Expand Down
219 changes: 219 additions & 0 deletions test/parallel/test-fs-ready-event-stream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
'use strict';
const common = require('../common');

const assert = require('assert');
const fs = require('fs');
const fixtures = require('../common/fixtures');

const fn = fixtures.path('elipses.txt');
const rangeFile = fixtures.path('x.txt');

{
let paused = false;
let bytesRead = 0;

const file = fs.ReadStream(fn);
const fileSize = fs.statSync(fn).size;

assert.strictEqual(file.bytesRead, 0);

file.on('ready', common.mustCall(function(fd) {
file.length = 0;
assert.strictEqual('number', typeof fd);
assert.strictEqual(file.bytesRead, 0);
assert.ok(file.readable);

// GH-535
file.pause();
file.resume();
file.pause();
file.resume();
}));

file.on('data', function(data) {
assert.ok(data instanceof Buffer);
assert.ok(!paused);
file.length += data.length;

bytesRead += data.length;
assert.strictEqual(file.bytesRead, bytesRead);

paused = true;
file.pause();

setTimeout(function() {
paused = false;
file.resume();
}, 10);
});


file.on('end', common.mustCall(function(chunk) {
assert.strictEqual(bytesRead, fileSize);
assert.strictEqual(file.bytesRead, fileSize);
}));


file.on('close', common.mustCall(function() {
assert.strictEqual(bytesRead, fileSize);
assert.strictEqual(file.bytesRead, fileSize);
}));

process.on('exit', function() {
assert.strictEqual(file.length, 30000);
});
}

{
const file = fs.createReadStream(fn, { encoding: 'utf8' });
file.length = 0;
file.on('data', function(data) {
assert.strictEqual('string', typeof data);
file.length += data.length;

for (let i = 0; i < data.length; i++) {
// http://www.fileformat.info/info/unicode/char/2026/index.htm
assert.strictEqual('\u2026', data[i]);
}
});

file.on('close', common.mustCall());

process.on('exit', function() {
assert.strictEqual(file.length, 10000);
});
}

{
const file =
fs.createReadStream(rangeFile, { bufferSize: 1, start: 1, end: 2 });
let contentRead = '';
file.on('data', function(data) {
contentRead += data.toString('utf-8');
});
file.on('end', common.mustCall(function(data) {
assert.strictEqual(contentRead, 'yz');
}));
}

{
const file = fs.createReadStream(rangeFile, { bufferSize: 1, start: 1 });
file.data = '';
file.on('data', function(data) {
file.data += data.toString('utf-8');
});
file.on('end', common.mustCall(function() {
assert.strictEqual(file.data, 'yz\n');
}));
}

{
// Ref: https://github.com/nodejs/node-v0.x-archive/issues/2320
const file = fs.createReadStream(rangeFile, { bufferSize: 1.23, start: 1 });
file.data = '';
file.on('data', function(data) {
file.data += data.toString('utf-8');
});
file.on('end', common.mustCall(function() {
assert.strictEqual(file.data, 'yz\n');
}));
}

common.expectsError(
() => {
fs.createReadStream(rangeFile, { start: 10, end: 2 });
},
{
code: 'ERR_OUT_OF_RANGE',
message: 'The value of "start" is out of range. It must be <= "end". ' +
'Received {start: 10, end: 2}',
type: RangeError
});

{
const stream = fs.createReadStream(rangeFile, { start: 0, end: 0 });
stream.data = '';

stream.on('data', function(chunk) {
stream.data += chunk;
});

stream.on('end', common.mustCall(function() {
assert.strictEqual('x', stream.data);
}));
}

{
// Verify that end works when start is not specified.
const stream = new fs.createReadStream(rangeFile, { end: 1 });
stream.data = '';

stream.on('data', function(chunk) {
stream.data += chunk;
});

stream.on('end', common.mustCall(function() {
assert.strictEqual('xy', stream.data);
}));
}

{
// pause and then resume immediately.
const pauseRes = fs.createReadStream(rangeFile);
pauseRes.pause();
pauseRes.resume();
}

{
let file = fs.createReadStream(rangeFile, { autoClose: false });
let data = '';
file.on('data', function(chunk) { data += chunk; });
file.on('end', common.mustCall(function() {
assert.strictEqual(data, 'xyz\n');
process.nextTick(function() {
assert(!file.closed);
assert(!file.destroyed);
fileNext();
});
}));

function fileNext() {
// This will tell us if the fd is usable again or not.
file = fs.createReadStream(null, { fd: file.fd, start: 0 });
file.data = '';
file.on('data', function(data) {
file.data += data;
});
file.on('end', common.mustCall(function(err) {
assert.strictEqual(file.data, 'xyz\n');
}));
process.on('exit', function() {
assert(file.closed);
assert(file.destroyed);
});
}
}

{
// Just to make sure autoClose won't close the stream because of error.
const file = fs.createReadStream(null, { fd: 13337, autoClose: false });
file.on('data', common.mustNotCall());
file.on('error', common.mustCall());
process.on('exit', function() {
assert(!file.closed);
assert(!file.destroyed);
assert(file.fd);
});
}

{
// Make sure stream is destroyed when file does not exist.
const file = fs.createReadStream('/path/to/file/that/does/not/exist');
file.on('data', common.mustNotCall());
file.on('error', common.mustCall());

process.on('exit', function() {
assert(!file.closed);
assert(file.destroyed);
});
}
20 changes: 20 additions & 0 deletions test/parallel/test-net-socket-ready-without-cb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';
const common = require('../common');

// This test ensures that socket.connect can be called without callback
// which is optional.

const net = require('net');

const server = net.createServer(common.mustCall(function(conn) {
conn.end();
server.close();
})).listen(0, common.mustCall(function() {
const client = new net.Socket();

client.on('ready', common.mustCall(function() {
client.end();
}));

client.connect(server.address());
}));

0 comments on commit 204d89d

Please sign in to comment.