runTest.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. "use strict";
  2. /*---------------------------------------------------------------------------------------------
  3. * Copyright (c) Microsoft Corporation. All rights reserved.
  4. * Licensed under the MIT License. See License.txt in the project root for license information.
  5. *--------------------------------------------------------------------------------------------*/
  6. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  7. if (k2 === undefined) k2 = k;
  8. var desc = Object.getOwnPropertyDescriptor(m, k);
  9. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  10. desc = { enumerable: true, get: function() { return m[k]; } };
  11. }
  12. Object.defineProperty(o, k2, desc);
  13. }) : (function(o, m, k, k2) {
  14. if (k2 === undefined) k2 = k;
  15. o[k2] = m[k];
  16. }));
  17. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  18. Object.defineProperty(o, "default", { enumerable: true, value: v });
  19. }) : function(o, v) {
  20. o["default"] = v;
  21. });
  22. var __importStar = (this && this.__importStar) || function (mod) {
  23. if (mod && mod.__esModule) return mod;
  24. var result = {};
  25. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  26. __setModuleDefault(result, mod);
  27. return result;
  28. };
  29. Object.defineProperty(exports, "__esModule", { value: true });
  30. exports.TestRunFailedError = void 0;
  31. exports.runTests = runTests;
  32. const cp = __importStar(require("child_process"));
  33. const download_1 = require("./download");
  34. const util_1 = require("./util");
  35. /**
  36. * Run VS Code extension test
  37. *
  38. * @returns The exit code of the command to launch VS Code extension test
  39. */
  40. async function runTests(options) {
  41. if (!options.vscodeExecutablePath) {
  42. options.vscodeExecutablePath = await (0, download_1.downloadAndUnzipVSCode)(options);
  43. }
  44. let args = [
  45. // https://github.com/microsoft/vscode/issues/84238
  46. '--no-sandbox',
  47. // https://github.com/microsoft/vscode-test/issues/221
  48. '--disable-gpu-sandbox',
  49. // https://github.com/microsoft/vscode-test/issues/120
  50. '--disable-updates',
  51. '--skip-welcome',
  52. '--skip-release-notes',
  53. '--disable-workspace-trust',
  54. '--extensionTestsPath=' + options.extensionTestsPath,
  55. ];
  56. if (Array.isArray(options.extensionDevelopmentPath)) {
  57. args.push(...options.extensionDevelopmentPath.map((devPath) => `--extensionDevelopmentPath=${devPath}`));
  58. }
  59. else {
  60. args.push(`--extensionDevelopmentPath=${options.extensionDevelopmentPath}`);
  61. }
  62. if (options.launchArgs) {
  63. args = options.launchArgs.concat(args);
  64. }
  65. if (!options.reuseMachineInstall) {
  66. args.push(...(0, util_1.getProfileArguments)(args));
  67. }
  68. return innerRunTests(options.vscodeExecutablePath, args, options.extensionTestsEnv);
  69. }
  70. const SIGINT = 'SIGINT';
  71. async function innerRunTests(executable, args, testRunnerEnv) {
  72. const fullEnv = Object.assign({}, process.env, testRunnerEnv);
  73. const shell = process.platform === 'win32';
  74. const cmd = cp.spawn(shell ? `"${executable}"` : executable, args, { env: fullEnv, shell });
  75. let exitRequested = false;
  76. const ctrlc1 = () => {
  77. process.removeListener(SIGINT, ctrlc1);
  78. process.on(SIGINT, ctrlc2);
  79. console.log('Closing VS Code gracefully. Press Ctrl+C to force close.');
  80. exitRequested = true;
  81. cmd.kill(SIGINT); // this should cause the returned promise to resolve
  82. };
  83. const ctrlc2 = () => {
  84. console.log('Closing VS Code forcefully.');
  85. process.removeListener(SIGINT, ctrlc2);
  86. exitRequested = true;
  87. (0, util_1.killTree)(cmd.pid, true);
  88. };
  89. const prom = new Promise((resolve, reject) => {
  90. if (cmd.pid) {
  91. process.on(SIGINT, ctrlc1);
  92. }
  93. cmd.stdout.on('data', (d) => process.stdout.write(d));
  94. cmd.stderr.on('data', (d) => process.stderr.write(d));
  95. cmd.on('error', function (data) {
  96. console.log('Test error: ' + data.toString());
  97. });
  98. let finished = false;
  99. function onProcessClosed(code, signal) {
  100. if (finished) {
  101. return;
  102. }
  103. finished = true;
  104. console.log(`Exit code: ${code ?? signal}`);
  105. // fix: on windows, it seems like these descriptors can linger for an
  106. // indeterminate amount of time, causing the process to hang.
  107. cmd.stdout.destroy();
  108. cmd.stderr.destroy();
  109. if (code !== 0) {
  110. reject(new TestRunFailedError(code ?? undefined, signal ?? undefined));
  111. }
  112. else {
  113. resolve(0);
  114. }
  115. }
  116. cmd.on('close', onProcessClosed);
  117. cmd.on('exit', onProcessClosed);
  118. });
  119. let code;
  120. try {
  121. code = await prom;
  122. }
  123. finally {
  124. process.removeListener(SIGINT, ctrlc1);
  125. process.removeListener(SIGINT, ctrlc2);
  126. }
  127. // exit immediately if we handled a SIGINT and no one else did
  128. if (exitRequested && process.listenerCount(SIGINT) === 0) {
  129. process.exit(1);
  130. }
  131. return code;
  132. }
  133. class TestRunFailedError extends Error {
  134. constructor(code, signal) {
  135. super(signal ? `Test run terminated with signal ${signal}` : `Test run failed with code ${code}`);
  136. this.code = code;
  137. this.signal = signal;
  138. }
  139. }
  140. exports.TestRunFailedError = TestRunFailedError;