• 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 cluster = require('cluster');
26const net = require('net');
27
28function forEach(obj, fn) {
29  Object.keys(obj).forEach(function(name, index) {
30    fn(obj[name], name);
31  });
32}
33
34if (cluster.isWorker) {
35  // Create a tcp server. This will be used as cluster-shared-server and as an
36  // alternative IPC channel.
37  const server = net.Server();
38  let socket, message;
39
40  function maybeReply() {
41    if (!socket || !message) return;
42
43    // Tell master using TCP socket that a message is received.
44    socket.write(JSON.stringify({
45      code: 'received message',
46      echo: message
47    }));
48  }
49
50  server.on('connection', function(socket_) {
51    socket = socket_;
52    maybeReply();
53
54    // Send a message back over the IPC channel.
55    process.send('message from worker');
56  });
57
58  process.on('message', function(message_) {
59    message = message_;
60    maybeReply();
61  });
62
63  server.listen(0, '127.0.0.1');
64} else if (cluster.isMaster) {
65
66  const checks = {
67    global: {
68      'receive': false,
69      'correct': false
70    },
71    master: {
72      'receive': false,
73      'correct': false
74    },
75    worker: {
76      'receive': false,
77      'correct': false
78    }
79  };
80
81
82  let client;
83  const check = (type, result) => {
84    checks[type].receive = true;
85    checks[type].correct = result;
86    console.error('check', checks);
87
88    let missing = false;
89    forEach(checks, function(type) {
90      if (type.receive === false) missing = true;
91    });
92
93    if (missing === false) {
94      console.error('end client');
95      client.end();
96    }
97  };
98
99  // Spawn worker
100  const worker = cluster.fork();
101
102  // When a IPC message is received from the worker
103  worker.on('message', function(message) {
104    check('master', message === 'message from worker');
105  });
106  cluster.on('message', function(worker_, message) {
107    assert.strictEqual(worker_, worker);
108    check('global', message === 'message from worker');
109  });
110
111  // When a TCP server is listening in the worker connect to it
112  worker.on('listening', function(address) {
113
114    client = net.connect(address.port, function() {
115      // Send message to worker.
116      worker.send('message from master');
117    });
118
119    client.on('data', function(data) {
120      // All data is JSON
121      data = JSON.parse(data.toString());
122
123      if (data.code === 'received message') {
124        check('worker', data.echo === 'message from master');
125      } else {
126        throw new Error(`wrong TCP message received: ${data}`);
127      }
128    });
129
130    // When the connection ends kill worker and shutdown process
131    client.on('end', function() {
132      worker.kill();
133    });
134
135    worker.on('exit', common.mustCall(function() {
136      process.exit(0);
137    }));
138  });
139
140  process.once('exit', function() {
141    forEach(checks, function(check, type) {
142      assert.ok(check.receive, `The ${type} did not receive any message`);
143      assert.ok(check.correct, `The ${type} did not get the correct message`);
144    });
145  });
146}
147