11cb0ef41Sopenharmony_ci// Flags: --expose-gc --no-warnings --expose-internals
21cb0ef41Sopenharmony_ci'use strict';
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ciconst common = require('../common');
51cb0ef41Sopenharmony_cicommon.skipIfWorker(); // https://github.com/nodejs/node/issues/22767
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_citry {
81cb0ef41Sopenharmony_ci  require('trace_events');
91cb0ef41Sopenharmony_ci} catch {
101cb0ef41Sopenharmony_ci  common.skip('missing trace events');
111cb0ef41Sopenharmony_ci}
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ciconst assert = require('assert');
141cb0ef41Sopenharmony_ciconst cp = require('child_process');
151cb0ef41Sopenharmony_ciconst path = require('path');
161cb0ef41Sopenharmony_ciconst fs = require('fs');
171cb0ef41Sopenharmony_ciconst tmpdir = require('../common/tmpdir');
181cb0ef41Sopenharmony_ciconst {
191cb0ef41Sopenharmony_ci  createTracing,
201cb0ef41Sopenharmony_ci  getEnabledCategories
211cb0ef41Sopenharmony_ci} = require('trace_events');
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cifunction getEnabledCategoriesFromCommandLine() {
241cb0ef41Sopenharmony_ci  const indexOfCatFlag = process.execArgv.indexOf('--trace-event-categories');
251cb0ef41Sopenharmony_ci  if (indexOfCatFlag === -1) {
261cb0ef41Sopenharmony_ci    return undefined;
271cb0ef41Sopenharmony_ci  }
281cb0ef41Sopenharmony_ci  return process.execArgv[indexOfCatFlag + 1];
291cb0ef41Sopenharmony_ci}
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ciconst isChild = process.argv[2] === 'child';
321cb0ef41Sopenharmony_ciconst enabledCategories = getEnabledCategoriesFromCommandLine();
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciassert.strictEqual(getEnabledCategories(), enabledCategories);
351cb0ef41Sopenharmony_ci[1, 'foo', true, false, null, undefined].forEach((i) => {
361cb0ef41Sopenharmony_ci  assert.throws(() => createTracing(i), {
371cb0ef41Sopenharmony_ci    code: 'ERR_INVALID_ARG_TYPE',
381cb0ef41Sopenharmony_ci    name: 'TypeError'
391cb0ef41Sopenharmony_ci  });
401cb0ef41Sopenharmony_ci  assert.throws(() => createTracing({ categories: i }), {
411cb0ef41Sopenharmony_ci    code: 'ERR_INVALID_ARG_TYPE',
421cb0ef41Sopenharmony_ci    name: 'TypeError'
431cb0ef41Sopenharmony_ci  });
441cb0ef41Sopenharmony_ci});
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ciassert.throws(
471cb0ef41Sopenharmony_ci  () => createTracing({ categories: [] }),
481cb0ef41Sopenharmony_ci  {
491cb0ef41Sopenharmony_ci    code: 'ERR_TRACE_EVENTS_CATEGORY_REQUIRED',
501cb0ef41Sopenharmony_ci    name: 'TypeError'
511cb0ef41Sopenharmony_ci  }
521cb0ef41Sopenharmony_ci);
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ciconst tracing = createTracing({ categories: [ 'node.perf' ] });
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ciassert.strictEqual(tracing.categories, 'node.perf');
571cb0ef41Sopenharmony_ciassert.strictEqual(tracing.enabled, false);
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ciassert.strictEqual(getEnabledCategories(), enabledCategories);
601cb0ef41Sopenharmony_citracing.enable();
611cb0ef41Sopenharmony_citracing.enable();  // Purposefully enable twice to test calling twice
621cb0ef41Sopenharmony_ciassert.strictEqual(tracing.enabled, true);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ciassert.strictEqual(getEnabledCategories(),
651cb0ef41Sopenharmony_ci                   [
661cb0ef41Sopenharmony_ci                     ...[enabledCategories].filter((_) => !!_), 'node.perf',
671cb0ef41Sopenharmony_ci                   ].join(','));
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_citracing.disable();
701cb0ef41Sopenharmony_ciassert.strictEqual(tracing.enabled, false);
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ciconst tracing2 = createTracing({ categories: [ 'foo' ] });
731cb0ef41Sopenharmony_citracing2.enable();
741cb0ef41Sopenharmony_ciassert.strictEqual(getEnabledCategories(), 'foo');
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_citracing2.disable();
771cb0ef41Sopenharmony_citracing2.disable();  // Purposefully disable twice to test calling twice
781cb0ef41Sopenharmony_ciassert.strictEqual(getEnabledCategories(), enabledCategories);
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ciif (isChild) {
811cb0ef41Sopenharmony_ci  const { internalBinding } = require('internal/test/binding');
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  const {
841cb0ef41Sopenharmony_ci    trace: {
851cb0ef41Sopenharmony_ci      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN: kBeforeEvent,
861cb0ef41Sopenharmony_ci      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END: kEndEvent,
871cb0ef41Sopenharmony_ci    }
881cb0ef41Sopenharmony_ci  } = internalBinding('constants');
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  const { trace } = internalBinding('trace_events');
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci  tracing.enable();
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  trace(kBeforeEvent, 'foo', 'test1', 0, 'test');
951cb0ef41Sopenharmony_ci  setTimeout(() => {
961cb0ef41Sopenharmony_ci    trace(kEndEvent, 'foo', 'test1');
971cb0ef41Sopenharmony_ci  }, 1);
981cb0ef41Sopenharmony_ci} else {
991cb0ef41Sopenharmony_ci  // Test that enabled tracing references do not get garbage collected
1001cb0ef41Sopenharmony_ci  // until after they are disabled.
1011cb0ef41Sopenharmony_ci  {
1021cb0ef41Sopenharmony_ci    {
1031cb0ef41Sopenharmony_ci      let tracing3 = createTracing({ categories: [ 'abc' ] });
1041cb0ef41Sopenharmony_ci      tracing3.enable();
1051cb0ef41Sopenharmony_ci      assert.strictEqual(getEnabledCategories(), 'abc');
1061cb0ef41Sopenharmony_ci      tracing3 = undefined;
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci    global.gc();
1091cb0ef41Sopenharmony_ci    assert.strictEqual(getEnabledCategories(), 'abc');
1101cb0ef41Sopenharmony_ci    // Not able to disable the thing after this point, however.
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  {
1141cb0ef41Sopenharmony_ci    common.expectWarning(
1151cb0ef41Sopenharmony_ci      'Warning',
1161cb0ef41Sopenharmony_ci      'Possible trace_events memory leak detected. There are more than ' +
1171cb0ef41Sopenharmony_ci      '10 enabled Tracing objects.');
1181cb0ef41Sopenharmony_ci    for (let n = 0; n < 10; n++) {
1191cb0ef41Sopenharmony_ci      const tracing = createTracing({ categories: [ `a${n}` ] });
1201cb0ef41Sopenharmony_ci      tracing.enable();
1211cb0ef41Sopenharmony_ci    }
1221cb0ef41Sopenharmony_ci  }
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  testApiInChildProcess(['--trace-event-categories', 'foo'], () => {
1251cb0ef41Sopenharmony_ci    testApiInChildProcess(['--trace-event-categories', 'foo']);
1261cb0ef41Sopenharmony_ci  });
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_cifunction testApiInChildProcess(execArgs, cb) {
1301cb0ef41Sopenharmony_ci  tmpdir.refresh();
1311cb0ef41Sopenharmony_ci  // Save the current directory so we can chdir back to it later
1321cb0ef41Sopenharmony_ci  const parentDir = process.cwd();
1331cb0ef41Sopenharmony_ci  process.chdir(tmpdir.path);
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  const expectedBegins = [{ cat: 'foo', name: 'test1' }];
1361cb0ef41Sopenharmony_ci  const expectedEnds = [{ cat: 'foo', name: 'test1' }];
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci  const proc = cp.fork(__filename,
1391cb0ef41Sopenharmony_ci                       ['child'],
1401cb0ef41Sopenharmony_ci                       {
1411cb0ef41Sopenharmony_ci                         execArgv: [
1421cb0ef41Sopenharmony_ci                           '--expose-gc',
1431cb0ef41Sopenharmony_ci                           '--expose-internals',
1441cb0ef41Sopenharmony_ci                           '--no-warnings',
1451cb0ef41Sopenharmony_ci                           ...execArgs,
1461cb0ef41Sopenharmony_ci                         ]
1471cb0ef41Sopenharmony_ci                       });
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  proc.once('exit', common.mustCall(() => {
1501cb0ef41Sopenharmony_ci    const file = path.join(tmpdir.path, 'node_trace.1.log');
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci    assert(fs.existsSync(file));
1531cb0ef41Sopenharmony_ci    fs.readFile(file, common.mustSucceed((data) => {
1541cb0ef41Sopenharmony_ci      const traces = JSON.parse(data.toString()).traceEvents
1551cb0ef41Sopenharmony_ci        .filter((trace) => trace.cat !== '__metadata');
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci      assert.strictEqual(
1581cb0ef41Sopenharmony_ci        traces.length,
1591cb0ef41Sopenharmony_ci        expectedBegins.length + expectedEnds.length);
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci      traces.forEach((trace) => {
1621cb0ef41Sopenharmony_ci        assert.strictEqual(trace.pid, proc.pid);
1631cb0ef41Sopenharmony_ci        switch (trace.ph) {
1641cb0ef41Sopenharmony_ci          case 'b': {
1651cb0ef41Sopenharmony_ci            const expectedBegin = expectedBegins.shift();
1661cb0ef41Sopenharmony_ci            assert.strictEqual(trace.cat, expectedBegin.cat);
1671cb0ef41Sopenharmony_ci            assert.strictEqual(trace.name, expectedBegin.name);
1681cb0ef41Sopenharmony_ci            break;
1691cb0ef41Sopenharmony_ci          }
1701cb0ef41Sopenharmony_ci          case 'e': {
1711cb0ef41Sopenharmony_ci            const expectedEnd = expectedEnds.shift();
1721cb0ef41Sopenharmony_ci            assert.strictEqual(trace.cat, expectedEnd.cat);
1731cb0ef41Sopenharmony_ci            assert.strictEqual(trace.name, expectedEnd.name);
1741cb0ef41Sopenharmony_ci            break;
1751cb0ef41Sopenharmony_ci          }
1761cb0ef41Sopenharmony_ci          default:
1771cb0ef41Sopenharmony_ci            assert.fail('Unexpected trace event phase');
1781cb0ef41Sopenharmony_ci        }
1791cb0ef41Sopenharmony_ci      });
1801cb0ef41Sopenharmony_ci      process.chdir(parentDir);
1811cb0ef41Sopenharmony_ci      cb && process.nextTick(cb);
1821cb0ef41Sopenharmony_ci    }));
1831cb0ef41Sopenharmony_ci  }));
1841cb0ef41Sopenharmony_ci}
185