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 58 const objKeys = Object.keys(providers); 59 if (objKeys.length > 0) 60 process._rawDebug(objKeys); 61 assert.strictEqual(objKeys.length, 0); 62 })); 63} 64 65function testUninitialized(req, ctor_name) { 66 assert.strictEqual(typeof req.getAsyncId, 'function'); 67 assert.strictEqual(req.getAsyncId(), -1); 68 assert.strictEqual(req.constructor.name, ctor_name); 69} 70 71function testInitialized(req, ctor_name) { 72 assert.strictEqual(typeof req.getAsyncId, 'function'); 73 assert(Number.isSafeInteger(req.getAsyncId())); 74 assert(req.getAsyncId() > 0); 75 assert.strictEqual(req.constructor.name, ctor_name); 76} 77 78 79{ 80 const cares = internalBinding('cares_wrap'); 81 const dns = require('dns'); 82 83 testUninitialized(new cares.GetAddrInfoReqWrap(), 'GetAddrInfoReqWrap'); 84 testUninitialized(new cares.GetNameInfoReqWrap(), 'GetNameInfoReqWrap'); 85 testUninitialized(new cares.QueryReqWrap(), 'QueryReqWrap'); 86 87 testInitialized(dns.lookup('www.google.com', () => {}), 'GetAddrInfoReqWrap'); 88 testInitialized(dns.lookupService('::1', 22, () => {}), 'GetNameInfoReqWrap'); 89 90 const resolver = new dns.Resolver(); 91 resolver.setServers(['127.0.0.1']); 92 testInitialized(resolver._handle, 'ChannelWrap'); 93 testInitialized(resolver.resolve6('::1', () => {}), 'QueryReqWrap'); 94 resolver.cancel(); 95} 96 97 98{ 99 const FSEvent = internalBinding('fs_event_wrap').FSEvent; 100 testInitialized(new FSEvent(), 'FSEvent'); 101} 102 103 104{ 105 const JSStream = internalBinding('js_stream').JSStream; 106 testInitialized(new JSStream(), 'JSStream'); 107} 108 109 110{ 111 // We don't want to expose getAsyncId for promises but we need to construct 112 // one so that the corresponding provider type is removed from the 113 // providers list. 114 new Promise((res) => res(5)); 115} 116 117 118if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check 119 const crypto = require('crypto'); 120 121 // The handle for PBKDF2 and RandomBytes isn't returned by the function call, 122 // so need to check it from the callback. 123 124 const mc = common.mustCall(function pb() { 125 testInitialized(this, 'AsyncWrap'); 126 }); 127 crypto.pbkdf2('password', 'salt', 1, 20, 'sha256', mc); 128 129 crypto.randomBytes(1, common.mustCall(function rb() { 130 testInitialized(this, 'AsyncWrap'); 131 })); 132 133 if (typeof internalBinding('crypto').scrypt === 'function') { 134 crypto.scrypt('password', 'salt', 8, common.mustCall(function() { 135 testInitialized(this, 'AsyncWrap'); 136 })); 137 } 138} 139 140 141{ 142 const binding = internalBinding('fs'); 143 const path = require('path'); 144 145 const FSReqCallback = binding.FSReqCallback; 146 const req = new FSReqCallback(); 147 req.oncomplete = () => { }; 148 149 testInitialized(req, 'FSReqCallback'); 150 binding.access(path.toNamespacedPath('../'), fs.F_OK, req); 151 152 const StatWatcher = binding.StatWatcher; 153 testInitialized(new StatWatcher(), 'StatWatcher'); 154} 155 156 157{ 158 const { HTTPParser } = require('_http_common'); 159 const parser = new HTTPParser(); 160 testUninitialized(parser, 'HTTPParser'); 161 parser.initialize(HTTPParser.REQUEST, {}); 162 testInitialized(parser, 'HTTPParser'); 163} 164 165 166{ 167 const Gzip = require('zlib').Gzip; 168 testInitialized(new Gzip()._handle, 'Zlib'); 169} 170 171{ 172 const binding = internalBinding('pipe_wrap'); 173 const handle = new binding.Pipe(binding.constants.IPC); 174 testInitialized(handle, 'Pipe'); 175} 176 177{ 178 tmpdir.refresh(); 179 180 const server = net.createServer(common.mustCall((socket) => { 181 server.close(); 182 })).listen(common.PIPE, common.mustCall(() => { 183 const binding = internalBinding('pipe_wrap'); 184 const handle = new binding.Pipe(binding.constants.SOCKET); 185 testInitialized(handle, 'Pipe'); 186 const req = new binding.PipeConnectWrap(); 187 testUninitialized(req, 'PipeConnectWrap'); 188 req.address = common.PIPE; 189 req.oncomplete = common.mustCall(() => handle.close()); 190 handle.connect(req, req.address, req.oncomplete); 191 testInitialized(req, 'PipeConnectWrap'); 192 })); 193} 194 195{ 196 const Process = internalBinding('process_wrap').Process; 197 testInitialized(new Process(), 'Process'); 198} 199 200{ 201 const { Signal } = internalBinding('signal_wrap'); 202 testInitialized(new Signal(), 'Signal'); 203} 204 205{ 206 async function openTest() { 207 const fd = await fsPromises.open(__filename, 'r'); 208 testInitialized(fd, 'FileHandle'); 209 await fd.close(); 210 } 211 openTest().then(common.mustCall()); 212} 213 214{ 215 const binding = internalBinding('stream_wrap'); 216 testUninitialized(new binding.WriteWrap(), 'WriteWrap'); 217} 218 219{ 220 const stream_wrap = internalBinding('stream_wrap'); 221 const tcp_wrap = internalBinding('tcp_wrap'); 222 const server = net.createServer(common.mustCall((socket) => { 223 server.close(); 224 socket.on('data', () => { 225 socket.end(); 226 socket.destroy(); 227 }); 228 socket.resume(); 229 })).listen(0, common.localhostIPv4, common.mustCall(() => { 230 const handle = new tcp_wrap.TCP(tcp_wrap.constants.SOCKET); 231 const req = new tcp_wrap.TCPConnectWrap(); 232 const sreq = new stream_wrap.ShutdownWrap(); 233 testInitialized(handle, 'TCP'); 234 testUninitialized(req, 'TCPConnectWrap'); 235 testUninitialized(sreq, 'ShutdownWrap'); 236 237 sreq.oncomplete = common.mustCall(() => { 238 handle.close(); 239 }); 240 241 req.oncomplete = common.mustCall(writeData); 242 function writeData() { 243 const wreq = new stream_wrap.WriteWrap(); 244 wreq.handle = handle; 245 wreq.oncomplete = () => { 246 handle.shutdown(sreq); 247 testInitialized(sreq, 'ShutdownWrap'); 248 }; 249 const err = handle.writeLatin1String(wreq, 'hi'.repeat(100000)); 250 if (err) 251 throw new Error(`write failed: ${getSystemErrorName(err)}`); 252 if (!stream_wrap.streamBaseState[stream_wrap.kLastWriteWasAsync]) { 253 testUninitialized(wreq, 'WriteWrap'); 254 // Synchronous finish. Write more data until we hit an 255 // asynchronous write. 256 return writeData(); 257 } 258 testInitialized(wreq, 'WriteWrap'); 259 } 260 req.address = common.localhostIPv4; 261 req.port = server.address().port; 262 const err = handle.connect(req, req.address, req.port); 263 assert.strictEqual(err, 0); 264 testInitialized(req, 'TCPConnectWrap'); 265 })); 266} 267 268 269if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check 270 const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap'); 271 const tcp = new TCP(TCPConstants.SOCKET); 272 273 const ca = fixtures.readKey('rsa_ca.crt'); 274 const cert = fixtures.readKey('rsa_cert.crt'); 275 const key = fixtures.readKey('rsa_private.pem'); 276 277 const credentials = require('tls').createSecureContext({ ca, cert, key }); 278 279 // TLSWrap is exposed, but needs to be instantiated via tls_wrap.wrap(). 280 const tls_wrap = internalBinding('tls_wrap'); 281 testInitialized(tls_wrap.wrap(tcp, credentials.context, true), 'TLSWrap'); 282} 283 284{ 285 const binding = internalBinding('udp_wrap'); 286 const handle = new binding.UDP(); 287 const req = new binding.SendWrap(); 288 testInitialized(handle, 'UDP'); 289 testUninitialized(req, 'SendWrap'); 290 291 handle.bind('0.0.0.0', 0, undefined); 292 const addr = {}; 293 handle.getsockname(addr); 294 req.address = '127.0.0.1'; 295 req.port = addr.port; 296 req.oncomplete = () => handle.close(); 297 handle.send(req, [Buffer.alloc(1)], 1, req.port, req.address, true); 298 testInitialized(req, 'SendWrap'); 299} 300 301if (process.features.inspector && common.isMainThread) { 302 const binding = internalBinding('inspector'); 303 const handle = new binding.Connection(() => {}); 304 testInitialized(handle, 'Connection'); 305 handle.disconnect(); 306} 307 308// PROVIDER_HEAPDUMP 309{ 310 v8.getHeapSnapshot().destroy(); 311} 312 313// DIRHANDLE 314{ 315 const dirBinding = internalBinding('fs_dir'); 316 const handle = dirBinding.opendir('./', 'utf8', undefined, {}); 317 testInitialized(handle, 'DirHandle'); 318} 319