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