• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Covers TCPWRAP and related TCPCONNECTWRAP
2'use strict';
3
4const common = require('../common');
5if (!common.hasIPv6)
6  common.skip('IPv6 support required');
7
8const assert = require('assert');
9const tick = require('../common/tick');
10const initHooks = require('./init-hooks');
11const { checkInvocations } = require('./hook-checks');
12const net = require('net');
13
14let tcp1, tcp2;
15let tcpserver;
16let tcpconnect;
17
18const hooks = initHooks();
19hooks.enable();
20
21const server = net
22  .createServer(common.mustCall(onconnection))
23  .on('listening', common.mustCall(onlistening));
24
25// Calling server.listen creates a TCPWRAP synchronously
26{
27  server.listen(0);
28  const tcpsservers = hooks.activitiesOfTypes('TCPSERVERWRAP');
29  const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
30  assert.strictEqual(tcpsservers.length, 1);
31  assert.strictEqual(tcpconnects.length, 0);
32  tcpserver = tcpsservers[0];
33  assert.strictEqual(tcpserver.type, 'TCPSERVERWRAP');
34  assert.strictEqual(typeof tcpserver.uid, 'number');
35  assert.strictEqual(typeof tcpserver.triggerAsyncId, 'number');
36  checkInvocations(tcpserver, { init: 1 }, 'when calling server.listen');
37}
38
39// Calling net.connect creates another TCPWRAP synchronously
40{
41  net.connect(
42    { port: server.address().port, host: '::1' },
43    common.mustCall(onconnected));
44  const tcps = hooks.activitiesOfTypes('TCPWRAP');
45  assert.strictEqual(tcps.length, 1);
46  process.nextTick(() => {
47    const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
48    assert.strictEqual(tcpconnects.length, 1);
49  });
50
51  tcp1 = tcps[0];
52  assert.strictEqual(tcps.length, 1);
53  assert.strictEqual(tcp1.type, 'TCPWRAP');
54  assert.strictEqual(typeof tcp1.uid, 'number');
55  assert.strictEqual(typeof tcp1.triggerAsyncId, 'number');
56
57  checkInvocations(tcpserver, { init: 1 },
58                   'tcpserver when client is connecting');
59  checkInvocations(tcp1, { init: 1 }, 'tcp1 when client is connecting');
60}
61
62function onlistening() {
63  assert.strictEqual(hooks.activitiesOfTypes('TCPWRAP').length, 1);
64}
65
66// Depending on timing we see client: onconnected or server: onconnection first
67// Therefore we can't depend on any ordering, but when we see a connection for
68// the first time we assign the tcpconnectwrap.
69function ontcpConnection(serverConnection) {
70  if (tcpconnect != null) {
71    // When client receives connection first ('onconnected') and the server
72    // second then we see an 'after' here, otherwise not
73    const expected = serverConnection ?
74      { init: 1, before: 1, after: 1 } :
75      { init: 1, before: 1 };
76    checkInvocations(
77      tcpconnect, expected,
78      'tcpconnect: when both client and server received connection');
79    return;
80  }
81
82  // Only focusing on TCPCONNECTWRAP here
83  const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
84  assert.strictEqual(tcpconnects.length, 1);
85  tcpconnect = tcpconnects[0];
86  assert.strictEqual(tcpconnect.type, 'TCPCONNECTWRAP');
87  assert.strictEqual(typeof tcpconnect.uid, 'number');
88  assert.strictEqual(typeof tcpconnect.triggerAsyncId, 'number');
89  // When client receives connection first ('onconnected'), we 'before' has
90  // been invoked at this point already, otherwise it only was 'init'ed
91  const expected = serverConnection ? { init: 1 } : { init: 1, before: 1 };
92  checkInvocations(tcpconnect, expected,
93                   'tcpconnect: when tcp connection is established');
94}
95
96let serverConnected = false;
97function onconnected() {
98  ontcpConnection(false);
99  // In the case that the client connects before the server TCPWRAP 'before'
100  // and 'after' weren't invoked yet. Also @see ontcpConnection.
101  const expected = serverConnected ?
102    { init: 1, before: 1, after: 1 } :
103    { init: 1 };
104  checkInvocations(tcpserver, expected, 'tcpserver when client connects');
105  checkInvocations(tcp1, { init: 1 }, 'tcp1 when client connects');
106}
107
108function onconnection(c) {
109  serverConnected = true;
110  ontcpConnection(true);
111
112  const tcps = hooks.activitiesOfTypes([ 'TCPWRAP' ]);
113  const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP');
114  assert.strictEqual(tcps.length, 2);
115  assert.strictEqual(tcpconnects.length, 1);
116  tcp2 = tcps[1];
117  assert.strictEqual(tcp2.type, 'TCPWRAP');
118  assert.strictEqual(typeof tcp2.uid, 'number');
119  assert.strictEqual(typeof tcp2.triggerAsyncId, 'number');
120
121  checkInvocations(tcpserver, { init: 1, before: 1 },
122                   'tcpserver when server receives connection');
123  checkInvocations(tcp1, { init: 1 }, 'tcp1 when server receives connection');
124  checkInvocations(tcp2, { init: 1 }, 'tcp2 when server receives connection');
125
126  c.end();
127  this.close(common.mustCall(onserverClosed));
128}
129
130function onserverClosed() {
131  setImmediate(() => {
132    checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 },
133                     'tcpserver when server is closed');
134    checkInvocations(tcp1, { init: 1, before: 2, after: 2, destroy: 1 },
135                     'tcp1 after server is closed');
136  });
137  checkInvocations(tcp2, { init: 1, before: 1, after: 1 },
138                   'tcp2 synchronously when server is closed');
139
140  tick(2, () => {
141    checkInvocations(tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
142                     'tcp2 when server is closed');
143    checkInvocations(tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 },
144                     'tcpconnect when server is closed');
145  });
146}
147
148process.on('exit', onexit);
149
150function onexit() {
151  hooks.disable();
152  hooks.sanityCheck([ 'TCPWRAP', 'TCPSERVERWRAP', 'TCPCONNECTWRAP' ]);
153
154  checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 },
155                   'tcpserver when process exits');
156  checkInvocations(
157    tcp1, { init: 1, before: 2, after: 2, destroy: 1 },
158    'tcp1 when process exits');
159  checkInvocations(
160    tcp2, { init: 1, before: 2, after: 2, destroy: 1 },
161    'tcp2 when process exits');
162  checkInvocations(
163    tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 },
164    'tcpconnect when process exits');
165}
166