| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ba96f14 commit 61c95f0
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -82,6 +82,42 @@ static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) { | |||
| 82 | 82 | ReportEndpoint(h, rc == 0 ? addr : nullptr, "remoteEndpoint", writer); | |
| 83 | 83 | } | |
| 84 | 84 | ||
| 85 | + // Utility function to format libuv pipe information. | ||
| 86 | + static void ReportPipeEndpoints(uv_handle_t* h, JSONWriter* writer) { | ||
| 87 | + uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h); | ||
| 88 | + MallocedBuffer<char> buffer(0); | ||
| 89 | + size_t buffer_size = 0; | ||
| 90 | + int rc = -1; | ||
| 91 | + | ||
| 92 | + // First call to get required buffer size. | ||
| 93 | + rc = uv_pipe_getsockname(&handle->pipe, buffer.data, &buffer_size); | ||
| 94 | + if (rc == UV_ENOBUFS) { | ||
| 95 | + buffer = MallocedBuffer<char>(buffer_size); | ||
| 96 | + if (buffer.data != nullptr) { | ||
| 97 | + rc = uv_pipe_getsockname(&handle->pipe, buffer.data, &buffer_size); | ||
| 98 | + } | ||
| 99 | + } | ||
| 100 | + if (rc == 0 && buffer_size != 0 && buffer.data != nullptr) { | ||
| 101 | + writer->json_keyvalue("localEndpoint", buffer.data); | ||
| 102 | + } else { | ||
| 103 | + writer->json_keyvalue("localEndpoint", null); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + // First call to get required buffer size. | ||
| 107 | + rc = uv_pipe_getpeername(&handle->pipe, buffer.data, &buffer_size); | ||
| 108 | + if (rc == UV_ENOBUFS) { | ||
| 109 | + buffer = MallocedBuffer<char>(buffer_size); | ||
| 110 | + if (buffer.data != nullptr) { | ||
| 111 | + rc = uv_pipe_getpeername(&handle->pipe, buffer.data, &buffer_size); | ||
| 112 | + } | ||
| 113 | + } | ||
| 114 | + if (rc == 0 && buffer_size != 0 && buffer.data != nullptr) { | ||
| 115 | + writer->json_keyvalue("remoteEndpoint", buffer.data); | ||
| 116 | + } else { | ||
| 117 | + writer->json_keyvalue("remoteEndpoint", null); | ||
| 118 | + } | ||
| 119 | + } | ||
| 120 | + | ||
| 85 | 121 | // Utility function to format libuv path information. | |
| 86 | 122 | static void ReportPath(uv_handle_t* h, JSONWriter* writer) { | |
| 87 | 123 | MallocedBuffer<char> buffer(0); | |
@@ -147,6 +183,9 @@ void WalkHandle(uv_handle_t* h, void* arg) { | |||
| 147 | 183 | case UV_UDP: | |
| 148 | 184 | ReportEndpoints(h, writer); | |
| 149 | 185 | break; | |
| 186 | + case UV_NAMED_PIPE: | ||
| 187 | + ReportPipeEndpoints(h, writer); | ||
| 188 | + break; | ||
| 150 | 189 | case UV_TIMER: { | |
| 151 | 190 | uint64_t due = handle->timer.timeout; | |
| 152 | 191 | uint64_t now = uv_now(handle->timer.loop); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,7 +15,7 @@ process.on('uncaughtException', common.mustCall((err) => { | |||
| 15 | 15 | assert.strictEqual(err, exception); | |
| 16 | 16 | const reports = helper.findReports(process.pid, tmpdir.path); | |
| 17 | 17 | assert.strictEqual(reports.length, 1); | |
| 18 | - console.log(reports[0]); | ||
| 18 | + | ||
| 19 | 19 | helper.validate(reports[0], [ | |
| 20 | 20 | ['header.event', 'Exception'], | |
| 21 | 21 | ['javascriptStack.message', `${exception}`], | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -15,7 +15,7 @@ process.on('uncaughtException', common.mustCall((err) => { | |||
| 15 | 15 | assert.strictEqual(err, exception); | |
| 16 | 16 | const reports = helper.findReports(process.pid, tmpdir.path); | |
| 17 | 17 | assert.strictEqual(reports.length, 1); | |
| 18 | - console.log(reports[0]); | ||
| 18 | + | ||
| 19 | 19 | helper.validate(reports[0], [ | |
| 20 | 20 | ['header.event', 'Exception'], | |
| 21 | 21 | ['javascriptStack.message', 'Symbol(foobar)'], | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,18 +2,22 @@ | |||
| 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); | ||
| 10 | + // This is quite similar to common.PIPE except that it uses an extended prefix | ||
| 11 | + // of "\\?\pipe" on windows. | ||
| 12 | + const PIPE = (() => { | ||
| 13 | + const localRelative = path.relative(process.cwd(), `${tmpdir.path}/`); | ||
| 14 | + const pipePrefix = common.isWindows ? '\\\\?\\pipe\\' : localRelative; | ||
| 15 | + const pipeName = `node-test.${process.pid}.sock`; | ||
| 16 | + return path.join(pipePrefix, pipeName); | ||
| 17 | + })(); | ||
| 12 | 18 | ||
| 19 | + function createFsHandle(childData) { | ||
| 13 | 20 | const fs = require('fs'); | |
| 14 | - const http = require('http'); | ||
| 15 | - const spawn = require('child_process').spawn; | ||
| 16 | - | ||
| 17 | 21 | // Watching files should result in fs_event/fs_poll uv handles. | |
| 18 | 22 | let watcher; | |
| 19 | 23 | try { | |
@@ -22,59 +26,129 @@ if (process.argv[2] === 'child') { | |||
| 22 | 26 | // fs.watch() unavailable | |
| 23 | 27 | } | |
| 24 | 28 | fs.watchFile(__filename, () => {}); | |
| 29 | + childData.skip_fs_watch = watcher === undefined; | ||
| 30 | + | ||
| 31 | + return () => { | ||
| 32 | + if (watcher) watcher.close(); | ||
| 33 | + fs.unwatchFile(__filename); | ||
| 34 | + }; | ||
| 35 | + } | ||
| 25 | 36 | ||
| 37 | + function createChildProcessHandle(childData) { | ||
| 38 | + const spawn = require('child_process').spawn; | ||
| 26 | 39 | // 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()));']); | ||
| 40 | + const cp = spawn(process.execPath, | ||
| 41 | + ['-e', "process.stdin.on('data', (x) => " + | ||
| 42 | + 'console.log(x.toString()));']); | ||
| 43 | + childData.pid = cp.pid; | ||
| 44 | + | ||
| 45 | + return () => { | ||
| 46 | + cp.kill(); | ||
| 47 | + }; | ||
| 48 | + } | ||
| 30 | 49 | ||
| 50 | + function createTimerHandle() { | ||
| 31 | 51 | const timeout = setInterval(() => {}, 1000); | |
| 32 | 52 | // Make sure the timer doesn't keep the test alive and let | |
| 33 | 53 | // us check we detect unref'd handles correctly. | |
| 34 | 54 | timeout.unref(); | |
| 55 | + return () => { | ||
| 56 | + clearInterval(timeout); | ||
| 57 | + }; | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + function createTcpHandle(childData) { | ||
| 61 | + const http = require('http'); | ||
| 35 | 62 | ||
| 63 | + return new Promise((resolve) => { | ||
| 64 | + // Simple server/connection to create tcp uv handles. | ||
| 65 | + const server = http.createServer((req, res) => { | ||
| 66 | + req.on('end', () => { | ||
| 67 | + resolve(() => { | ||
| 68 | + res.writeHead(200, { 'Content-Type': 'text/plain' }); | ||
| 69 | + res.end(); | ||
| 70 | + server.close(); | ||
| 71 | + }); | ||
| 72 | + }); | ||
| 73 | + req.resume(); | ||
| 74 | + }); | ||
| 75 | + server.listen(() => { | ||
| 76 | + childData.tcp_address = server.address(); | ||
| 77 | + http.get({ port: server.address().port }); | ||
| 78 | + }); | ||
| 79 | + }); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + function createUdpHandle(childData) { | ||
| 36 | 83 | // Datagram socket for udp uv handles. | |
| 37 | 84 | 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 | - })); | ||
| 85 | + const udpSocket = dgram.createSocket('udp4'); | ||
| 86 | + const connectedUdpSocket = dgram.createSocket('udp4'); | ||
| 87 | + | ||
| 88 | + return new Promise((resolve) => { | ||
| 89 | + udpSocket.bind({}, common.mustCall(() => { | ||
| 90 | + connectedUdpSocket.connect(udpSocket.address().port); | ||
| 43 | 91 | ||
| 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); | ||
| 92 | + childData.udp_address = udpSocket.address(); | ||
| 93 | + resolve(() => { | ||
| 94 | + connectedUdpSocket.close(); | ||
| 95 | + udpSocket.close(); | ||
| 96 | + }); | ||
| 97 | + })); | ||
| 98 | + }); | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + function createNamedPipeHandle(childData) { | ||
| 102 | + const net = require('net'); | ||
| 103 | + const sockPath = PIPE; | ||
| 104 | + return new Promise((resolve) => { | ||
| 105 | + const server = net.createServer((socket) => { | ||
| 106 | + childData.pipe_sock_path = server.address(); | ||
| 107 | + resolve(() => { | ||
| 108 | + socket.end(); | ||
| 109 | + server.close(); | ||
| 61 | 110 | }); | |
| 62 | 111 | }); | |
| 63 | - req.resume(); | ||
| 112 | + server.listen( | ||
| 113 | + sockPath, | ||
| 114 | + () => { | ||
| 115 | + net.connect(sockPath, (socket) => {}); | ||
| 116 | + }); | ||
| 64 | 117 | }); | |
| 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 }); | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + async function child() { | ||
| 121 | + // Exit on loss of parent process | ||
| 122 | + const exit = () => process.exit(2); | ||
| 123 | + process.on('disconnect', exit); | ||
| 124 | + | ||
| 125 | + const childData = {}; | ||
| 126 | + const disposes = await Promise.all([ | ||
| 127 | + createFsHandle(childData), | ||
| 128 | + createChildProcessHandle(childData), | ||
| 129 | + createTimerHandle(childData), | ||
| 130 | + createTcpHandle(childData), | ||
| 131 | + createUdpHandle(childData), | ||
| 132 | + createNamedPipeHandle(childData), | ||
| 133 | + ]); | ||
| 134 | + process.send(childData); | ||
| 135 | + | ||
| 136 | + // Generate the report while the connection is active. | ||
| 137 | + console.log(JSON.stringify(process.report.getReport(), null, 2)); | ||
| 138 | + | ||
| 139 | + // Tidy up to allow process to exit cleanly. | ||
| 140 | + disposes.forEach((it) => { | ||
| 141 | + it(); | ||
| 72 | 142 | }); | |
| 143 | + process.removeListener('disconnect', exit); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + if (process.argv[2] === 'child') { | ||
| 147 | + child(); | ||
| 73 | 148 | } else { | |
| 74 | 149 | const helper = require('../common/report.js'); | |
| 75 | 150 | const fork = require('child_process').fork; | |
| 76 | 151 | const assert = require('assert'); | |
| 77 | - const tmpdir = require('../common/tmpdir'); | ||
| 78 | 152 | tmpdir.refresh(); | |
| 79 | 153 | const options = { encoding: 'utf8', silent: true, cwd: tmpdir.path }; | |
| 80 | 154 | const child = fork(__filename, ['child'], options); | |
@@ -86,11 +160,11 @@ if (process.argv[2] === 'child') { | |||
| 86 | 160 | const report_msg = 'Report files were written: unexpectedly'; | |
| 87 | 161 | child.stdout.on('data', (chunk) => { stdout += chunk; }); | |
| 88 | 162 | child.on('exit', common.mustCall((code, signal) => { | |
| 163 | + assert.strictEqual(stderr.trim(), ''); | ||
| 89 | 164 | assert.deepStrictEqual(code, 0, 'Process exited unexpectedly with code: ' + | |
| 90 | 165 | `${code}`); | |
| 91 | 166 | assert.deepStrictEqual(signal, null, 'Process should have exited cleanly,' + | |
| 92 | 167 | ` but did not: ${signal}`); | |
| 93 | - assert.strictEqual(stderr.trim(), ''); | ||
| 94 | 168 | ||
| 95 | 169 | const reports = helper.findReports(child.pid, tmpdir.path); | |
| 96 | 170 | assert.deepStrictEqual(reports, [], report_msg, reports); | |
@@ -116,6 +190,7 @@ if (process.argv[2] === 'child') { | |||
| 116 | 190 | const expected_filename = `${prefix}${__filename}`; | |
| 117 | 191 | const found_tcp = []; | |
| 118 | 192 | const found_udp = []; | |
| 193 | + const found_named_pipe = []; | ||
| 119 | 194 | // Functions are named to aid debugging when they are not called. | |
| 120 | 195 | const validators = { | |
| 121 | 196 | fs_event: common.mustCall(function fs_event_validator(handle) { | |
@@ -133,6 +208,21 @@ if (process.argv[2] === 'child') { | |||
| 133 | 208 | }), | |
| 134 | 209 | pipe: common.mustCallAtLeast(function pipe_validator(handle) { | |
| 135 | 210 | assert(handle.is_referenced); | |
| 211 | + // Pipe handles. The report should contain three pipes: | ||
| 212 | + // 1. The server's listening pipe. | ||
| 213 | + // 2. The inbound pipe making the request. | ||
| 214 | + // 3. The outbound pipe sending the response. | ||
| 215 | + // | ||
| 216 | + // There is no way to distinguish inbound and outbound in a cross | ||
| 217 | + // platform manner, so we just check inbound here. | ||
| 218 | + const sockPath = child_data.pipe_sock_path; | ||
| 219 | + if (handle.localEndpoint === sockPath) { | ||
| 220 | + if (handle.writable === false) { | ||
| 221 | + found_named_pipe.push('listening'); | ||
| 222 | + } | ||
| 223 | + } else if (handle.remoteEndpoint === sockPath) { | ||
| 224 | + found_named_pipe.push('inbound'); | ||
| 225 | + } | ||
| 136 | 226 | }), | |
| 137 | 227 | process: common.mustCall(function process_validator(handle) { | |
| 138 | 228 | assert.strictEqual(handle.pid, child_data.pid); | |
@@ -172,7 +262,7 @@ if (process.argv[2] === 'child') { | |||
| 172 | 262 | assert(handle.is_referenced); | |
| 173 | 263 | }, 2), | |
| 174 | 264 | }; | |
| 175 | - console.log(report.libuv); | ||
| 265 | + | ||
| 176 | 266 | for (const entry of report.libuv) { | |
| 177 | 267 | if (validators[entry.type]) validators[entry.type](entry); | |
| 178 | 268 | } | |
@@ -182,6 +272,9 @@ if (process.argv[2] === 'child') { | |||
| 182 | 272 | for (const socket of ['connected', 'unconnected']) { | |
| 183 | 273 | assert(found_udp.includes(socket), `${socket} UDP socket was not found`); | |
| 184 | 274 | } | |
| 275 | + for (const socket of ['listening', 'inbound']) { | ||
| 276 | + assert(found_named_pipe.includes(socket), `${socket} named pipe socket was not found`); | ||
| 277 | + } | ||
| 185 | 278 | ||
| 186 | 279 | // Common report tests. | |
| 187 | 280 | helper.validateContent(stdout); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments