11cb0ef41Sopenharmony_ci// Covers TCPWRAP and related TCPCONNECTWRAP
21cb0ef41Sopenharmony_ci'use strict';
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst common = require('../common');
51cb0ef41Sopenharmony_ciif (!common.hasIPv6)
61cb0ef41Sopenharmony_ci  common.skip('IPv6 support required');
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ciconst assert = require('assert');
91cb0ef41Sopenharmony_ciconst tick = require('../common/tick');
101cb0ef41Sopenharmony_ciconst initHooks = require('./init-hooks');
111cb0ef41Sopenharmony_ciconst { checkInvocations } = require('./hook-checks');
121cb0ef41Sopenharmony_ciconst net = require('net');
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cilet tcp1, tcp2;
151cb0ef41Sopenharmony_cilet tcpserver;
161cb0ef41Sopenharmony_cilet tcpconnect;
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciconst hooks = initHooks();
191cb0ef41Sopenharmony_cihooks.enable();
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciconst server = net
221cb0ef41Sopenharmony_ci  .createServer(common.mustCall(onconnection))
231cb0ef41Sopenharmony_ci  .on('listening', common.mustCall(onlistening));
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// Calling server.listen creates a TCPWRAP synchronously
261cb0ef41Sopenharmony_ci{
271cb0ef41Sopenharmony_ci  server.listen(0);
281cb0ef41Sopenharmony_ci  const tcpsservers = hooks.activitiesOfTypes('TCPSERVERWRAP');
291cb0ef41Sopenharmony_ci  const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
301cb0ef41Sopenharmony_ci  assert.strictEqual(tcpsservers.length, 1);
311cb0ef41Sopenharmony_ci  assert.strictEqual(tcpconnects.length, 0);
321cb0ef41Sopenharmony_ci  tcpserver = tcpsservers[0];
331cb0ef41Sopenharmony_ci  assert.strictEqual(tcpserver.type, 'TCPSERVERWRAP');
341cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcpserver.uid, 'number');
351cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcpserver.triggerAsyncId, 'number');
361cb0ef41Sopenharmony_ci  checkInvocations(tcpserver, { init: 1 }, 'when calling server.listen');
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci// Calling net.connect creates another TCPWRAP synchronously
401cb0ef41Sopenharmony_ci{
411cb0ef41Sopenharmony_ci  net.connect(
421cb0ef41Sopenharmony_ci    { port: server.address().port, host: '::1' },
431cb0ef41Sopenharmony_ci    common.mustCall(onconnected));
441cb0ef41Sopenharmony_ci  const tcps = hooks.activitiesOfTypes('TCPWRAP');
451cb0ef41Sopenharmony_ci  assert.strictEqual(tcps.length, 1);
461cb0ef41Sopenharmony_ci  process.nextTick(() => {
471cb0ef41Sopenharmony_ci    const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
481cb0ef41Sopenharmony_ci    assert.strictEqual(tcpconnects.length, 1);
491cb0ef41Sopenharmony_ci  });
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  tcp1 = tcps[0];
521cb0ef41Sopenharmony_ci  assert.strictEqual(tcps.length, 1);
531cb0ef41Sopenharmony_ci  assert.strictEqual(tcp1.type, 'TCPWRAP');
541cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcp1.uid, 'number');
551cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcp1.triggerAsyncId, 'number');
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  checkInvocations(tcpserver, { init: 1 },
581cb0ef41Sopenharmony_ci                   'tcpserver when client is connecting');
591cb0ef41Sopenharmony_ci  checkInvocations(tcp1, { init: 1 }, 'tcp1 when client is connecting');
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_cifunction onlistening() {
631cb0ef41Sopenharmony_ci  assert.strictEqual(hooks.activitiesOfTypes('TCPWRAP').length, 1);
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci// Depending on timing we see client: onconnected or server: onconnection first
671cb0ef41Sopenharmony_ci// Therefore we can't depend on any ordering, but when we see a connection for
681cb0ef41Sopenharmony_ci// the first time we assign the tcpconnectwrap.
691cb0ef41Sopenharmony_cifunction ontcpConnection(serverConnection) {
701cb0ef41Sopenharmony_ci  if (tcpconnect != null) {
711cb0ef41Sopenharmony_ci    // When client receives connection first ('onconnected') and the server
721cb0ef41Sopenharmony_ci    // second then we see an 'after' here, otherwise not
731cb0ef41Sopenharmony_ci    const expected = serverConnection ?
741cb0ef41Sopenharmony_ci      { init: 1, before: 1, after: 1 } :
751cb0ef41Sopenharmony_ci      { init: 1, before: 1 };
761cb0ef41Sopenharmony_ci    checkInvocations(
771cb0ef41Sopenharmony_ci      tcpconnect, expected,
781cb0ef41Sopenharmony_ci      'tcpconnect: when both client and server received connection');
791cb0ef41Sopenharmony_ci    return;
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  // Only focusing on TCPCONNECTWRAP here
831cb0ef41Sopenharmony_ci  const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
841cb0ef41Sopenharmony_ci  assert.strictEqual(tcpconnects.length, 1);
851cb0ef41Sopenharmony_ci  tcpconnect = tcpconnects[0];
861cb0ef41Sopenharmony_ci  assert.strictEqual(tcpconnect.type, 'TCPCONNECTWRAP');
871cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcpconnect.uid, 'number');
881cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcpconnect.triggerAsyncId, 'number');
891cb0ef41Sopenharmony_ci  // When client receives connection first ('onconnected'), we 'before' has
901cb0ef41Sopenharmony_ci  // been invoked at this point already, otherwise it only was 'init'ed
911cb0ef41Sopenharmony_ci  const expected = serverConnection ? { init: 1 } : { init: 1, before: 1 };
921cb0ef41Sopenharmony_ci  checkInvocations(tcpconnect, expected,
931cb0ef41Sopenharmony_ci                   'tcpconnect: when tcp connection is established');
941cb0ef41Sopenharmony_ci}
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_cilet serverConnected = false;
971cb0ef41Sopenharmony_cifunction onconnected() {
981cb0ef41Sopenharmony_ci  ontcpConnection(false);
991cb0ef41Sopenharmony_ci  // In the case that the client connects before the server TCPWRAP 'before'
1001cb0ef41Sopenharmony_ci  // and 'after' weren't invoked yet. Also @see ontcpConnection.
1011cb0ef41Sopenharmony_ci  const expected = serverConnected ?
1021cb0ef41Sopenharmony_ci    { init: 1, before: 1, after: 1 } :
1031cb0ef41Sopenharmony_ci    { init: 1 };
1041cb0ef41Sopenharmony_ci  checkInvocations(tcpserver, expected, 'tcpserver when client connects');
1051cb0ef41Sopenharmony_ci  checkInvocations(tcp1, { init: 1 }, 'tcp1 when client connects');
1061cb0ef41Sopenharmony_ci}
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_cifunction onconnection(c) {
1091cb0ef41Sopenharmony_ci  serverConnected = true;
1101cb0ef41Sopenharmony_ci  ontcpConnection(true);
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  const tcps = hooks.activitiesOfTypes([ 'TCPWRAP' ]);
1131cb0ef41Sopenharmony_ci  const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
1141cb0ef41Sopenharmony_ci  assert.strictEqual(tcps.length, 2);
1151cb0ef41Sopenharmony_ci  assert.strictEqual(tcpconnects.length, 1);
1161cb0ef41Sopenharmony_ci  tcp2 = tcps[1];
1171cb0ef41Sopenharmony_ci  assert.strictEqual(tcp2.type, 'TCPWRAP');
1181cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcp2.uid, 'number');
1191cb0ef41Sopenharmony_ci  assert.strictEqual(typeof tcp2.triggerAsyncId, 'number');
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  checkInvocations(tcpserver, { init: 1, before: 1 },
1221cb0ef41Sopenharmony_ci                   'tcpserver when server receives connection');
1231cb0ef41Sopenharmony_ci  checkInvocations(tcp1, { init: 1 }, 'tcp1 when server receives connection');
1241cb0ef41Sopenharmony_ci  checkInvocations(tcp2, { init: 1 }, 'tcp2 when server receives connection');
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  c.end();
1271cb0ef41Sopenharmony_ci  this.close(common.mustCall(onserverClosed));
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_cifunction onserverClosed() {
1311cb0ef41Sopenharmony_ci  setImmediate(() => {
1321cb0ef41Sopenharmony_ci    checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 },
1331cb0ef41Sopenharmony_ci                     'tcpserver when server is closed');
1341cb0ef41Sopenharmony_ci    checkInvocations(tcp1, { init: 1, before: 2, after: 2, destroy: 1 },
1351cb0ef41Sopenharmony_ci                     'tcp1 after server is closed');
1361cb0ef41Sopenharmony_ci  });
1371cb0ef41Sopenharmony_ci  checkInvocations(tcp2, { init: 1, before: 1, after: 1 },
1381cb0ef41Sopenharmony_ci                   'tcp2 synchronously when server is closed');
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  tick(2, () => {
1411cb0ef41Sopenharmony_ci    checkInvocations(tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
1421cb0ef41Sopenharmony_ci                     'tcp2 when server is closed');
1431cb0ef41Sopenharmony_ci    checkInvocations(tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 },
1441cb0ef41Sopenharmony_ci                     'tcpconnect when server is closed');
1451cb0ef41Sopenharmony_ci  });
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ciprocess.on('exit', onexit);
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_cifunction onexit() {
1511cb0ef41Sopenharmony_ci  hooks.disable();
1521cb0ef41Sopenharmony_ci  hooks.sanityCheck([ 'TCPWRAP', 'TCPSERVERWRAP', 'TCPCONNECTWRAP' ]);
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 },
1551cb0ef41Sopenharmony_ci                   'tcpserver when process exits');
1561cb0ef41Sopenharmony_ci  checkInvocations(
1571cb0ef41Sopenharmony_ci    tcp1, { init: 1, before: 2, after: 2, destroy: 1 },
1581cb0ef41Sopenharmony_ci    'tcp1 when process exits');
1591cb0ef41Sopenharmony_ci  checkInvocations(
1601cb0ef41Sopenharmony_ci    tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
1611cb0ef41Sopenharmony_ci    'tcp2 when process exits');
1621cb0ef41Sopenharmony_ci  checkInvocations(
1631cb0ef41Sopenharmony_ci    tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 },
1641cb0ef41Sopenharmony_ci    'tcpconnect when process exits');
1651cb0ef41Sopenharmony_ci}
166