11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors.
21cb0ef41Sopenharmony_ci//
31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a
41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the
51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including
61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish,
71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit
81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the
91cb0ef41Sopenharmony_ci// following conditions:
101cb0ef41Sopenharmony_ci//
111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included
121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE.
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci'use strict';
231cb0ef41Sopenharmony_ciconst common = require('../common');
241cb0ef41Sopenharmony_ciconst assert = require('assert');
251cb0ef41Sopenharmony_ciconst fork = require('child_process').fork;
261cb0ef41Sopenharmony_ciconst net = require('net');
271cb0ef41Sopenharmony_ciconst debug = require('util').debuglog('test');
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciconst Countdown = require('../common/countdown');
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciif (process.argv[2] === 'child') {
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  let serverScope;
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  // TODO(@jasnell): The message event is not called consistently
361cb0ef41Sopenharmony_ci  // across platforms. Need to investigate if it can be made
371cb0ef41Sopenharmony_ci  // more consistent.
381cb0ef41Sopenharmony_ci  const onServer = (msg, server) => {
391cb0ef41Sopenharmony_ci    if (msg.what !== 'server') return;
401cb0ef41Sopenharmony_ci    process.removeListener('message', onServer);
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci    serverScope = server;
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci    // TODO(@jasnell): This is apparently not called consistently
451cb0ef41Sopenharmony_ci    // across platforms. Need to investigate if it can be made
461cb0ef41Sopenharmony_ci    // more consistent.
471cb0ef41Sopenharmony_ci    server.on('connection', (socket) => {
481cb0ef41Sopenharmony_ci      debug('CHILD: got connection');
491cb0ef41Sopenharmony_ci      process.send({ what: 'connection' });
501cb0ef41Sopenharmony_ci      socket.destroy();
511cb0ef41Sopenharmony_ci    });
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci    // Start making connection from parent.
541cb0ef41Sopenharmony_ci    debug('CHILD: server listening');
551cb0ef41Sopenharmony_ci    process.send({ what: 'listening' });
561cb0ef41Sopenharmony_ci  };
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  process.on('message', onServer);
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci  // TODO(@jasnell): The close event is not called consistently
611cb0ef41Sopenharmony_ci  // across platforms. Need to investigate if it can be made
621cb0ef41Sopenharmony_ci  // more consistent.
631cb0ef41Sopenharmony_ci  const onClose = (msg) => {
641cb0ef41Sopenharmony_ci    if (msg.what !== 'close') return;
651cb0ef41Sopenharmony_ci    process.removeListener('message', onClose);
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    serverScope.on('close', common.mustCall(() => {
681cb0ef41Sopenharmony_ci      process.send({ what: 'close' });
691cb0ef41Sopenharmony_ci    }));
701cb0ef41Sopenharmony_ci    serverScope.close();
711cb0ef41Sopenharmony_ci  };
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  process.on('message', onClose);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  process.send({ what: 'ready' });
761cb0ef41Sopenharmony_ci} else {
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  const child = fork(process.argv[1], ['child']);
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  child.on('exit', common.mustCall((code, signal) => {
811cb0ef41Sopenharmony_ci    const message = `CHILD: died with ${code}, ${signal}`;
821cb0ef41Sopenharmony_ci    assert.strictEqual(code, 0, message);
831cb0ef41Sopenharmony_ci  }));
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci  // Send net.Server to child and test by connecting.
861cb0ef41Sopenharmony_ci  function testServer(callback) {
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci    // Destroy server execute callback when done.
891cb0ef41Sopenharmony_ci    const countdown = new Countdown(2, () => {
901cb0ef41Sopenharmony_ci      server.on('close', common.mustCall(() => {
911cb0ef41Sopenharmony_ci        debug('PARENT: server closed');
921cb0ef41Sopenharmony_ci        child.send({ what: 'close' });
931cb0ef41Sopenharmony_ci      }));
941cb0ef41Sopenharmony_ci      server.close();
951cb0ef41Sopenharmony_ci    });
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci    // We expect 4 connections and close events.
981cb0ef41Sopenharmony_ci    const connections = new Countdown(4, () => countdown.dec());
991cb0ef41Sopenharmony_ci    const closed = new Countdown(4, () => countdown.dec());
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci    // Create server and send it to child.
1021cb0ef41Sopenharmony_ci    const server = net.createServer();
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    // TODO(@jasnell): The specific number of times the connection
1051cb0ef41Sopenharmony_ci    // event is emitted appears to be variable across platforms.
1061cb0ef41Sopenharmony_ci    // Need to investigate why and whether it can be made
1071cb0ef41Sopenharmony_ci    // more consistent.
1081cb0ef41Sopenharmony_ci    server.on('connection', (socket) => {
1091cb0ef41Sopenharmony_ci      debug('PARENT: got connection');
1101cb0ef41Sopenharmony_ci      socket.destroy();
1111cb0ef41Sopenharmony_ci      connections.dec();
1121cb0ef41Sopenharmony_ci    });
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci    server.on('listening', common.mustCall(() => {
1151cb0ef41Sopenharmony_ci      debug('PARENT: server listening');
1161cb0ef41Sopenharmony_ci      child.send({ what: 'server' }, server);
1171cb0ef41Sopenharmony_ci    }));
1181cb0ef41Sopenharmony_ci    server.listen(0);
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    // Handle client messages.
1211cb0ef41Sopenharmony_ci    // TODO(@jasnell): The specific number of times the message
1221cb0ef41Sopenharmony_ci    // event is emitted appears to be variable across platforms.
1231cb0ef41Sopenharmony_ci    // Need to investigate why and whether it can be made
1241cb0ef41Sopenharmony_ci    // more consistent.
1251cb0ef41Sopenharmony_ci    const messageHandlers = (msg) => {
1261cb0ef41Sopenharmony_ci      if (msg.what === 'listening') {
1271cb0ef41Sopenharmony_ci        // Make connections.
1281cb0ef41Sopenharmony_ci        let socket;
1291cb0ef41Sopenharmony_ci        for (let i = 0; i < 4; i++) {
1301cb0ef41Sopenharmony_ci          socket = net.connect(server.address().port, common.mustCall(() => {
1311cb0ef41Sopenharmony_ci            debug('CLIENT: connected');
1321cb0ef41Sopenharmony_ci          }));
1331cb0ef41Sopenharmony_ci          socket.on('close', common.mustCall(() => {
1341cb0ef41Sopenharmony_ci            closed.dec();
1351cb0ef41Sopenharmony_ci            debug('CLIENT: closed');
1361cb0ef41Sopenharmony_ci          }));
1371cb0ef41Sopenharmony_ci        }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci      } else if (msg.what === 'connection') {
1401cb0ef41Sopenharmony_ci        // Child got connection
1411cb0ef41Sopenharmony_ci        connections.dec();
1421cb0ef41Sopenharmony_ci      } else if (msg.what === 'close') {
1431cb0ef41Sopenharmony_ci        child.removeListener('message', messageHandlers);
1441cb0ef41Sopenharmony_ci        callback();
1451cb0ef41Sopenharmony_ci      }
1461cb0ef41Sopenharmony_ci    };
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci    child.on('message', messageHandlers);
1491cb0ef41Sopenharmony_ci  }
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  const onReady = common.mustCall((msg) => {
1521cb0ef41Sopenharmony_ci    if (msg.what !== 'ready') return;
1531cb0ef41Sopenharmony_ci    child.removeListener('message', onReady);
1541cb0ef41Sopenharmony_ci    testServer(common.mustCall());
1551cb0ef41Sopenharmony_ci  });
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  // Create server and send it to child.
1581cb0ef41Sopenharmony_ci  child.on('message', onReady);
1591cb0ef41Sopenharmony_ci}
160