• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23const common = require('../common');
24const assert = require('assert');
25const fork = require('child_process').fork;
26const net = require('net');
27
28// child
29if (process.argv[2] === 'child') {
30
31  // Check that the 'disconnect' event is deferred to the next event loop tick.
32  const disconnect = process.disconnect;
33  process.disconnect = function() {
34    disconnect.apply(this, arguments);
35    // If the event is emitted synchronously, we're too late by now.
36    process.once('disconnect', common.mustCall(disconnectIsNotAsync));
37    // The funky function name makes it show up legible in mustCall errors.
38    function disconnectIsNotAsync() {}
39  };
40
41  const server = net.createServer();
42
43  server.on('connection', function(socket) {
44
45    socket.resume();
46
47    process.on('disconnect', function() {
48      socket.end((process.connected).toString());
49    });
50
51    // When the socket is closed, we will close the server
52    // allowing the process to self terminate
53    socket.on('end', function() {
54      server.close();
55    });
56
57    socket.write('ready');
58  });
59
60  // When the server is ready tell parent
61  server.on('listening', function() {
62    process.send({ msg: 'ready', port: server.address().port });
63  });
64
65  server.listen(0);
66
67} else {
68  // testcase
69  const child = fork(process.argv[1], ['child']);
70
71  let childFlag = false;
72  let parentFlag = false;
73
74  // When calling .disconnect the event should emit
75  // and the disconnected flag should be true.
76  child.on('disconnect', common.mustCall(function() {
77    parentFlag = child.connected;
78  }));
79
80  // The process should also self terminate without using signals
81  child.on('exit', common.mustCall());
82
83  // When child is listening
84  child.on('message', function(obj) {
85    if (obj && obj.msg === 'ready') {
86
87      // Connect to child using TCP to know if disconnect was emitted
88      const socket = net.connect(obj.port);
89
90      socket.on('data', function(data) {
91        data = data.toString();
92
93        // Ready to be disconnected
94        if (data === 'ready') {
95          child.disconnect();
96          assert.throws(
97            child.disconnect.bind(child),
98            {
99              code: 'ERR_IPC_DISCONNECTED'
100            });
101          return;
102        }
103
104        // 'disconnect' is emitted
105        childFlag = (data === 'true');
106      });
107
108    }
109  });
110
111  process.on('exit', function() {
112    assert.strictEqual(childFlag, false);
113    assert.strictEqual(parentFlag, false);
114  });
115}
116