| // Covers TCPWRAP and related TCPCONNECTWRAP |
| 'use strict'; |
| |
| const common = require('../common'); |
| if (!common.hasIPv6) |
| common.skip('IPv6 support required'); |
| |
| const assert = require('assert'); |
| const tick = require('../common/tick'); |
| const initHooks = require('./init-hooks'); |
| const { checkInvocations } = require('./hook-checks'); |
| const net = require('net'); |
| |
| let tcp1, tcp2; |
| let tcpserver; |
| let tcpconnect; |
| |
| const hooks = initHooks(); |
| hooks.enable(); |
| |
| const server = net |
| .createServer(common.mustCall(onconnection)) |
| .on('listening', common.mustCall(onlistening)); |
| |
| // Calling server.listen creates a TCPWRAP synchronously |
| { |
| server.listen(0); |
| const tcpsservers = hooks.activitiesOfTypes('TCPSERVERWRAP'); |
| const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP'); |
| assert.strictEqual(tcpsservers.length, 1); |
| assert.strictEqual(tcpconnects.length, 0); |
| tcpserver = tcpsservers[0]; |
| assert.strictEqual(tcpserver.type, 'TCPSERVERWRAP'); |
| assert.strictEqual(typeof tcpserver.uid, 'number'); |
| assert.strictEqual(typeof tcpserver.triggerAsyncId, 'number'); |
| checkInvocations(tcpserver, { init: 1 }, 'when calling server.listen'); |
| } |
| |
| // Calling net.connect creates another TCPWRAP synchronously |
| { |
| net.connect( |
| { port: server.address().port, host: '::1' }, |
| common.mustCall(onconnected)); |
| const tcps = hooks.activitiesOfTypes('TCPWRAP'); |
| assert.strictEqual(tcps.length, 1); |
| process.nextTick(() => { |
| const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP'); |
| assert.strictEqual(tcpconnects.length, 1); |
| }); |
| |
| tcp1 = tcps[0]; |
| assert.strictEqual(tcps.length, 1); |
| assert.strictEqual(tcp1.type, 'TCPWRAP'); |
| assert.strictEqual(typeof tcp1.uid, 'number'); |
| assert.strictEqual(typeof tcp1.triggerAsyncId, 'number'); |
| |
| checkInvocations(tcpserver, { init: 1 }, |
| 'tcpserver when client is connecting'); |
| checkInvocations(tcp1, { init: 1 }, 'tcp1 when client is connecting'); |
| } |
| |
| function onlistening() { |
| assert.strictEqual(hooks.activitiesOfTypes('TCPWRAP').length, 1); |
| } |
| |
| // Depending on timing we see client: onconnected or server: onconnection first |
| // Therefore we can't depend on any ordering, but when we see a connection for |
| // the first time we assign the tcpconnectwrap. |
| function ontcpConnection(serverConnection) { |
| if (tcpconnect != null) { |
| // When client receives connection first ('onconnected') and the server |
| // second then we see an 'after' here, otherwise not |
| const expected = serverConnection ? |
| { init: 1, before: 1, after: 1 } : |
| { init: 1, before: 1 }; |
| checkInvocations( |
| tcpconnect, expected, |
| 'tcpconnect: when both client and server received connection'); |
| return; |
| } |
| |
| // Only focusing on TCPCONNECTWRAP here |
| const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP'); |
| assert.strictEqual(tcpconnects.length, 1); |
| tcpconnect = tcpconnects[0]; |
| assert.strictEqual(tcpconnect.type, 'TCPCONNECTWRAP'); |
| assert.strictEqual(typeof tcpconnect.uid, 'number'); |
| assert.strictEqual(typeof tcpconnect.triggerAsyncId, 'number'); |
| // When client receives connection first ('onconnected'), we 'before' has |
| // been invoked at this point already, otherwise it only was 'init'ed |
| const expected = serverConnection ? { init: 1 } : { init: 1, before: 1 }; |
| checkInvocations(tcpconnect, expected, |
| 'tcpconnect: when tcp connection is established'); |
| } |
| |
| let serverConnected = false; |
| function onconnected() { |
| ontcpConnection(false); |
| // In the case that the client connects before the server TCPWRAP 'before' |
| // and 'after' weren't invoked yet. Also @see ontcpConnection. |
| const expected = serverConnected ? |
| { init: 1, before: 1, after: 1 } : |
| { init: 1 }; |
| checkInvocations(tcpserver, expected, 'tcpserver when client connects'); |
| checkInvocations(tcp1, { init: 1 }, 'tcp1 when client connects'); |
| } |
| |
| function onconnection(c) { |
| serverConnected = true; |
| ontcpConnection(true); |
| |
| const tcps = hooks.activitiesOfTypes([ 'TCPWRAP' ]); |
| const tcpconnects = hooks.activitiesOfTypes('TCPCONNECTWRAP'); |
| assert.strictEqual(tcps.length, 2); |
| assert.strictEqual(tcpconnects.length, 1); |
| tcp2 = tcps[1]; |
| assert.strictEqual(tcp2.type, 'TCPWRAP'); |
| assert.strictEqual(typeof tcp2.uid, 'number'); |
| assert.strictEqual(typeof tcp2.triggerAsyncId, 'number'); |
| |
| checkInvocations(tcpserver, { init: 1, before: 1 }, |
| 'tcpserver when server receives connection'); |
| checkInvocations(tcp1, { init: 1 }, 'tcp1 when server receives connection'); |
| checkInvocations(tcp2, { init: 1 }, 'tcp2 when server receives connection'); |
| |
| c.end(); |
| this.close(common.mustCall(onserverClosed)); |
| } |
| |
| function onserverClosed() { |
| checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 }, |
| 'tcpserver when server is closed'); |
| setImmediate(() => { |
| checkInvocations(tcp1, { init: 1, before: 2, after: 2, destroy: 1 }, |
| 'tcp1 after server is closed'); |
| }); |
| checkInvocations(tcp2, { init: 1, before: 1, after: 1 }, |
| 'tcp2 synchronously when server is closed'); |
| |
| tick(2, () => { |
| checkInvocations(tcp2, { init: 1, before: 2, after: 2, destroy: 1 }, |
| 'tcp2 when server is closed'); |
| checkInvocations(tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 }, |
| 'tcpconnect when server is closed'); |
| }); |
| } |
| |
| process.on('exit', onexit); |
| |
| function onexit() { |
| hooks.disable(); |
| hooks.sanityCheck([ 'TCPWRAP', 'TCPSERVERWRAP', 'TCPCONNECTWRAP' ]); |
| |
| checkInvocations(tcpserver, { init: 1, before: 1, after: 1, destroy: 1 }, |
| 'tcpserver when process exits'); |
| checkInvocations( |
| tcp1, { init: 1, before: 2, after: 2, destroy: 1 }, |
| 'tcp1 when process exits'); |
| checkInvocations( |
| tcp2, { init: 1, before: 2, after: 2, destroy: 1 }, |
| 'tcp2 when process exits'); |
| checkInvocations( |
| tcpconnect, { init: 1, before: 1, after: 1, destroy: 1 }, |
| 'tcpconnect when process exits'); |
| } |