11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst assert = require('assert');
51cb0ef41Sopenharmony_ciconst { execFile, execFileSync } = require('child_process');
61cb0ef41Sopenharmony_ciconst { getEventListeners } = require('events');
71cb0ef41Sopenharmony_ciconst { getSystemErrorName } = require('util');
81cb0ef41Sopenharmony_ciconst fixtures = require('../common/fixtures');
91cb0ef41Sopenharmony_ciconst os = require('os');
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ciconst fixture = fixtures.path('exit.js');
121cb0ef41Sopenharmony_ciconst echoFixture = fixtures.path('echo.js');
131cb0ef41Sopenharmony_ciconst execOpts = { encoding: 'utf8', shell: true };
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci{
161cb0ef41Sopenharmony_ci  execFile(
171cb0ef41Sopenharmony_ci    process.execPath,
181cb0ef41Sopenharmony_ci    [fixture, 42],
191cb0ef41Sopenharmony_ci    common.mustCall((e) => {
201cb0ef41Sopenharmony_ci      // Check that arguments are included in message
211cb0ef41Sopenharmony_ci      assert.strictEqual(e.message.trim(),
221cb0ef41Sopenharmony_ci                         `Command failed: ${process.execPath} ${fixture} 42`);
231cb0ef41Sopenharmony_ci      assert.strictEqual(e.code, 42);
241cb0ef41Sopenharmony_ci    })
251cb0ef41Sopenharmony_ci  );
261cb0ef41Sopenharmony_ci}
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci{
291cb0ef41Sopenharmony_ci  // Verify that negative exit codes can be translated to UV error names.
301cb0ef41Sopenharmony_ci  const errorString = `Error: Command failed: ${process.execPath}`;
311cb0ef41Sopenharmony_ci  const code = -1;
321cb0ef41Sopenharmony_ci  const callback = common.mustCall((err, stdout, stderr) => {
331cb0ef41Sopenharmony_ci    assert.strictEqual(err.toString().trim(), errorString);
341cb0ef41Sopenharmony_ci    assert.strictEqual(err.code, getSystemErrorName(code));
351cb0ef41Sopenharmony_ci    assert.strictEqual(err.killed, true);
361cb0ef41Sopenharmony_ci    assert.strictEqual(err.signal, null);
371cb0ef41Sopenharmony_ci    assert.strictEqual(err.cmd, process.execPath);
381cb0ef41Sopenharmony_ci    assert.strictEqual(stdout.trim(), '');
391cb0ef41Sopenharmony_ci    assert.strictEqual(stderr.trim(), '');
401cb0ef41Sopenharmony_ci  });
411cb0ef41Sopenharmony_ci  const child = execFile(process.execPath, callback);
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  child.kill();
441cb0ef41Sopenharmony_ci  child.emit('close', code, null);
451cb0ef41Sopenharmony_ci}
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci{
481cb0ef41Sopenharmony_ci  // Verify the shell option works properly
491cb0ef41Sopenharmony_ci  execFile(process.execPath, [fixture, 0], execOpts, common.mustSucceed());
501cb0ef41Sopenharmony_ci}
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci{
531cb0ef41Sopenharmony_ci  // Verify that the signal option works properly
541cb0ef41Sopenharmony_ci  const ac = new AbortController();
551cb0ef41Sopenharmony_ci  const { signal } = ac;
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  const test = () => {
581cb0ef41Sopenharmony_ci    const check = common.mustCall((err) => {
591cb0ef41Sopenharmony_ci      assert.strictEqual(err.code, 'ABORT_ERR');
601cb0ef41Sopenharmony_ci      assert.strictEqual(err.name, 'AbortError');
611cb0ef41Sopenharmony_ci      assert.strictEqual(err.signal, undefined);
621cb0ef41Sopenharmony_ci    });
631cb0ef41Sopenharmony_ci    execFile(process.execPath, [echoFixture, 0], { signal }, check);
641cb0ef41Sopenharmony_ci  };
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci  // Verify that it still works the same way now that the signal is aborted.
671cb0ef41Sopenharmony_ci  test();
681cb0ef41Sopenharmony_ci  ac.abort();
691cb0ef41Sopenharmony_ci}
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci{
721cb0ef41Sopenharmony_ci  // Verify that does not spawn a child if already aborted
731cb0ef41Sopenharmony_ci  const signal = AbortSignal.abort();
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  const check = common.mustCall((err) => {
761cb0ef41Sopenharmony_ci    assert.strictEqual(err.code, 'ABORT_ERR');
771cb0ef41Sopenharmony_ci    assert.strictEqual(err.name, 'AbortError');
781cb0ef41Sopenharmony_ci    assert.strictEqual(err.signal, undefined);
791cb0ef41Sopenharmony_ci  });
801cb0ef41Sopenharmony_ci  execFile(process.execPath, [echoFixture, 0], { signal }, check);
811cb0ef41Sopenharmony_ci}
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci{
841cb0ef41Sopenharmony_ci  // Verify that if something different than Abortcontroller.signal
851cb0ef41Sopenharmony_ci  // is passed, ERR_INVALID_ARG_TYPE is thrown
861cb0ef41Sopenharmony_ci  assert.throws(() => {
871cb0ef41Sopenharmony_ci    const callback = common.mustNotCall();
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    execFile(process.execPath, [echoFixture, 0], { signal: 'hello' }, callback);
901cb0ef41Sopenharmony_ci  }, { code: 'ERR_INVALID_ARG_TYPE', name: 'TypeError' });
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci{
931cb0ef41Sopenharmony_ci  // Verify that the process completing removes the abort listener
941cb0ef41Sopenharmony_ci  const ac = new AbortController();
951cb0ef41Sopenharmony_ci  const { signal } = ac;
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  const callback = common.mustCall((err) => {
981cb0ef41Sopenharmony_ci    assert.strictEqual(getEventListeners(ac.signal).length, 0);
991cb0ef41Sopenharmony_ci    assert.strictEqual(err, null);
1001cb0ef41Sopenharmony_ci  });
1011cb0ef41Sopenharmony_ci  execFile(process.execPath, [fixture, 0], { signal }, callback);
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci// Verify the execFile() stdout is the same as execFileSync().
1051cb0ef41Sopenharmony_ci{
1061cb0ef41Sopenharmony_ci  const file = 'echo';
1071cb0ef41Sopenharmony_ci  const args = ['foo', 'bar'];
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_ci  // Test with and without `{ shell: true }`
1101cb0ef41Sopenharmony_ci  [
1111cb0ef41Sopenharmony_ci    // Skipping shell-less test on Windows because its echo command is a shell built-in command.
1121cb0ef41Sopenharmony_ci    ...(common.isWindows ? [] : [{ encoding: 'utf8' }]),
1131cb0ef41Sopenharmony_ci    { shell: true, encoding: 'utf8' },
1141cb0ef41Sopenharmony_ci  ].forEach((options) => {
1151cb0ef41Sopenharmony_ci    const execFileSyncStdout = execFileSync(file, args, options);
1161cb0ef41Sopenharmony_ci    assert.strictEqual(execFileSyncStdout, `foo bar${os.EOL}`);
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci    execFile(file, args, options, common.mustCall((_, stdout) => {
1191cb0ef41Sopenharmony_ci      assert.strictEqual(stdout, execFileSyncStdout);
1201cb0ef41Sopenharmony_ci    }));
1211cb0ef41Sopenharmony_ci  });
1221cb0ef41Sopenharmony_ci}
123