summaryrefslogtreecommitdiff
path: root/test/node-report/test-api-uvhandles.js
blob: 52f58b6e1355218f096f9f6bfa7ea44676c8947f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
'use strict';

// Testcase to check reporting of uv handles.
const common = require('../common');
common.skipIfReportDisabled();
if (process.argv[2] === 'child') {
  // Exit on loss of parent process
  const exit = () => process.exit(2);
  process.on('disconnect', exit);

  const fs = require('fs');
  const http = require('http');
  const spawn = require('child_process').spawn;

  // Watching files should result in fs_event/fs_poll uv handles.
  let watcher;
  try {
    watcher = fs.watch(__filename);
  } catch {
    // fs.watch() unavailable
  }
  fs.watchFile(__filename, () => {});

  // Child should exist when this returns as child_process.pid must be set.
  const child_process = spawn(process.execPath,
                              ['-e', "process.stdin.on('data', (x) => " +
                                     'console.log(x.toString()));']);

  const timeout = setInterval(() => {}, 1000);
  // Make sure the timer doesn't keep the test alive and let
  // us check we detect unref'd handles correctly.
  timeout.unref();

  // Datagram socket for udp uv handles.
  const dgram = require('dgram');
  const udp_socket = dgram.createSocket('udp4');
  udp_socket.bind({});

  // Simple server/connection to create tcp uv handles.
  const server = http.createServer((req, res) => {
    req.on('end', () => {
      // Generate the report while the connection is active.
      console.log(process.report.getReport());
      child_process.kill();

      res.writeHead(200, { 'Content-Type': 'text/plain' });
      res.end();

      // Tidy up to allow process to exit cleanly.
      server.close(() => {
        if (watcher) watcher.close();
        fs.unwatchFile(__filename);
        udp_socket.close();
        process.removeListener('disconnect', exit);
      });
    });
    req.resume();
  });
  server.listen(() => {
    const data = { pid: child_process.pid,
                   tcp_address: server.address(),
                   udp_address: udp_socket.address(),
                   skip_fs_watch: (watcher === undefined ?
                     'fs.watch() unavailable' :
                     false) };
    process.send(data);
    http.get({ port: server.address().port });
  });
} else {
  const helper = require('../common/report.js');
  const fork = require('child_process').fork;
  const assert = require('assert');
  const tmpdir = require('../common/tmpdir');
  tmpdir.refresh();
  const options = { encoding: 'utf8', silent: true, cwd: tmpdir.path };
  const child = fork('--experimental-report', [__filename, 'child'], options);
  let stderr = '';
  child.stderr.on('data', (chunk) => { stderr += chunk; });
  let stdout = '';
  const std_msg = 'Found messages in stderr unexpectedly: ';
  const report_msg = 'Report files were written: unexpectedly';
  child.stdout.on('data', (chunk) => { stdout += chunk; });
  child.on('exit', common.mustCall((code, signal) => {
    assert.deepStrictEqual(code, 0, 'Process exited unexpectedly with code' +
                           `${code}`);
    assert.deepStrictEqual(signal, null, 'Process should have exited cleanly,' +
                            ` but did not: ${signal}`);
    assert.ok(stderr.match(
      '(node:.*) ExperimentalWarning: report is an experimental' +
      ' feature. This feature could change at any time'),
              std_msg);

    const reports = helper.findReports(child.pid, tmpdir.path);
    assert.deepStrictEqual(reports, [], report_msg, reports);

    const report = JSON.parse(stdout);
    let fs = 0;
    let poll = 0;
    let process = 0;
    let timer = 0;
    let pipe = 0;
    let tcp = 0;
    let udp = 0;
    const fs_msg = 'fs_event not found';
    const poll_msg = 'poll_event not found';
    const process_msg = 'process event not found';
    const timer_msg = 'timer event not found';
    const pipe_msg = 'pipe event not found';
    const tcp_msg = 'tcp event not found';
    const udp_msg = 'udp event not found';
    for (const entry in report.libuv) {
      if (report.libuv[entry].type === 'fs_event') fs = 1;
      else if (report.libuv[entry].type === 'fs_poll') poll = 1;
      else if (report.libuv[entry].type === 'process') process = 1;
      else if (report.libuv[entry].type === 'timer') timer = 1;
      else if (report.libuv[entry].type === 'pipe') pipe = 1;
      else if (report.libuv[entry].type === 'tcp') tcp = 1;
      else if (report.libuv[entry].type === 'udp') udp = 1;
    }
    assert.deepStrictEqual(fs, 1, fs_msg);
    assert.deepStrictEqual(poll, 1, poll_msg);
    assert.deepStrictEqual(process, 1, process_msg);
    assert.deepStrictEqual(timer, 1, timer_msg);
    assert.deepStrictEqual(pipe, 1, pipe_msg);
    assert.deepStrictEqual(tcp, 1, tcp_msg);
    assert.deepStrictEqual(udp, 1, udp_msg);

    // Common report tests.
    helper.validateContent(stdout, { pid: child.pid,
                                     commandline: child.spawnargs.join(' ')
    });
  }));
}