• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2// Flags: --expose-gc --expose-internals --no-warnings --test-udp-no-try-send
3
4const common = require('../common');
5const { internalBinding } = require('internal/test/binding');
6const assert = require('assert');
7const fs = require('fs');
8const v8 = require('v8');
9const fsPromises = fs.promises;
10const net = require('net');
11const providers = { ...internalBinding('async_wrap').Providers };
12const fixtures = require('../common/fixtures');
13const tmpdir = require('../common/tmpdir');
14const { getSystemErrorName } = require('util');
15
16// Make sure that all Providers are tested.
17{
18  const hooks = require('async_hooks').createHook({
19    init(id, type) {
20      if (type === 'NONE')
21        throw new Error('received a provider type of NONE');
22      delete providers[type];
23    },
24  }).enable();
25  process.on('beforeExit', common.mustCall(() => {
26    // This garbage collection call verifies that the wraps being garbage
27    // collected doesn't resurrect the process again due to weirdly timed
28    // uv_close calls and other similar instruments in destructors.
29    global.gc();
30
31    process.removeAllListeners('uncaughtException');
32    hooks.disable();
33    delete providers.NONE;  // Should never be used.
34
35    // See test/pseudo-tty/test-async-wrap-getasyncid-tty.js
36    // Requires an 'actual' tty fd to be available.
37    delete providers.TTYWRAP;
38
39    // TODO(jasnell): Test for these
40    delete providers.HTTP2SESSION;
41    delete providers.HTTP2STREAM;
42    delete providers.HTTP2PING;
43    delete providers.HTTP2SETTINGS;
44    // TODO(addaleax): Test for these
45    delete providers.STREAMPIPE;
46    delete providers.MESSAGEPORT;
47    delete providers.WORKER;
48    delete providers.JSUDPWRAP;
49    if (!common.isMainThread)
50      delete providers.INSPECTORJSBINDING;
51    delete providers.KEYPAIRGENREQUEST;
52    delete providers.HTTPCLIENTREQUEST;
53    delete providers.HTTPINCOMINGMESSAGE;
54    delete providers.ELDHISTOGRAM;
55    delete providers.SIGINTWATCHDOG;
56    delete providers.WORKERHEAPSNAPSHOT;
57    delete providers.FIXEDSIZEBLOBCOPY;
58
59    const objKeys = Object.keys(providers);
60    if (objKeys.length > 0)
61      process._rawDebug(objKeys);
62    assert.strictEqual(objKeys.length, 0);
63  }));
64}
65
66function testUninitialized(req, ctor_name) {
67  assert.strictEqual(typeof req.getAsyncId, 'function');
68  assert.strictEqual(req.getAsyncId(), -1);
69  assert.strictEqual(req.constructor.name, ctor_name);
70}
71
72function testInitialized(req, ctor_name) {
73  assert.strictEqual(typeof req.getAsyncId, 'function');
74  assert(Number.isSafeInteger(req.getAsyncId()));
75  assert(req.getAsyncId() > 0);
76  assert.strictEqual(req.constructor.name, ctor_name);
77}
78
79
80{
81  const cares = internalBinding('cares_wrap');
82  const dns = require('dns');
83
84  testUninitialized(new cares.GetAddrInfoReqWrap(), 'GetAddrInfoReqWrap');
85  testUninitialized(new cares.GetNameInfoReqWrap(), 'GetNameInfoReqWrap');
86  testUninitialized(new cares.QueryReqWrap(), 'QueryReqWrap');
87
88  testInitialized(dns.lookup('www.google.com', () => {}), 'GetAddrInfoReqWrap');
89  testInitialized(dns.lookupService('::1', 22, () => {}), 'GetNameInfoReqWrap');
90
91  const resolver = new dns.Resolver();
92  resolver.setServers(['127.0.0.1']);
93  testInitialized(resolver._handle, 'ChannelWrap');
94  testInitialized(resolver.resolve6('::1', () => {}), 'QueryReqWrap');
95  resolver.cancel();
96}
97
98
99{
100  const FSEvent = internalBinding('fs_event_wrap').FSEvent;
101  testInitialized(new FSEvent(), 'FSEvent');
102}
103
104
105{
106  const JSStream = internalBinding('js_stream').JSStream;
107  testInitialized(new JSStream(), 'JSStream');
108}
109
110
111{
112  // We don't want to expose getAsyncId for promises but we need to construct
113  // one so that the corresponding provider type is removed from the
114  // providers list.
115  new Promise((res) => res(5));
116}
117
118
119if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check
120  const crypto = require('crypto');
121
122  // The handle for PBKDF2 and RandomBytes isn't returned by the function call,
123  // so need to check it from the callback.
124
125  const mc = common.mustCall(function pb() {
126    testInitialized(this, 'AsyncWrap');
127  });
128  crypto.pbkdf2('password', 'salt', 1, 20, 'sha256', mc);
129
130  crypto.randomBytes(1, common.mustCall(function rb() {
131    testInitialized(this, 'AsyncWrap');
132  }));
133
134  if (typeof internalBinding('crypto').scrypt === 'function') {
135    crypto.scrypt('password', 'salt', 8, common.mustCall(function() {
136      testInitialized(this, 'AsyncWrap');
137    }));
138  }
139}
140
141
142{
143  const binding = internalBinding('fs');
144  const path = require('path');
145
146  const FSReqCallback = binding.FSReqCallback;
147  const req = new FSReqCallback();
148  req.oncomplete = () => { };
149
150  testInitialized(req, 'FSReqCallback');
151  binding.access(path.toNamespacedPath('../'), fs.F_OK, req);
152
153  const StatWatcher = binding.StatWatcher;
154  testInitialized(new StatWatcher(), 'StatWatcher');
155}
156
157
158{
159  const { HTTPParser } = require('_http_common');
160  const parser = new HTTPParser();
161  testUninitialized(parser, 'HTTPParser');
162  parser.initialize(HTTPParser.REQUEST, {});
163  testInitialized(parser, 'HTTPParser');
164}
165
166
167{
168  const Gzip = require('zlib').Gzip;
169  testInitialized(new Gzip()._handle, 'Zlib');
170}
171
172{
173  const binding = internalBinding('pipe_wrap');
174  const handle = new binding.Pipe(binding.constants.IPC);
175  testInitialized(handle, 'Pipe');
176}
177
178{
179  tmpdir.refresh();
180
181  const server = net.createServer(common.mustCall((socket) => {
182    server.close();
183  })).listen(common.PIPE, common.mustCall(() => {
184    const binding = internalBinding('pipe_wrap');
185    const handle = new binding.Pipe(binding.constants.SOCKET);
186    testInitialized(handle, 'Pipe');
187    const req = new binding.PipeConnectWrap();
188    testUninitialized(req, 'PipeConnectWrap');
189    req.address = common.PIPE;
190    req.oncomplete = common.mustCall(() => handle.close());
191    handle.connect(req, req.address, req.oncomplete);
192    testInitialized(req, 'PipeConnectWrap');
193  }));
194}
195
196{
197  const Process = internalBinding('process_wrap').Process;
198  testInitialized(new Process(), 'Process');
199}
200
201{
202  const { Signal } = internalBinding('signal_wrap');
203  testInitialized(new Signal(), 'Signal');
204}
205
206{
207  async function openTest() {
208    const fd = await fsPromises.open(__filename, 'r');
209    testInitialized(fd, 'FileHandle');
210    await fd.close();
211  }
212  openTest().then(common.mustCall());
213}
214
215{
216  const binding = internalBinding('stream_wrap');
217  testUninitialized(new binding.WriteWrap(), 'WriteWrap');
218}
219
220{
221  const stream_wrap = internalBinding('stream_wrap');
222  const tcp_wrap = internalBinding('tcp_wrap');
223  const server = net.createServer(common.mustCall((socket) => {
224    server.close();
225    socket.on('data', () => {
226      socket.end();
227      socket.destroy();
228    });
229    socket.resume();
230  })).listen(0, common.localhostIPv4, common.mustCall(() => {
231    const handle = new tcp_wrap.TCP(tcp_wrap.constants.SOCKET);
232    const req = new tcp_wrap.TCPConnectWrap();
233    const sreq = new stream_wrap.ShutdownWrap();
234    testInitialized(handle, 'TCP');
235    testUninitialized(req, 'TCPConnectWrap');
236    testUninitialized(sreq, 'ShutdownWrap');
237
238    sreq.oncomplete = common.mustCall(() => {
239      handle.close();
240    });
241
242    req.oncomplete = common.mustCall(writeData);
243    function writeData() {
244      const wreq = new stream_wrap.WriteWrap();
245      wreq.handle = handle;
246      wreq.oncomplete = () => {
247        handle.shutdown(sreq);
248        testInitialized(sreq, 'ShutdownWrap');
249      };
250      const err = handle.writeLatin1String(wreq, 'hi'.repeat(100000));
251      if (err)
252        throw new Error(`write failed: ${getSystemErrorName(err)}`);
253      if (!stream_wrap.streamBaseState[stream_wrap.kLastWriteWasAsync]) {
254        testUninitialized(wreq, 'WriteWrap');
255        // Synchronous finish. Write more data until we hit an
256        // asynchronous write.
257        return writeData();
258      }
259      testInitialized(wreq, 'WriteWrap');
260    }
261    req.address = common.localhostIPv4;
262    req.port = server.address().port;
263    const err = handle.connect(req, req.address, req.port);
264    assert.strictEqual(err, 0);
265    testInitialized(req, 'TCPConnectWrap');
266  }));
267}
268
269
270if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check
271  const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
272  const tcp = new TCP(TCPConstants.SOCKET);
273
274  const ca = fixtures.readKey('rsa_ca.crt');
275  const cert = fixtures.readKey('rsa_cert.crt');
276  const key = fixtures.readKey('rsa_private.pem');
277
278  const credentials = require('tls').createSecureContext({ ca, cert, key });
279
280  // TLSWrap is exposed, but needs to be instantiated via tls_wrap.wrap().
281  const tls_wrap = internalBinding('tls_wrap');
282  testInitialized(tls_wrap.wrap(tcp, credentials.context, true), 'TLSWrap');
283}
284
285{
286  const binding = internalBinding('udp_wrap');
287  const handle = new binding.UDP();
288  const req = new binding.SendWrap();
289  testInitialized(handle, 'UDP');
290  testUninitialized(req, 'SendWrap');
291
292  handle.bind('0.0.0.0', 0, undefined);
293  const addr = {};
294  handle.getsockname(addr);
295  req.address = '127.0.0.1';
296  req.port = addr.port;
297  req.oncomplete = () => handle.close();
298  handle.send(req, [Buffer.alloc(1)], 1, req.port, req.address, true);
299  testInitialized(req, 'SendWrap');
300}
301
302if (process.features.inspector && common.isMainThread) {
303  const binding = internalBinding('inspector');
304  const handle = new binding.Connection(() => {});
305  testInitialized(handle, 'Connection');
306  handle.disconnect();
307}
308
309// PROVIDER_HEAPDUMP
310{
311  v8.getHeapSnapshot().destroy();
312}
313
314// DIRHANDLE
315{
316  const dirBinding = internalBinding('fs_dir');
317  const handle = dirBinding.opendir('./', 'utf8', undefined, {});
318  testInitialized(handle, 'DirHandle');
319}
320