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_ci
251cb0ef41Sopenharmony_ciconst assert = require('node:assert');
261cb0ef41Sopenharmony_ciconst cluster = require('node:cluster');
271cb0ef41Sopenharmony_ciconst { spawnSync } = require('node:child_process');
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciassert.strictEqual('NODE_UNIQUE_ID' in process.env, false,
301cb0ef41Sopenharmony_ci                   `NODE_UNIQUE_ID (${process.env.NODE_UNIQUE_ID}) ` +
311cb0ef41Sopenharmony_ci                   'should be removed on startup');
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci{
341cb0ef41Sopenharmony_ci  const { status } = spawnSync(process.execPath, [
351cb0ef41Sopenharmony_ci    '-e',
361cb0ef41Sopenharmony_ci    `
371cb0ef41Sopenharmony_ci      const { strictEqual } = require('node:assert');
381cb0ef41Sopenharmony_ci      Object.setPrototypeOf(process.env, { NODE_UNIQUE_ID: 0 });
391cb0ef41Sopenharmony_ci      strictEqual(require('cluster').isPrimary, true);
401cb0ef41Sopenharmony_ci    `,
411cb0ef41Sopenharmony_ci  ]);
421cb0ef41Sopenharmony_ci  assert.strictEqual(status, 0);
431cb0ef41Sopenharmony_ci}
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_cifunction forEach(obj, fn) {
461cb0ef41Sopenharmony_ci  Object.keys(obj).forEach((name, index) => {
471cb0ef41Sopenharmony_ci    fn(obj[name], name, index);
481cb0ef41Sopenharmony_ci  });
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciif (cluster.isWorker) {
531cb0ef41Sopenharmony_ci  require('http').Server(common.mustNotCall()).listen(0, '127.0.0.1');
541cb0ef41Sopenharmony_ci} else if (cluster.isPrimary) {
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  const checks = {
571cb0ef41Sopenharmony_ci    cluster: {
581cb0ef41Sopenharmony_ci      events: {
591cb0ef41Sopenharmony_ci        fork: false,
601cb0ef41Sopenharmony_ci        online: false,
611cb0ef41Sopenharmony_ci        listening: false,
621cb0ef41Sopenharmony_ci        exit: false
631cb0ef41Sopenharmony_ci      },
641cb0ef41Sopenharmony_ci      equal: {
651cb0ef41Sopenharmony_ci        fork: false,
661cb0ef41Sopenharmony_ci        online: false,
671cb0ef41Sopenharmony_ci        listening: false,
681cb0ef41Sopenharmony_ci        exit: false
691cb0ef41Sopenharmony_ci      }
701cb0ef41Sopenharmony_ci    },
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci    worker: {
731cb0ef41Sopenharmony_ci      events: {
741cb0ef41Sopenharmony_ci        online: false,
751cb0ef41Sopenharmony_ci        listening: false,
761cb0ef41Sopenharmony_ci        exit: false
771cb0ef41Sopenharmony_ci      },
781cb0ef41Sopenharmony_ci      equal: {
791cb0ef41Sopenharmony_ci        online: false,
801cb0ef41Sopenharmony_ci        listening: false,
811cb0ef41Sopenharmony_ci        exit: false
821cb0ef41Sopenharmony_ci      },
831cb0ef41Sopenharmony_ci      states: {
841cb0ef41Sopenharmony_ci        none: false,
851cb0ef41Sopenharmony_ci        online: false,
861cb0ef41Sopenharmony_ci        listening: false,
871cb0ef41Sopenharmony_ci        dead: false
881cb0ef41Sopenharmony_ci      }
891cb0ef41Sopenharmony_ci    }
901cb0ef41Sopenharmony_ci  };
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  const stateNames = Object.keys(checks.worker.states);
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  // Check events, states, and emit arguments
951cb0ef41Sopenharmony_ci  forEach(checks.cluster.events, (bool, name, index) => {
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci    // Listen on event
981cb0ef41Sopenharmony_ci    cluster.on(name, common.mustCall(function(/* worker */) {
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci      // Set event
1011cb0ef41Sopenharmony_ci      checks.cluster.events[name] = true;
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci      // Check argument
1041cb0ef41Sopenharmony_ci      checks.cluster.equal[name] = worker === arguments[0];
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci      // Check state
1071cb0ef41Sopenharmony_ci      const state = stateNames[index];
1081cb0ef41Sopenharmony_ci      checks.worker.states[state] = (state === worker.state);
1091cb0ef41Sopenharmony_ci    }));
1101cb0ef41Sopenharmony_ci  });
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  // Kill worker when listening
1131cb0ef41Sopenharmony_ci  cluster.on('listening', common.mustCall(() => {
1141cb0ef41Sopenharmony_ci    worker.kill();
1151cb0ef41Sopenharmony_ci  }));
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  // Kill process when worker is killed
1181cb0ef41Sopenharmony_ci  cluster.on('exit', common.mustCall());
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  // Create worker
1211cb0ef41Sopenharmony_ci  const worker = cluster.fork();
1221cb0ef41Sopenharmony_ci  assert.strictEqual(worker.id, 1);
1231cb0ef41Sopenharmony_ci  assert(worker instanceof cluster.Worker,
1241cb0ef41Sopenharmony_ci         'the worker is not a instance of the Worker constructor');
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  // Check event
1271cb0ef41Sopenharmony_ci  forEach(checks.worker.events, function(bool, name, index) {
1281cb0ef41Sopenharmony_ci    worker.on(name, common.mustCall(function() {
1291cb0ef41Sopenharmony_ci      // Set event
1301cb0ef41Sopenharmony_ci      checks.worker.events[name] = true;
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci      // Check argument
1331cb0ef41Sopenharmony_ci      checks.worker.equal[name] = (worker === this);
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci      switch (name) {
1361cb0ef41Sopenharmony_ci        case 'exit':
1371cb0ef41Sopenharmony_ci          assert.strictEqual(arguments[0], worker.process.exitCode);
1381cb0ef41Sopenharmony_ci          assert.strictEqual(arguments[1], worker.process.signalCode);
1391cb0ef41Sopenharmony_ci          assert.strictEqual(arguments.length, 2);
1401cb0ef41Sopenharmony_ci          break;
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci        case 'listening': {
1431cb0ef41Sopenharmony_ci          assert.strictEqual(arguments.length, 1);
1441cb0ef41Sopenharmony_ci          assert.strictEqual(Object.keys(arguments[0]).length, 4);
1451cb0ef41Sopenharmony_ci          assert.strictEqual(arguments[0].address, '127.0.0.1');
1461cb0ef41Sopenharmony_ci          assert.strictEqual(arguments[0].addressType, 4);
1471cb0ef41Sopenharmony_ci          assert(Object.hasOwn(arguments[0], 'fd'));
1481cb0ef41Sopenharmony_ci          assert.strictEqual(arguments[0].fd, undefined);
1491cb0ef41Sopenharmony_ci          const port = arguments[0].port;
1501cb0ef41Sopenharmony_ci          assert(Number.isInteger(port));
1511cb0ef41Sopenharmony_ci          assert(port >= 1);
1521cb0ef41Sopenharmony_ci          assert(port <= 65535);
1531cb0ef41Sopenharmony_ci          break;
1541cb0ef41Sopenharmony_ci        }
1551cb0ef41Sopenharmony_ci        default:
1561cb0ef41Sopenharmony_ci          assert.strictEqual(arguments.length, 0);
1571cb0ef41Sopenharmony_ci          break;
1581cb0ef41Sopenharmony_ci      }
1591cb0ef41Sopenharmony_ci    }));
1601cb0ef41Sopenharmony_ci  });
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  // Check all values
1631cb0ef41Sopenharmony_ci  process.once('exit', () => {
1641cb0ef41Sopenharmony_ci    // Check cluster events
1651cb0ef41Sopenharmony_ci    forEach(checks.cluster.events, (check, name) => {
1661cb0ef41Sopenharmony_ci      assert(check,
1671cb0ef41Sopenharmony_ci             `The cluster event "${name}" on the cluster object did not fire`);
1681cb0ef41Sopenharmony_ci    });
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    // Check cluster event arguments
1711cb0ef41Sopenharmony_ci    forEach(checks.cluster.equal, (check, name) => {
1721cb0ef41Sopenharmony_ci      assert(check,
1731cb0ef41Sopenharmony_ci             `The cluster event "${name}" did not emit with correct argument`);
1741cb0ef41Sopenharmony_ci    });
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    // Check worker states
1771cb0ef41Sopenharmony_ci    forEach(checks.worker.states, (check, name) => {
1781cb0ef41Sopenharmony_ci      assert(check,
1791cb0ef41Sopenharmony_ci             `The worker state "${name}" was not set to true`);
1801cb0ef41Sopenharmony_ci    });
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci    // Check worker events
1831cb0ef41Sopenharmony_ci    forEach(checks.worker.events, (check, name) => {
1841cb0ef41Sopenharmony_ci      assert(check,
1851cb0ef41Sopenharmony_ci             `The worker event "${name}" on the worker object did not fire`);
1861cb0ef41Sopenharmony_ci    });
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_ci    // Check worker event arguments
1891cb0ef41Sopenharmony_ci    forEach(checks.worker.equal, (check, name) => {
1901cb0ef41Sopenharmony_ci      assert(check,
1911cb0ef41Sopenharmony_ci             `The worker event "${name}" did not emit with correct argument`);
1921cb0ef41Sopenharmony_ci    });
1931cb0ef41Sopenharmony_ci  });
1941cb0ef41Sopenharmony_ci
1951cb0ef41Sopenharmony_ci}
196