2
2
3
3
// Testcase to check reporting of uv handles.
4
4
const common = require ( '../common' ) ;
5
+ const tmpdir = require ( '../common/tmpdir' ) ;
6
+ const path = require ( 'path' ) ;
5
7
if ( common . isIBMi )
6
8
common . skip ( 'IBMi does not support fs.watch()' ) ;
7
9
8
- if ( process . argv [ 2 ] === 'child' ) {
9
- // Exit on loss of parent process
10
- const exit = ( ) => process . exit ( 2 ) ;
11
- process . on ( 'disconnect' , exit ) ;
12
-
10
+ function createFsHandle ( childData ) {
13
11
const fs = require ( 'fs' ) ;
14
- const http = require ( 'http' ) ;
15
- const spawn = require ( 'child_process' ) . spawn ;
16
-
17
12
// Watching files should result in fs_event/fs_poll uv handles.
18
13
let watcher ;
19
14
try {
@@ -22,54 +17,127 @@ if (process.argv[2] === 'child') {
22
17
// fs.watch() unavailable
23
18
}
24
19
fs . watchFile ( __filename , ( ) => { } ) ;
20
+ childData . skip_fs_watch = watcher === undefined ;
21
+
22
+ return ( ) => {
23
+ if ( watcher ) watcher . close ( ) ;
24
+ fs . unwatchFile ( __filename ) ;
25
+ } ;
26
+ }
25
27
28
+ function createChildProcessHandle ( childData ) {
29
+ const spawn = require ( 'child_process' ) . spawn ;
26
30
// Child should exist when this returns as child_process.pid must be set.
27
- const child_process = spawn ( process . execPath ,
28
- [ '-e' , "process.stdin.on('data', (x) => " +
29
- 'console.log(x.toString()));' ] ) ;
31
+ const cp = spawn ( process . execPath ,
32
+ [ '-e' , "process.stdin.on('data', (x) => " +
33
+ 'console.log(x.toString()));' ] ) ;
34
+ childData . pid = cp . pid ;
35
+
36
+ return ( ) => {
37
+ cp . kill ( ) ;
38
+ } ;
39
+ }
30
40
41
+ function createTimerHandle ( ) {
31
42
const timeout = setInterval ( ( ) => { } , 1000 ) ;
32
43
// Make sure the timer doesn't keep the test alive and let
33
44
// us check we detect unref'd handles correctly.
34
45
timeout . unref ( ) ;
46
+ return ( ) => {
47
+ clearInterval ( timeout ) ;
48
+ } ;
49
+ }
50
+
51
+ function createTcpHandle ( childData ) {
52
+ const http = require ( 'http' ) ;
53
+
54
+ return new Promise ( ( resolve ) => {
55
+ // Simple server/connection to create tcp uv handles.
56
+ const server = http . createServer ( ( req , res ) => {
57
+ req . on ( 'end' , ( ) => {
58
+ resolve ( ( ) => {
59
+ res . writeHead ( 200 , { 'Content-Type' : 'text/plain' } ) ;
60
+ res . end ( ) ;
61
+ server . close ( ) ;
62
+ } ) ;
63
+ } ) ;
64
+ req . resume ( ) ;
65
+ } ) ;
66
+ server . listen ( ( ) => {
67
+ childData . tcp_address = server . address ( ) ;
68
+ http . get ( { port : server . address ( ) . port } ) ;
69
+ } ) ;
70
+ } ) ;
71
+ }
35
72
73
+ function createUdpHandle ( childData ) {
36
74
// Datagram socket for udp uv handles.
37
75
const dgram = require ( 'dgram' ) ;
38
- const udp_socket = dgram . createSocket ( 'udp4' ) ;
39
- const connected_udp_socket = dgram . createSocket ( 'udp4' ) ;
40
- udp_socket . bind ( { } , common . mustCall ( ( ) => {
41
- connected_udp_socket . connect ( udp_socket . address ( ) . port ) ;
42
- } ) ) ;
76
+ const udpSocket = dgram . createSocket ( 'udp4' ) ;
77
+ const connectedUdpSocket = dgram . createSocket ( 'udp4' ) ;
78
+
79
+ return new Promise ( ( resolve ) => {
80
+ udpSocket . bind ( { } , common . mustCall ( ( ) => {
81
+ connectedUdpSocket . connect ( udpSocket . address ( ) . port ) ;
43
82
44
- // Simple server/connection to create tcp uv handles.
45
- const server = http . createServer ( ( req , res ) => {
46
- req . on ( 'end' , ( ) => {
47
- // Generate the report while the connection is active.
48
- console . log ( JSON . stringify ( process . report . getReport ( ) , null , 2 ) ) ;
49
- child_process . kill ( ) ;
50
-
51
- res . writeHead ( 200 , { 'Content-Type' : 'text/plain' } ) ;
52
- res . end ( ) ;
53
-
54
- // Tidy up to allow process to exit cleanly.
55
- server . close ( ( ) => {
56
- if ( watcher ) watcher . close ( ) ;
57
- fs . unwatchFile ( __filename ) ;
58
- connected_udp_socket . close ( ) ;
59
- udp_socket . close ( ) ;
60
- process . removeListener ( 'disconnect' , exit ) ;
83
+ childData . udp_address = udpSocket . address ( ) ;
84
+ resolve ( ( ) => {
85
+ connectedUdpSocket . close ( ) ;
86
+ udpSocket . close ( ) ;
87
+ } ) ;
88
+ } ) ) ;
89
+ } ) ;
90
+ }
91
+
92
+ function createNamedPipeHandle ( childData ) {
93
+ const net = require ( 'net' ) ;
94
+ const fs = require ( 'fs' ) ;
95
+ fs . mkdirSync ( tmpdir . path , { recursive : true } ) ;
96
+ const sockPath = path . join ( tmpdir . path , 'test-report-uv-handles.sock' ) ;
97
+ return new Promise ( ( resolve ) => {
98
+ const server = net . createServer ( ( socket ) => {
99
+ childData . pipe_sock_path = server . address ( ) ;
100
+ resolve ( ( ) => {
101
+ socket . end ( ) ;
102
+ server . close ( ) ;
61
103
} ) ;
62
104
} ) ;
63
- req . resume ( ) ;
105
+ server . listen (
106
+ sockPath ,
107
+ ( ) => {
108
+ net . connect ( sockPath , ( socket ) => { } ) ;
109
+ } ) ;
64
110
} ) ;
65
- server . listen ( ( ) => {
66
- const data = { pid : child_process . pid ,
67
- tcp_address : server . address ( ) ,
68
- udp_address : udp_socket . address ( ) ,
69
- skip_fs_watch : ( watcher === undefined ) } ;
70
- process . send ( data ) ;
71
- http . get ( { port : server . address ( ) . port } ) ;
111
+ }
112
+
113
+ async function child ( ) {
114
+ // Exit on loss of parent process
115
+ const exit = ( ) => process . exit ( 2 ) ;
116
+ process . on ( 'disconnect' , exit ) ;
117
+
118
+ const childData = { } ;
119
+ const disposes = await Promise . all ( [
120
+ createFsHandle ( childData ) ,
121
+ createChildProcessHandle ( childData ) ,
122
+ createTimerHandle ( childData ) ,
123
+ createTcpHandle ( childData ) ,
124
+ createUdpHandle ( childData ) ,
125
+ createNamedPipeHandle ( childData ) ,
126
+ ] ) ;
127
+ process . send ( childData ) ;
128
+
129
+ // Generate the report while the connection is active.
130
+ console . log ( JSON . stringify ( process . report . getReport ( ) , null , 2 ) ) ;
131
+
132
+ // Tidy up to allow process to exit cleanly.
133
+ disposes . forEach ( ( it ) => {
134
+ it ( ) ;
72
135
} ) ;
136
+ process . removeListener ( 'disconnect' , exit ) ;
137
+ }
138
+
139
+ if ( process . argv [ 2 ] === 'child' ) {
140
+ child ( ) ;
73
141
} else {
74
142
const helper = require ( '../common/report.js' ) ;
75
143
const fork = require ( 'child_process' ) . fork ;
@@ -116,6 +184,7 @@ if (process.argv[2] === 'child') {
116
184
const expected_filename = `${ prefix } ${ __filename } ` ;
117
185
const found_tcp = [ ] ;
118
186
const found_udp = [ ] ;
187
+ const found_named_pipe = [ ] ;
119
188
// Functions are named to aid debugging when they are not called.
120
189
const validators = {
121
190
fs_event : common . mustCall ( function fs_event_validator ( handle ) {
@@ -133,6 +202,20 @@ if (process.argv[2] === 'child') {
133
202
} ) ,
134
203
pipe : common . mustCallAtLeast ( function pipe_validator ( handle ) {
135
204
assert ( handle . is_referenced ) ;
205
+ // Pipe handles. The report should contain three pipes:
206
+ // 1. The server's listening pipe.
207
+ // 2. The inbound pipe making the request.
208
+ // 3. The outbound pipe sending the response.
209
+ const sockPath = child_data . pipe_sock_path ;
210
+ if ( handle . localEndpointName === sockPath ) {
211
+ if ( handle . writable === false ) {
212
+ found_named_pipe . push ( 'listening' ) ;
213
+ } else {
214
+ found_named_pipe . push ( 'inbound' ) ;
215
+ }
216
+ } else if ( handle . remoteEndpointName === sockPath ) {
217
+ found_named_pipe . push ( 'outbound' ) ;
218
+ }
136
219
} ) ,
137
220
process : common . mustCall ( function process_validator ( handle ) {
138
221
assert . strictEqual ( handle . pid , child_data . pid ) ;
@@ -172,7 +255,7 @@ if (process.argv[2] === 'child') {
172
255
assert ( handle . is_referenced ) ;
173
256
} , 2 ) ,
174
257
} ;
175
- console . log ( report . libuv ) ;
258
+
176
259
for ( const entry of report . libuv ) {
177
260
if ( validators [ entry . type ] ) validators [ entry . type ] ( entry ) ;
178
261
}
@@ -182,6 +265,9 @@ if (process.argv[2] === 'child') {
182
265
for ( const socket of [ 'connected' , 'unconnected' ] ) {
183
266
assert ( found_udp . includes ( socket ) , `${ socket } UDP socket was not found` ) ;
184
267
}
268
+ for ( const socket of [ 'listening' , 'inbound' , 'outbound' ] ) {
269
+ assert ( found_named_pipe . includes ( socket ) , `${ socket } Named pipe socket was not found` ) ;
270
+ }
185
271
186
272
// Common report tests.
187
273
helper . validateContent ( stdout ) ;
0 commit comments