11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci// Flags: --expose-internals
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst initHooks = require('./init-hooks');
51cb0ef41Sopenharmony_ciconst { checkInvocations } = require('./hook-checks');
61cb0ef41Sopenharmony_ciconst assert = require('assert');
71cb0ef41Sopenharmony_ciconst { async_id_symbol } = require('internal/async_hooks').symbols;
81cb0ef41Sopenharmony_ciconst http = require('http');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci// Checks that the async resource used in init in case of a reused handle
111cb0ef41Sopenharmony_ci// is not reused. Test is based on parallel\test-async-hooks-http-agent.js.
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciconst hooks = initHooks();
141cb0ef41Sopenharmony_cihooks.enable();
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciconst reqAsyncIds = [];
171cb0ef41Sopenharmony_cilet socket;
181cb0ef41Sopenharmony_cilet responses = 0;
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci// Make sure a single socket is transparently reused for 2 requests.
211cb0ef41Sopenharmony_ciconst agent = new http.Agent({
221cb0ef41Sopenharmony_ci  keepAlive: true,
231cb0ef41Sopenharmony_ci  keepAliveMsecs: Infinity,
241cb0ef41Sopenharmony_ci  maxSockets: 1,
251cb0ef41Sopenharmony_ci});
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciconst verifyRequest = (idx) => (res) => {
281cb0ef41Sopenharmony_ci  reqAsyncIds[idx] = res.socket[async_id_symbol];
291cb0ef41Sopenharmony_ci  assert.ok(reqAsyncIds[idx] > 0, `${reqAsyncIds[idx]} > 0`);
301cb0ef41Sopenharmony_ci  if (socket) {
311cb0ef41Sopenharmony_ci    // Check that both requests share their socket.
321cb0ef41Sopenharmony_ci    assert.strictEqual(res.socket, socket);
331cb0ef41Sopenharmony_ci  } else {
341cb0ef41Sopenharmony_ci    socket = res.socket;
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  res.on('data', common.mustCallAtLeast());
381cb0ef41Sopenharmony_ci  res.on('end', common.mustCall(() => {
391cb0ef41Sopenharmony_ci    if (++responses === 2) {
401cb0ef41Sopenharmony_ci      // Clean up to let the event loop stop.
411cb0ef41Sopenharmony_ci      server.close();
421cb0ef41Sopenharmony_ci      agent.destroy();
431cb0ef41Sopenharmony_ci    }
441cb0ef41Sopenharmony_ci  }));
451cb0ef41Sopenharmony_ci};
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ciconst server = http.createServer(common.mustCall((req, res) => {
481cb0ef41Sopenharmony_ci  req.once('data', common.mustCallAtLeast(() => {
491cb0ef41Sopenharmony_ci    res.writeHead(200, { 'Content-Type': 'text/plain' });
501cb0ef41Sopenharmony_ci    res.write('foo');
511cb0ef41Sopenharmony_ci  }));
521cb0ef41Sopenharmony_ci  req.on('end', common.mustCall(() => {
531cb0ef41Sopenharmony_ci    res.end('bar');
541cb0ef41Sopenharmony_ci  }));
551cb0ef41Sopenharmony_ci}, 2)).listen(0, common.mustCall(() => {
561cb0ef41Sopenharmony_ci  const port = server.address().port;
571cb0ef41Sopenharmony_ci  const payload = 'hello world';
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  // First request.
601cb0ef41Sopenharmony_ci  const r1 = http.request({
611cb0ef41Sopenharmony_ci    agent, port, method: 'POST',
621cb0ef41Sopenharmony_ci  }, common.mustCall(verifyRequest(0)));
631cb0ef41Sopenharmony_ci  r1.end(payload);
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci  // Second request. Sent in parallel with the first one.
661cb0ef41Sopenharmony_ci  const r2 = http.request({
671cb0ef41Sopenharmony_ci    agent, port, method: 'POST',
681cb0ef41Sopenharmony_ci  }, common.mustCall(verifyRequest(1)));
691cb0ef41Sopenharmony_ci  r2.end(payload);
701cb0ef41Sopenharmony_ci}));
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ciprocess.on('exit', onExit);
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_cifunction onExit() {
761cb0ef41Sopenharmony_ci  hooks.disable();
771cb0ef41Sopenharmony_ci  hooks.sanityCheck();
781cb0ef41Sopenharmony_ci  const activities = hooks.activities;
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  // Verify both invocations
811cb0ef41Sopenharmony_ci  const first = activities.filter((x) => x.uid === reqAsyncIds[0])[0];
821cb0ef41Sopenharmony_ci  checkInvocations(first, { init: 1, destroy: 1 }, 'when process exits');
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  const second = activities.filter((x) => x.uid === reqAsyncIds[1])[0];
851cb0ef41Sopenharmony_ci  checkInvocations(second, { init: 1, destroy: 1 }, 'when process exits');
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  // Verify reuse handle has been wrapped
881cb0ef41Sopenharmony_ci  assert.strictEqual(first.type, second.type);
891cb0ef41Sopenharmony_ci  assert.ok(first.handle !== second.handle, 'Resource reused');
901cb0ef41Sopenharmony_ci  assert.ok(first.handle === second.handle.handle,
911cb0ef41Sopenharmony_ci            'Resource not wrapped correctly');
921cb0ef41Sopenharmony_ci}
93