/
collectHandles.test.js
120 lines (94 loc) · 3.71 KB
/
collectHandles.test.js
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
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import {promises as dns} from 'dns';
import http from 'http';
import {PerformanceObserver} from 'perf_hooks';
import zlib from 'zlib';
import collectHandles from '../collectHandles';
describe('collectHandles', () => {
it('should collect Timeout', async () => {
const handleCollector = collectHandles();
const interval = setInterval(() => {}, 100);
const openHandles = await handleCollector();
expect(openHandles).toContainEqual(
expect.objectContaining({message: 'Timeout'}),
);
clearInterval(interval);
});
it('should not collect the PerformanceObserver open handle', async () => {
const handleCollector = collectHandles();
const obs = new PerformanceObserver((list, observer) => {});
obs.observe({entryTypes: ['mark']});
const openHandles = await handleCollector();
expect(openHandles).not.toContainEqual(
expect.objectContaining({message: 'PerformanceObserver'}),
);
obs.disconnect();
});
it('should not collect the DNSCHANNEL open handle', async () => {
const handleCollector = collectHandles();
const resolver = new dns.Resolver();
resolver.getServers();
const openHandles = await handleCollector();
expect(openHandles).not.toContainEqual(
expect.objectContaining({message: 'DNSCHANNEL'}),
);
});
it('should not collect the ZLIB open handle', async () => {
const handleCollector = collectHandles();
const decompressed = zlib.inflateRawSync(
Buffer.from('cb2a2d2e5128492d2ec9cc4b0700', 'hex'),
);
const openHandles = await handleCollector();
expect(openHandles).not.toContainEqual(
expect.objectContaining({message: 'ZLIB'}),
);
});
it('should collect handles opened in test functions with `done` callbacks', done => {
const handleCollector = collectHandles();
const server = http.createServer((_, response) => response.end('ok'));
server.listen(0, () => {
// Collect results while server is still open.
handleCollector()
.then(openHandles => {
server.close(() => {
expect(openHandles).toContainEqual(
expect.objectContaining({message: 'TCPSERVERWRAP'}),
);
done();
});
})
.catch(done);
});
});
it('should not collect handles that have been queued to close', async () => {
const handleCollector = collectHandles();
const server = http.createServer((_, response) => response.end('ok'));
// Start and stop server.
await new Promise(r => server.listen(0, r));
await new Promise(r => server.close(r));
const openHandles = await handleCollector();
expect(openHandles).toHaveLength(0);
});
it('should collect handles indirectly triggered by user code', async () => {
const handleCollector = collectHandles();
// Calling `server.listen` with just a port (e.g. `server.listen(0)`)
// creates a `TCPSERVERWRAP` async resource. However, including a `host`
// option instead creates a `GETADDRINFOREQWRAP` resource that only
// lasts for the lifetime of the `listen()` call, but which *indirectly*
// creates a long-lived `TCPSERVERWRAP` resource. We want to make sure we
// capture that long-lived resource.
const server = new http.Server();
await new Promise(r => server.listen({host: 'localhost', port: 0}, r));
const openHandles = await handleCollector();
await new Promise(r => server.close(r));
expect(openHandles).toContainEqual(
expect.objectContaining({message: 'TCPSERVERWRAP'}),
);
});
});