11cb0ef41Sopenharmony_ciimport * as common from '../common/index.mjs';
21cb0ef41Sopenharmony_ciimport * as fixtures from '../common/fixtures.mjs';
31cb0ef41Sopenharmony_ciimport assert from 'node:assert';
41cb0ef41Sopenharmony_ciimport { describe, it } from 'node:test';
51cb0ef41Sopenharmony_ciimport { writeFileSync, readFileSync } from 'node:fs';
61cb0ef41Sopenharmony_ciimport { setTimeout } from 'node:timers/promises';
71cb0ef41Sopenharmony_ciimport { NodeInstance } from '../common/inspector-helper.js';
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciif (common.isIBMi)
111cb0ef41Sopenharmony_ci  common.skip('IBMi does not support `fs.watch()`');
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_cicommon.skipIfInspectorDisabled();
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cilet gettingDebuggedPid = false;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciasync function getDebuggedPid(instance, waitForLog = true) {
181cb0ef41Sopenharmony_ci  gettingDebuggedPid = true;
191cb0ef41Sopenharmony_ci  const session = await instance.connectInspectorSession();
201cb0ef41Sopenharmony_ci  await session.send({ method: 'Runtime.enable' });
211cb0ef41Sopenharmony_ci  if (waitForLog) {
221cb0ef41Sopenharmony_ci    await session.waitForConsoleOutput('log', 'safe to debug now');
231cb0ef41Sopenharmony_ci  }
241cb0ef41Sopenharmony_ci  const { value: innerPid } = (await session.send({
251cb0ef41Sopenharmony_ci    'method': 'Runtime.evaluate', 'params': { 'expression': 'process.pid' }
261cb0ef41Sopenharmony_ci  })).result;
271cb0ef41Sopenharmony_ci  session.disconnect();
281cb0ef41Sopenharmony_ci  gettingDebuggedPid = false;
291cb0ef41Sopenharmony_ci  return innerPid;
301cb0ef41Sopenharmony_ci}
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cifunction restart(file) {
331cb0ef41Sopenharmony_ci  writeFileSync(file, readFileSync(file));
341cb0ef41Sopenharmony_ci  const interval = setInterval(() => {
351cb0ef41Sopenharmony_ci    if (!gettingDebuggedPid) {
361cb0ef41Sopenharmony_ci      writeFileSync(file, readFileSync(file));
371cb0ef41Sopenharmony_ci    }
381cb0ef41Sopenharmony_ci  }, common.platformTimeout(500));
391cb0ef41Sopenharmony_ci  return () => clearInterval(interval);
401cb0ef41Sopenharmony_ci}
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_cidescribe('watch mode - inspect', () => {
431cb0ef41Sopenharmony_ci  it('should start debugger on inner process', async () => {
441cb0ef41Sopenharmony_ci    const file = fixtures.path('watch-mode/inspect.js');
451cb0ef41Sopenharmony_ci    const instance = new NodeInstance(['--inspect=0', '--watch'], undefined, file);
461cb0ef41Sopenharmony_ci    let stderr = '';
471cb0ef41Sopenharmony_ci    const stdout = [];
481cb0ef41Sopenharmony_ci    instance.on('stderr', (data) => { stderr += data; });
491cb0ef41Sopenharmony_ci    instance.on('stdout', (data) => { stdout.push(data); });
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci    const pids = [instance.pid];
521cb0ef41Sopenharmony_ci    pids.push(await getDebuggedPid(instance));
531cb0ef41Sopenharmony_ci    instance.resetPort();
541cb0ef41Sopenharmony_ci    const stopRestarting = restart(file);
551cb0ef41Sopenharmony_ci    pids.push(await getDebuggedPid(instance));
561cb0ef41Sopenharmony_ci    stopRestarting();
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci    await setTimeout(common.platformTimeout(500));
591cb0ef41Sopenharmony_ci    await instance.kill();
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci    // There should be a process per restart and one per parent process.
621cb0ef41Sopenharmony_ci    // Message about Debugger should appear once per restart.
631cb0ef41Sopenharmony_ci    // On some systems restart can happen multiple times.
641cb0ef41Sopenharmony_ci    const restarts = stdout.filter((line) => line === 'safe to debug now').length;
651cb0ef41Sopenharmony_ci    assert.ok(stderr.match(/Debugger listening on ws:\/\//g).length >= restarts);
661cb0ef41Sopenharmony_ci    assert.ok(new Set(pids).size >= restarts + 1);
671cb0ef41Sopenharmony_ci  });
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  it('should prevent attaching debugger with SIGUSR1 to outer process', { skip: common.isWindows }, async () => {
701cb0ef41Sopenharmony_ci    const file = fixtures.path('watch-mode/inspect_with_signal.js');
711cb0ef41Sopenharmony_ci    const instance = new NodeInstance(['--inspect-port=0', '--watch'], undefined, file);
721cb0ef41Sopenharmony_ci    let stderr = '';
731cb0ef41Sopenharmony_ci    instance.on('stderr', (data) => { stderr += data; });
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    const loggedPid = await new Promise((resolve) => {
761cb0ef41Sopenharmony_ci      instance.on('stdout', (data) => {
771cb0ef41Sopenharmony_ci        const matches = data.match(/pid is (\d+)/);
781cb0ef41Sopenharmony_ci        if (matches) resolve(Number(matches[1]));
791cb0ef41Sopenharmony_ci      });
801cb0ef41Sopenharmony_ci    });
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci    process.kill(instance.pid, 'SIGUSR1');
841cb0ef41Sopenharmony_ci    process.kill(loggedPid, 'SIGUSR1');
851cb0ef41Sopenharmony_ci    const debuggedPid = await getDebuggedPid(instance, false);
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci    await instance.kill();
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    // Message about Debugger should only appear once in inner process.
901cb0ef41Sopenharmony_ci    assert.strictEqual(stderr.match(/Debugger listening on ws:\/\//g).length, 1);
911cb0ef41Sopenharmony_ci    assert.strictEqual(loggedPid, debuggedPid);
921cb0ef41Sopenharmony_ci  });
931cb0ef41Sopenharmony_ci});
94