| // Copyright Joyent, Inc. and other Node contributors. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the |
| // "Software"), to deal in the Software without restriction, including |
| // without limitation the rights to use, copy, modify, merge, publish, |
| // distribute, sublicense, and/or sell copies of the Software, and to permit |
| // persons to whom the Software is furnished to do so, subject to the |
| // following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included |
| // in all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| 'use strict'; |
| const common = require('../common'); |
| const assert = require('assert'); |
| const fork = require('child_process').fork; |
| const net = require('net'); |
| const debug = require('util').debuglog('test'); |
| |
| const Countdown = require('../common/countdown'); |
| |
| if (process.argv[2] === 'child') { |
| |
| let serverScope; |
| |
| // TODO(@jasnell): The message event is not called consistently |
| // across platforms. Need to investigate if it can be made |
| // more consistent. |
| const onServer = (msg, server) => { |
| if (msg.what !== 'server') return; |
| process.removeListener('message', onServer); |
| |
| serverScope = server; |
| |
| // TODO(@jasnell): This is apparently not called consistently |
| // across platforms. Need to investigate if it can be made |
| // more consistent. |
| server.on('connection', (socket) => { |
| debug('CHILD: got connection'); |
| process.send({ what: 'connection' }); |
| socket.destroy(); |
| }); |
| |
| // Start making connection from parent. |
| debug('CHILD: server listening'); |
| process.send({ what: 'listening' }); |
| }; |
| |
| process.on('message', onServer); |
| |
| // TODO(@jasnell): The close event is not called consistently |
| // across platforms. Need to investigate if it can be made |
| // more consistent. |
| const onClose = (msg) => { |
| if (msg.what !== 'close') return; |
| process.removeListener('message', onClose); |
| |
| serverScope.on('close', common.mustCall(() => { |
| process.send({ what: 'close' }); |
| })); |
| serverScope.close(); |
| }; |
| |
| process.on('message', onClose); |
| |
| process.send({ what: 'ready' }); |
| } else { |
| |
| const child = fork(process.argv[1], ['child']); |
| |
| child.on('exit', common.mustCall((code, signal) => { |
| const message = `CHILD: died with ${code}, ${signal}`; |
| assert.strictEqual(code, 0, message); |
| })); |
| |
| // Send net.Server to child and test by connecting. |
| function testServer(callback) { |
| |
| // Destroy server execute callback when done. |
| const countdown = new Countdown(2, () => { |
| server.on('close', common.mustCall(() => { |
| debug('PARENT: server closed'); |
| child.send({ what: 'close' }); |
| })); |
| server.close(); |
| }); |
| |
| // We expect 4 connections and close events. |
| const connections = new Countdown(4, () => countdown.dec()); |
| const closed = new Countdown(4, () => countdown.dec()); |
| |
| // Create server and send it to child. |
| const server = net.createServer(); |
| |
| // TODO(@jasnell): The specific number of times the connection |
| // event is emitted appears to be variable across platforms. |
| // Need to investigate why and whether it can be made |
| // more consistent. |
| server.on('connection', (socket) => { |
| debug('PARENT: got connection'); |
| socket.destroy(); |
| connections.dec(); |
| }); |
| |
| server.on('listening', common.mustCall(() => { |
| debug('PARENT: server listening'); |
| child.send({ what: 'server' }, server); |
| })); |
| server.listen(0); |
| |
| // Handle client messages. |
| // TODO(@jasnell): The specific number of times the message |
| // event is emitted appears to be variable across platforms. |
| // Need to investigate why and whether it can be made |
| // more consistent. |
| const messageHandlers = (msg) => { |
| if (msg.what === 'listening') { |
| // Make connections. |
| let socket; |
| for (let i = 0; i < 4; i++) { |
| socket = net.connect(server.address().port, common.mustCall(() => { |
| debug('CLIENT: connected'); |
| })); |
| socket.on('close', common.mustCall(() => { |
| closed.dec(); |
| debug('CLIENT: closed'); |
| })); |
| } |
| |
| } else if (msg.what === 'connection') { |
| // Child got connection |
| connections.dec(); |
| } else if (msg.what === 'close') { |
| child.removeListener('message', messageHandlers); |
| callback(); |
| } |
| }; |
| |
| child.on('message', messageHandlers); |
| } |
| |
| const onReady = common.mustCall((msg) => { |
| if (msg.what !== 'ready') return; |
| child.removeListener('message', onReady); |
| testServer(common.mustCall()); |
| }); |
| |
| // Create server and send it to child. |
| child.on('message', onReady); |
| } |