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