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 {
241cb0ef41Sopenharmony_ci  mustCall,
251cb0ef41Sopenharmony_ci  mustCallAtLeast,
261cb0ef41Sopenharmony_ci  platformTimeout,
271cb0ef41Sopenharmony_ci} = require('../common');
281cb0ef41Sopenharmony_ciconst assert = require('assert');
291cb0ef41Sopenharmony_ciconst fork = require('child_process').fork;
301cb0ef41Sopenharmony_ciconst net = require('net');
311cb0ef41Sopenharmony_ciconst debug = require('util').debuglog('test');
321cb0ef41Sopenharmony_ciconst count = 12;
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciif (process.argv[2] === 'child') {
351cb0ef41Sopenharmony_ci  const needEnd = [];
361cb0ef41Sopenharmony_ci  const id = process.argv[3];
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  process.on('message', mustCall((m, socket) => {
391cb0ef41Sopenharmony_ci    if (!socket) return;
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci    debug(`[${id}] got socket ${m}`);
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci    // Will call .end('end') or .write('write');
441cb0ef41Sopenharmony_ci    socket[m](m);
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci    socket.resume();
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci    socket.on('data', mustCallAtLeast(() => {
491cb0ef41Sopenharmony_ci      debug(`[${id}] socket.data ${m}`);
501cb0ef41Sopenharmony_ci    }));
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci    socket.on('end', mustCall(() => {
531cb0ef41Sopenharmony_ci      debug(`[${id}] socket.end ${m}`);
541cb0ef41Sopenharmony_ci    }));
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    // Store the unfinished socket
571cb0ef41Sopenharmony_ci    if (m === 'write') {
581cb0ef41Sopenharmony_ci      needEnd.push(socket);
591cb0ef41Sopenharmony_ci    }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci    socket.on('close', mustCall((had_error) => {
621cb0ef41Sopenharmony_ci      debug(`[${id}] socket.close ${had_error} ${m}`);
631cb0ef41Sopenharmony_ci    }));
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci    socket.on('finish', mustCall(() => {
661cb0ef41Sopenharmony_ci      debug(`[${id}] socket finished ${m}`);
671cb0ef41Sopenharmony_ci    }));
681cb0ef41Sopenharmony_ci  }));
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  process.on('message', mustCall((m) => {
711cb0ef41Sopenharmony_ci    if (m !== 'close') return;
721cb0ef41Sopenharmony_ci    debug(`[${id}] got close message`);
731cb0ef41Sopenharmony_ci    needEnd.forEach((endMe, i) => {
741cb0ef41Sopenharmony_ci      debug(`[${id}] ending ${i}/${needEnd.length}`);
751cb0ef41Sopenharmony_ci      endMe.end('end');
761cb0ef41Sopenharmony_ci    });
771cb0ef41Sopenharmony_ci  }));
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  process.on('disconnect', mustCall(() => {
801cb0ef41Sopenharmony_ci    debug(`[${id}] process disconnect, ending`);
811cb0ef41Sopenharmony_ci    needEnd.forEach((endMe, i) => {
821cb0ef41Sopenharmony_ci      debug(`[${id}] ending ${i}/${needEnd.length}`);
831cb0ef41Sopenharmony_ci      endMe.end('end');
841cb0ef41Sopenharmony_ci    });
851cb0ef41Sopenharmony_ci  }));
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci} else {
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci  const child1 = fork(process.argv[1], ['child', '1']);
901cb0ef41Sopenharmony_ci  const child2 = fork(process.argv[1], ['child', '2']);
911cb0ef41Sopenharmony_ci  const child3 = fork(process.argv[1], ['child', '3']);
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  const server = net.createServer();
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  let connected = 0;
961cb0ef41Sopenharmony_ci  let closed = 0;
971cb0ef41Sopenharmony_ci  server.on('connection', function(socket) {
981cb0ef41Sopenharmony_ci    switch (connected % 6) {
991cb0ef41Sopenharmony_ci      case 0:
1001cb0ef41Sopenharmony_ci        child1.send('end', socket); break;
1011cb0ef41Sopenharmony_ci      case 1:
1021cb0ef41Sopenharmony_ci        child1.send('write', socket); break;
1031cb0ef41Sopenharmony_ci      case 2:
1041cb0ef41Sopenharmony_ci        child2.send('end', socket); break;
1051cb0ef41Sopenharmony_ci      case 3:
1061cb0ef41Sopenharmony_ci        child2.send('write', socket); break;
1071cb0ef41Sopenharmony_ci      case 4:
1081cb0ef41Sopenharmony_ci        child3.send('end', socket); break;
1091cb0ef41Sopenharmony_ci      case 5:
1101cb0ef41Sopenharmony_ci        child3.send('write', socket); break;
1111cb0ef41Sopenharmony_ci    }
1121cb0ef41Sopenharmony_ci    connected += 1;
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci    // TODO(@jasnell): This is not actually being called.
1151cb0ef41Sopenharmony_ci    // It is not clear if it is needed.
1161cb0ef41Sopenharmony_ci    socket.once('close', () => {
1171cb0ef41Sopenharmony_ci      debug(`[m] socket closed, total ${++closed}`);
1181cb0ef41Sopenharmony_ci    });
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci    if (connected === count) {
1211cb0ef41Sopenharmony_ci      closeServer();
1221cb0ef41Sopenharmony_ci    }
1231cb0ef41Sopenharmony_ci  });
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  let disconnected = 0;
1261cb0ef41Sopenharmony_ci  server.on('listening', mustCall(() => {
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci    let j = count;
1291cb0ef41Sopenharmony_ci    while (j--) {
1301cb0ef41Sopenharmony_ci      const client = net.connect(server.address().port, '127.0.0.1');
1311cb0ef41Sopenharmony_ci      client.on('error', () => {
1321cb0ef41Sopenharmony_ci        // This can happen if we kill the subprocess too early.
1331cb0ef41Sopenharmony_ci        // The client should still get a close event afterwards.
1341cb0ef41Sopenharmony_ci        // It likely won't so don't wrap in a mustCall.
1351cb0ef41Sopenharmony_ci        debug('[m] CLIENT: error event');
1361cb0ef41Sopenharmony_ci      });
1371cb0ef41Sopenharmony_ci      client.on('close', mustCall(() => {
1381cb0ef41Sopenharmony_ci        debug('[m] CLIENT: close event');
1391cb0ef41Sopenharmony_ci        disconnected += 1;
1401cb0ef41Sopenharmony_ci      }));
1411cb0ef41Sopenharmony_ci      client.resume();
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci  }));
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  let closeEmitted = false;
1461cb0ef41Sopenharmony_ci  server.on('close', mustCall(function() {
1471cb0ef41Sopenharmony_ci    closeEmitted = true;
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci    child1.kill();
1501cb0ef41Sopenharmony_ci    child2.kill();
1511cb0ef41Sopenharmony_ci    child3.kill();
1521cb0ef41Sopenharmony_ci  }));
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  server.listen(0, '127.0.0.1');
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  function closeServer() {
1571cb0ef41Sopenharmony_ci    server.close();
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci    setTimeout(() => {
1601cb0ef41Sopenharmony_ci      assert(!closeEmitted);
1611cb0ef41Sopenharmony_ci      child1.send('close');
1621cb0ef41Sopenharmony_ci      child2.send('close');
1631cb0ef41Sopenharmony_ci      child3.disconnect();
1641cb0ef41Sopenharmony_ci    }, platformTimeout(200));
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  process.on('exit', function() {
1681cb0ef41Sopenharmony_ci    assert.strictEqual(server._workers.length, 0);
1691cb0ef41Sopenharmony_ci    assert.strictEqual(disconnected, count);
1701cb0ef41Sopenharmony_ci    assert.strictEqual(connected, count);
1711cb0ef41Sopenharmony_ci  });
1721cb0ef41Sopenharmony_ci}
173