11cb0ef41Sopenharmony_ci#!/usr/bin/env node
21cb0ef41Sopenharmony_ci/**
31cb0ef41Sopenharmony_ci * Usage:
41cb0ef41Sopenharmony_ci *   test-npm-package.js [--install] [--rebuild] <source> <test-arg>+
51cb0ef41Sopenharmony_ci *
61cb0ef41Sopenharmony_ci * Everything after the <source> directory gets passed to `npm run` to build
71cb0ef41Sopenharmony_ci * the test command.
81cb0ef41Sopenharmony_ci *
91cb0ef41Sopenharmony_ci * If `--install` is passed, we'll run a full `npm install` before running the
101cb0ef41Sopenharmony_ci * test suite. Same for `--rebuild` and `npm rebuild`.
111cb0ef41Sopenharmony_ci *
121cb0ef41Sopenharmony_ci * We always use the node used to spawn this script and the `npm` version
131cb0ef41Sopenharmony_ci * bundled in `deps/npm`.
141cb0ef41Sopenharmony_ci *
151cb0ef41Sopenharmony_ci * If an additional `--logfile=<filename>` option is passed before `<source>`,
161cb0ef41Sopenharmony_ci * the stdout output of the test script will be written to that file.
171cb0ef41Sopenharmony_ci */
181cb0ef41Sopenharmony_ci'use strict';
191cb0ef41Sopenharmony_ciconst { spawn, spawnSync } = require('child_process');
201cb0ef41Sopenharmony_ciconst { createHash } = require('crypto');
211cb0ef41Sopenharmony_ciconst { createWriteStream, mkdirSync, rmdirSync } = require('fs');
221cb0ef41Sopenharmony_ciconst path = require('path');
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciconst common = require('../test/common');
251cb0ef41Sopenharmony_ciconst tmpDir = require('../test/common/tmpdir');
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciconst projectDir = path.resolve(__dirname, '..');
281cb0ef41Sopenharmony_ciconst npmBin = path.join(projectDir, 'deps', 'npm', 'bin', 'npm-cli.js');
291cb0ef41Sopenharmony_ciconst nodePath = path.dirname(process.execPath);
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_cifunction spawnCopyDeepSync(source, destination) {
321cb0ef41Sopenharmony_ci  if (common.isWindows) {
331cb0ef41Sopenharmony_ci    mkdirSync(destination); // Prevent interactive prompt
341cb0ef41Sopenharmony_ci    return spawnSync('xcopy.exe', ['/E', source, destination]);
351cb0ef41Sopenharmony_ci  }
361cb0ef41Sopenharmony_ci  return spawnSync('cp', ['-r', `${source}/`, destination]);
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_cifunction runNPMPackageTests({ srcDir, install, rebuild, testArgs, logfile }) {
401cb0ef41Sopenharmony_ci  // Make sure we don't conflict with concurrent test runs
411cb0ef41Sopenharmony_ci  const srcHash = createHash('md5').update(srcDir).digest('hex');
421cb0ef41Sopenharmony_ci  tmpDir.path = `${tmpDir.path}.npm.${srcHash}`;
431cb0ef41Sopenharmony_ci  tmpDir.refresh();
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  const npmCache = path.join(tmpDir.path, 'npm-cache');
461cb0ef41Sopenharmony_ci  const npmPrefix = path.join(tmpDir.path, 'npm-prefix');
471cb0ef41Sopenharmony_ci  const npmTmp = path.join(tmpDir.path, 'npm-tmp');
481cb0ef41Sopenharmony_ci  const npmUserconfig = path.join(tmpDir.path, 'npm-userconfig');
491cb0ef41Sopenharmony_ci  const pkgDir = path.join(tmpDir.path, 'pkg');
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ci  spawnCopyDeepSync(srcDir, pkgDir);
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  const npmOptions = {
541cb0ef41Sopenharmony_ci    cwd: pkgDir,
551cb0ef41Sopenharmony_ci    env: Object.assign({}, process.env, {
561cb0ef41Sopenharmony_ci      'npm_config_cache': npmCache,
571cb0ef41Sopenharmony_ci      'npm_config_prefix': npmPrefix,
581cb0ef41Sopenharmony_ci      'npm_config_tmp': npmTmp,
591cb0ef41Sopenharmony_ci      'npm_config_userconfig': npmUserconfig,
601cb0ef41Sopenharmony_ci    }),
611cb0ef41Sopenharmony_ci    stdio: 'inherit',
621cb0ef41Sopenharmony_ci  };
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  if (common.isWindows) {
651cb0ef41Sopenharmony_ci    npmOptions.env.home = tmpDir.path;
661cb0ef41Sopenharmony_ci    npmOptions.env.Path = `${nodePath};${process.env.Path}`;
671cb0ef41Sopenharmony_ci  } else {
681cb0ef41Sopenharmony_ci    npmOptions.env.HOME = tmpDir.path;
691cb0ef41Sopenharmony_ci    npmOptions.env.PATH = `${nodePath}:${process.env.PATH}`;
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  if (rebuild) {
731cb0ef41Sopenharmony_ci    spawnSync(process.execPath, [
741cb0ef41Sopenharmony_ci      npmBin,
751cb0ef41Sopenharmony_ci      'rebuild',
761cb0ef41Sopenharmony_ci    ], npmOptions);
771cb0ef41Sopenharmony_ci  }
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci  if (install) {
801cb0ef41Sopenharmony_ci    spawnSync(process.execPath, [
811cb0ef41Sopenharmony_ci      npmBin,
821cb0ef41Sopenharmony_ci      'install',
831cb0ef41Sopenharmony_ci      '--ignore-scripts',
841cb0ef41Sopenharmony_ci      '--no-save',
851cb0ef41Sopenharmony_ci    ], npmOptions);
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  const testChild = spawn(process.execPath, [
891cb0ef41Sopenharmony_ci    npmBin,
901cb0ef41Sopenharmony_ci    '--silent',
911cb0ef41Sopenharmony_ci    'run',
921cb0ef41Sopenharmony_ci    ...testArgs,
931cb0ef41Sopenharmony_ci  ], Object.assign({}, npmOptions, { stdio: 'pipe' }));
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  testChild.stdout.pipe(process.stdout);
961cb0ef41Sopenharmony_ci  testChild.stderr.pipe(process.stderr);
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci  if (logfile) {
991cb0ef41Sopenharmony_ci    const logStream = createWriteStream(logfile);
1001cb0ef41Sopenharmony_ci    testChild.stdout.pipe(logStream);
1011cb0ef41Sopenharmony_ci  }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  testChild.on('exit', () => {
1041cb0ef41Sopenharmony_ci    tmpDir.refresh();
1051cb0ef41Sopenharmony_ci    rmdirSync(tmpDir.path);
1061cb0ef41Sopenharmony_ci  });
1071cb0ef41Sopenharmony_ci}
1081cb0ef41Sopenharmony_ci
1091cb0ef41Sopenharmony_cifunction parseArgs(args) {
1101cb0ef41Sopenharmony_ci  let srcDir;
1111cb0ef41Sopenharmony_ci  let rebuild = false;
1121cb0ef41Sopenharmony_ci  let install = false;
1131cb0ef41Sopenharmony_ci  let logfile = null;
1141cb0ef41Sopenharmony_ci  const testArgs = [];
1151cb0ef41Sopenharmony_ci  args.forEach((arg) => {
1161cb0ef41Sopenharmony_ci    if (srcDir) {
1171cb0ef41Sopenharmony_ci      testArgs.push(arg);
1181cb0ef41Sopenharmony_ci      return;
1191cb0ef41Sopenharmony_ci    }
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci    if (arg === '--install') {
1221cb0ef41Sopenharmony_ci      install = true;
1231cb0ef41Sopenharmony_ci    } else if (arg === '--rebuild') {
1241cb0ef41Sopenharmony_ci      rebuild = true;
1251cb0ef41Sopenharmony_ci    } else if (arg[0] !== '-') {
1261cb0ef41Sopenharmony_ci      srcDir = path.resolve(projectDir, arg);
1271cb0ef41Sopenharmony_ci    } else if (arg.startsWith('--logfile=')) {
1281cb0ef41Sopenharmony_ci      logfile = path.resolve(projectDir, arg.slice('--logfile='.length));
1291cb0ef41Sopenharmony_ci    } else {
1301cb0ef41Sopenharmony_ci      throw new Error(`Unrecognized option ${arg}`);
1311cb0ef41Sopenharmony_ci    }
1321cb0ef41Sopenharmony_ci  });
1331cb0ef41Sopenharmony_ci  if (!srcDir) {
1341cb0ef41Sopenharmony_ci    throw new Error('Expected a source directory');
1351cb0ef41Sopenharmony_ci  }
1361cb0ef41Sopenharmony_ci  return { srcDir, install, rebuild, testArgs, logfile };
1371cb0ef41Sopenharmony_ci}
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_cirunNPMPackageTests(parseArgs(process.argv.slice(2)));
140