diff --git a/src/client/common/process/internal/scripts/index.ts b/src/client/common/process/internal/scripts/index.ts index 7240d7be67f8..f719844ef80b 100644 --- a/src/client/common/process/internal/scripts/index.ts +++ b/src/client/common/process/internal/scripts/index.ts @@ -110,6 +110,13 @@ export function testlauncher(testArgs: string[]): string[] { return [script, ...testArgs]; } +// run_pytest_script.py +export function pytestlauncher(testArgs: string[]): string[] { + const script = path.join(SCRIPTS_DIR, 'vscode_pytest', 'run_pytest_script.py'); + // There is no output to parse, so we do not return a function. + return [script, ...testArgs]; +} + // visualstudio_py_testlauncher.py // eslint-disable-next-line camelcase diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index 5b39bd97a740..af233132768c 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -178,12 +178,7 @@ export class DebugLauncher implements ITestDebugLauncher { const args = script(testArgs); const [program] = args; configArgs.program = program; - // if the test provider is pytest, then use the pytest module instead of using a program - const rewriteTestingEnabled = process.env.ENABLE_PYTHON_TESTING_REWRITE; - if (options.testProvider === 'pytest' && rewriteTestingEnabled) { - configArgs.module = 'pytest'; - configArgs.program = undefined; - } + configArgs.args = args.slice(1); // We leave configArgs.request as "test" so it will be sent in telemetry. @@ -204,12 +199,16 @@ export class DebugLauncher implements ITestDebugLauncher { throw Error(`Invalid debug config "${debugConfig.name}"`); } launchArgs.request = 'launch'; + + // If we are in the pytest rewrite then we must send additional environment variables. + const rewriteTestingEnabled = process.env.ENABLE_PYTHON_TESTING_REWRITE; if (options.testProvider === 'pytest' && rewriteTestingEnabled) { if (options.pytestPort && options.pytestUUID) { launchArgs.env = { ...launchArgs.env, TEST_PORT: options.pytestPort, TEST_UUID: options.pytestUUID, + RUN_TEST_IDS_PORT: options.pytestRunTestIdsPort, }; } else { throw Error( @@ -238,7 +237,7 @@ export class DebugLauncher implements ITestDebugLauncher { } case 'pytest': { if (rewriteTestingEnabled) { - return (testArgs: string[]) => testArgs; + return internalScripts.pytestlauncher; // this is the new way to run pytest execution, debugger } return internalScripts.testlauncher; // old way pytest execution, debugger } diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index a5d263058525..443a2c2ef20e 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -27,6 +27,7 @@ export type LaunchOptions = { outChannel?: OutputChannel; pytestPort?: string; pytestUUID?: string; + pytestRunTestIdsPort?: string; }; export type ParserOptions = TestDiscoveryOptions; diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 4c6dcd9cdbee..39b7f8c787b9 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as net from 'net'; import { IConfigurationService, ITestOutputChannel } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; -import { traceLog, traceVerbose } from '../../../logging'; +import { traceError, traceLog, traceVerbose } from '../../../logging'; import { DataReceivedEvent, ExecutionTestPayload, ITestExecutionAdapter, ITestServer } from '../common/types'; import { ExecutionFactoryCreateWithEnvironmentOptions, @@ -112,18 +112,16 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { testArgs.splice(0, 0, '--rootdir', uri.fsPath); } - // why is this needed? if (debugBool && !testArgs.some((a) => a.startsWith('--capture') || a === '-s')) { testArgs.push('--capture', 'no'); } - const pluginArgs = ['-p', 'vscode_pytest'].concat(testArgs).concat(testIds); - const scriptPath = path.join(fullPluginPath, 'vscode_pytest', 'run_pytest_script.py'); - const runArgs = [scriptPath, ...testArgs]; + // create payload with testIds to send to run pytest script const testData = JSON.stringify(testIds); const headers = [`Content-Length: ${Buffer.byteLength(testData)}`, 'Content-Type: application/json']; const payload = `${headers.join('\r\n')}\r\n\r\n${testData}`; + let pytestRunTestIdsPort: string | undefined; const startServer = (): Promise => new Promise((resolve, reject) => { const server = net.createServer((socket: net.Socket) => { @@ -151,11 +149,12 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { await startServer() .then((assignedPort) => { traceLog(`Server started and listening on port ${assignedPort}`); + pytestRunTestIdsPort = assignedPort.toString(); if (spawnOptions.extraVariables) - spawnOptions.extraVariables.RUN_TEST_IDS_PORT = assignedPort.toString(); + spawnOptions.extraVariables.RUN_TEST_IDS_PORT = pytestRunTestIdsPort; }) .catch((error) => { - console.error('Error starting server:', error); + traceError('Error starting server:', error); }); if (debugBool) { @@ -163,22 +162,27 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { const pytestUUID = uuid.toString(); const launchOptions: LaunchOptions = { cwd: uri.fsPath, - args: pluginArgs, + args: testArgs, token: spawnOptions.token, testProvider: PYTEST_PROVIDER, pytestPort, pytestUUID, + pytestRunTestIdsPort, }; - console.debug(`Running debug test with arguments: ${pluginArgs.join(' ')}\r\n`); + traceVerbose(`Running debug test with arguments: ${testArgs.join(' ')}\r\n`); await debugLauncher!.launchDebugger(launchOptions); } else { + // combine path to run script with run args + const scriptPath = path.join(fullPluginPath, 'vscode_pytest', 'run_pytest_script.py'); + const runArgs = [scriptPath, ...testArgs]; + await execService?.exec(runArgs, spawnOptions).catch((ex) => { - console.debug(`Error while running tests: ${testIds}\r\n${ex}\r\n\r\n`); + traceError(`Error while running tests: ${testIds}\r\n${ex}\r\n\r\n`); return Promise.reject(ex); }); } } catch (ex) { - console.debug(`Error while running tests: ${testIds}\r\n${ex}\r\n\r\n`); + traceVerbose(`Error while running tests: ${testIds}\r\n${ex}\r\n\r\n`); return Promise.reject(ex); }