From 7a12250ed02a5d23dd663c9e8149d678b6cf5682 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Fri, 7 Jun 2024 13:04:05 -0700 Subject: [PATCH 01/11] add proposed api --- package.json | 3 ++- types/vscode.proposed.testRunInDebug.d.ts | 17 +++++++++++++++++ vscode.proposed.testRunInDebug.d.ts | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 types/vscode.proposed.testRunInDebug.d.ts create mode 100644 vscode.proposed.testRunInDebug.d.ts diff --git a/package.json b/package.json index 0b2def5937f6..1cb7f9d0d835 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "terminalDataWriteEvent", "terminalExecuteCommandEvent", "contribIssueReporter", - "terminalShellIntegration" + "terminalShellIntegration", + "testRunInDebug" ], "author": { "name": "Microsoft Corporation" diff --git a/types/vscode.proposed.testRunInDebug.d.ts b/types/vscode.proposed.testRunInDebug.d.ts new file mode 100644 index 000000000000..8e3d011e7093 --- /dev/null +++ b/types/vscode.proposed.testRunInDebug.d.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + // https://github.com/microsoft/vscode/issues/214486 + + export interface DebugSessionOptions { + /** + * Signals to the editor that the debug session was started from a test run + * request. This is used to link the lifecycle of the debug session and + * test run in UI actions. + */ + testRun?: TestRun; + } +} diff --git a/vscode.proposed.testRunInDebug.d.ts b/vscode.proposed.testRunInDebug.d.ts new file mode 100644 index 000000000000..8eb273e2a5e3 --- /dev/null +++ b/vscode.proposed.testRunInDebug.d.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode' { + + // https://github.com/microsoft/vscode/issues/214486 + + export interface DebugSessionOptions { + /** + * Signals to the editor that the debug session was started from a test run + * request. This is used to link the lifecycle of the debug session and + * test run in UI actions. + */ + testRun?: TestRun; + } +} From d7aa219e5be1ef7934920e0ebcd7ee99344a3ca2 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 13 Jun 2024 07:35:20 -0700 Subject: [PATCH 02/11] adopt proposed API for test debug restart --- src/client/testing/common/debugLauncher.ts | 16 +++++++++++++--- src/client/testing/common/types.ts | 4 ++-- .../pytest/pytestExecutionAdapter.ts | 12 ++++++++---- .../unittest/testExecutionAdapter.ts | 12 ++++++++---- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index aef1a9fd9197..750719281fd0 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -1,6 +1,6 @@ import { inject, injectable, named } from 'inversify'; import * as path from 'path'; -import { DebugConfiguration, l10n, Uri, WorkspaceFolder } from 'vscode'; +import { DebugConfiguration, l10n, Uri, WorkspaceFolder, DebugSessionOptions, TestRun } from 'vscode'; import { IApplicationShell, IDebugService } from '../../common/application/types'; import { EXTENSION_ROOT_DIR } from '../../common/constants'; import * as internalScripts from '../../common/process/internal/scripts'; @@ -32,7 +32,7 @@ export class DebugLauncher implements ITestDebugLauncher { this.configService = this.serviceContainer.get(IConfigurationService); } - public async launchDebugger(options: LaunchOptions, callback?: () => void): Promise { + public async launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise { const deferred = createDeferred(); if (options.token && options.token.isCancellationRequested) { return undefined; @@ -52,7 +52,17 @@ export class DebugLauncher implements ITestDebugLauncher { deferred.resolve(); callback?.(); }); - debugManager.startDebugging(workspaceFolder, launchArgs); + + const debugSessionOptions: DebugSessionOptions = { + testRun: runInstance, + }; + + debugManager.startDebugging(workspaceFolder, launchArgs, debugSessionOptions); + + debugManager.onDidTerminateDebugSession(() => { + deferred.resolve(); + callback?.(); + }); return deferred.promise; } diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 29a6de7768cb..0074bbc77be8 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -1,4 +1,4 @@ -import { CancellationToken, Disposable, OutputChannel, Uri } from 'vscode'; +import { CancellationToken, Disposable, OutputChannel, TestRun, Uri } from 'vscode'; import { Product } from '../../common/types'; import { TestSettingsPropertyNames } from '../configuration/types'; import { TestProvider } from '../types'; @@ -88,7 +88,7 @@ export interface ITestConfigurationManagerFactory { } export const ITestDebugLauncher = Symbol('ITestDebugLauncher'); export interface ITestDebugLauncher { - launchDebugger(options: LaunchOptions, callback?: () => void): Promise; + launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise; } export const IUnitTestSocketServer = Symbol('IUnitTestSocketServer'); diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 5099efde179c..777244fbc5ad 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -166,10 +166,14 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { pytestPort: resultNamedPipeName, }; traceInfo(`Running DEBUG pytest with arguments: ${testArgs} for workspace ${uri.fsPath} \r\n`); - await debugLauncher!.launchDebugger(launchOptions, () => { - serverDispose(); // this will resolve deferredTillServerClose - deferredTillEOT?.resolve(); - }); + await debugLauncher!.launchDebugger( + launchOptions, + () => { + serverDispose(); // this will resolve deferredTillServerClose + deferredTillEOT?.resolve(); + }, + runInstance, + ); } else { // deferredTillExecClose is resolved when all stdout and stderr is read const deferredTillExecClose: Deferred = utils.createTestingDeferred(); diff --git a/src/client/testing/testController/unittest/testExecutionAdapter.ts b/src/client/testing/testController/unittest/testExecutionAdapter.ts index 4746c3101752..4c632a32d834 100644 --- a/src/client/testing/testController/unittest/testExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/testExecutionAdapter.ts @@ -176,10 +176,14 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { traceError('Debug launcher is not defined'); throw new Error('Debug launcher is not defined'); } - await debugLauncher.launchDebugger(launchOptions, () => { - serverDispose(); // this will resolve the deferredTillAllServerClose - deferredTillEOT?.resolve(); - }); + await debugLauncher.launchDebugger( + launchOptions, + () => { + serverDispose(); // this will resolve the deferredTillAllServerClose + deferredTillEOT?.resolve(); + }, + runInstance, + ); } else { // This means it is running the test traceInfo(`Running unittests for workspace ${cwd} with arguments: ${args}\r\n`); From e72f905445ebc20abe8d865c617adb1651edaf50 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Mon, 1 Jul 2024 10:05:11 -0700 Subject: [PATCH 03/11] more changes --- src/client/testing/common/debugLauncher.ts | 20 ++++++++++++------- .../testing/testController/controller.ts | 7 +++++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index 750719281fd0..eb81cb87f053 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -34,11 +34,19 @@ export class DebugLauncher implements ITestDebugLauncher { public async launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise { const deferred = createDeferred(); + console.log('launch debugger', runInstance?.name); if (options.token && options.token.isCancellationRequested) { return undefined; deferred.resolve(); callback?.(); } + let callbackCalled = false; + options.token?.onCancellationRequested(() => { + console.log('onCancellationRequested', runInstance?.name); + deferred.resolve(); + callback?.(); + callbackCalled = true; + }); const workspaceFolder = DebugLauncher.resolveWorkspaceFolder(options.cwd); const launchArgs = await this.getLaunchArgs( @@ -48,11 +56,6 @@ export class DebugLauncher implements ITestDebugLauncher { ); const debugManager = this.serviceContainer.get(IDebugService); - debugManager.onDidTerminateDebugSession(() => { - deferred.resolve(); - callback?.(); - }); - const debugSessionOptions: DebugSessionOptions = { testRun: runInstance, }; @@ -60,8 +63,11 @@ export class DebugLauncher implements ITestDebugLauncher { debugManager.startDebugging(workspaceFolder, launchArgs, debugSessionOptions); debugManager.onDidTerminateDebugSession(() => { - deferred.resolve(); - callback?.(); + console.log('onDidTerminateDebugSession :', runInstance?.name); + if (!callbackCalled) { + deferred.resolve(); + callback?.(); + } }); return deferred.promise; } diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index b55eaa446018..e913c5820169 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -373,12 +373,14 @@ export class PythonTestController implements ITestController, IExtensionSingleAc } else { (this.workspaceService.workspaceFolders || []).forEach((w) => workspaces.push(w)); } + // generate random number + const random = Math.floor(Math.random() * 1000); const runInstance = this.testController.createTestRun( request, - `Running Tests for Workspace(s): ${workspaces.map((w) => w.uri.fsPath).join(';')}`, + `Running Tests for Workspace(s): ${workspaces.map((w) => w.uri.fsPath).join(';')} random: ${random}`, true, ); - + console.log('created run isntance', runInstance?.name); const dispose = token.onCancellationRequested(() => { runInstance.appendOutput(`\nRun instance cancelled.\r\n`); runInstance.end(); @@ -480,6 +482,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc ); } finally { traceVerbose('Finished running tests, ending runInstance.'); + console.log('end run instance', runInstance?.name); runInstance.appendOutput(`Finished running tests!\r\n`); runInstance.end(); dispose.dispose(); From fe8395930d1b27e5002b4992a08c2abf8b45938c Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Mon, 15 Jul 2024 13:06:49 -0700 Subject: [PATCH 04/11] logging --- src/client/testing/common/debugLauncher.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index eb81cb87f053..e0adf2ec257e 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -65,6 +65,7 @@ export class DebugLauncher implements ITestDebugLauncher { debugManager.onDidTerminateDebugSession(() => { console.log('onDidTerminateDebugSession :', runInstance?.name); if (!callbackCalled) { + console.log('onDidTerminateDebugSession :', runInstance?.name, 'resolve'); deferred.resolve(); callback?.(); } From 4b8f8a576971ee54e3d7a085a2dc7e1ad24999e6 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Tue, 30 Jul 2024 15:09:38 -0700 Subject: [PATCH 05/11] change to save active debug sessions --- src/client/testing/common/debugLauncher.ts | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index e0adf2ec257e..cde19586eb83 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -1,6 +1,6 @@ import { inject, injectable, named } from 'inversify'; import * as path from 'path'; -import { DebugConfiguration, l10n, Uri, WorkspaceFolder, DebugSessionOptions, TestRun } from 'vscode'; +import { DebugConfiguration, l10n, Uri, WorkspaceFolder, DebugSessionOptions, TestRun, DebugSession } from 'vscode'; import { IApplicationShell, IDebugService } from '../../common/application/types'; import { EXTENSION_ROOT_DIR } from '../../common/constants'; import * as internalScripts from '../../common/process/internal/scripts'; @@ -9,7 +9,7 @@ import { DebuggerTypeName, PythonDebuggerTypeName } from '../../debugger/constan import { IDebugConfigurationResolver } from '../../debugger/extension/configuration/types'; import { DebugPurpose, LaunchRequestArguments } from '../../debugger/types'; import { IServiceContainer } from '../../ioc/types'; -import { traceError } from '../../logging'; +import { traceError, traceVerbose } from '../../logging'; import { TestProvider } from '../types'; import { ITestDebugLauncher, LaunchOptions } from './types'; import { getConfigurationsForWorkspace } from '../../debugger/extension/configuration/launch.json/launchJsonReader'; @@ -35,17 +35,19 @@ export class DebugLauncher implements ITestDebugLauncher { public async launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise { const deferred = createDeferred(); console.log('launch debugger', runInstance?.name); + let hasCallbackBeenCalled = false; if (options.token && options.token.isCancellationRequested) { + hasCallbackBeenCalled = true; return undefined; deferred.resolve(); callback?.(); } - let callbackCalled = false; + options.token?.onCancellationRequested(() => { console.log('onCancellationRequested', runInstance?.name); deferred.resolve(); callback?.(); - callbackCalled = true; + hasCallbackBeenCalled = true; }); const workspaceFolder = DebugLauncher.resolveWorkspaceFolder(options.cwd); @@ -60,12 +62,21 @@ export class DebugLauncher implements ITestDebugLauncher { testRun: runInstance, }; - debugManager.startDebugging(workspaceFolder, launchArgs, debugSessionOptions); + let activatedDebugSession: DebugSession | undefined; + debugManager.startDebugging(workspaceFolder, launchArgs, debugSessionOptions).then(() => { + traceVerbose(`Debug session started. runInstance: ${runInstance?.name}`); + // Save the debug session after it is started so we can check if it is the one that was terminated. + activatedDebugSession = debugManager.activeDebugSession; + }); - debugManager.onDidTerminateDebugSession(() => { - console.log('onDidTerminateDebugSession :', runInstance?.name); - if (!callbackCalled) { - console.log('onDidTerminateDebugSession :', runInstance?.name, 'resolve'); + debugManager.onDidTerminateDebugSession((session) => { + traceVerbose(`Debug session terminated. sessionId: ${session.id}, runInstance: ${runInstance?.name}`); + // Only resolve no callback has been made and the session is the one that was started. + if ( + !hasCallbackBeenCalled && + activatedDebugSession !== undefined && + session.id === activatedDebugSession?.id + ) { deferred.resolve(); callback?.(); } From 20027343d69d94e0737e0c025969f7de74ac0be3 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Tue, 30 Jul 2024 15:20:13 -0700 Subject: [PATCH 06/11] remove proposed distinction --- package.json | 3 +-- types/vscode.proposed.testRunInDebug.d.ts | 17 ----------------- vscode.proposed.testRunInDebug.d.ts | 18 ------------------ 3 files changed, 1 insertion(+), 37 deletions(-) delete mode 100644 types/vscode.proposed.testRunInDebug.d.ts delete mode 100644 vscode.proposed.testRunInDebug.d.ts diff --git a/package.json b/package.json index 1cb7f9d0d835..0b2def5937f6 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "terminalDataWriteEvent", "terminalExecuteCommandEvent", "contribIssueReporter", - "terminalShellIntegration", - "testRunInDebug" + "terminalShellIntegration" ], "author": { "name": "Microsoft Corporation" diff --git a/types/vscode.proposed.testRunInDebug.d.ts b/types/vscode.proposed.testRunInDebug.d.ts deleted file mode 100644 index 8e3d011e7093..000000000000 --- a/types/vscode.proposed.testRunInDebug.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - // https://github.com/microsoft/vscode/issues/214486 - - export interface DebugSessionOptions { - /** - * Signals to the editor that the debug session was started from a test run - * request. This is used to link the lifecycle of the debug session and - * test run in UI actions. - */ - testRun?: TestRun; - } -} diff --git a/vscode.proposed.testRunInDebug.d.ts b/vscode.proposed.testRunInDebug.d.ts deleted file mode 100644 index 8eb273e2a5e3..000000000000 --- a/vscode.proposed.testRunInDebug.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode' { - - // https://github.com/microsoft/vscode/issues/214486 - - export interface DebugSessionOptions { - /** - * Signals to the editor that the debug session was started from a test run - * request. This is used to link the lifecycle of the debug session and - * test run in UI actions. - */ - testRun?: TestRun; - } -} From 90eaf6d78d952ef9d7199ae532ce6fd80e8ed940 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 31 Jul 2024 10:10:32 -0700 Subject: [PATCH 07/11] remove unnessary parent option --- src/client/testing/common/debugLauncher.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index cde19586eb83..caac4871fa70 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -1,6 +1,6 @@ import { inject, injectable, named } from 'inversify'; import * as path from 'path'; -import { DebugConfiguration, l10n, Uri, WorkspaceFolder, DebugSessionOptions, TestRun, DebugSession } from 'vscode'; +import { DebugConfiguration, l10n, Uri, WorkspaceFolder, TestRun, DebugSession } from 'vscode'; import { IApplicationShell, IDebugService } from '../../common/application/types'; import { EXTENSION_ROOT_DIR } from '../../common/constants'; import * as internalScripts from '../../common/process/internal/scripts'; @@ -58,12 +58,8 @@ export class DebugLauncher implements ITestDebugLauncher { ); const debugManager = this.serviceContainer.get(IDebugService); - const debugSessionOptions: DebugSessionOptions = { - testRun: runInstance, - }; - let activatedDebugSession: DebugSession | undefined; - debugManager.startDebugging(workspaceFolder, launchArgs, debugSessionOptions).then(() => { + debugManager.startDebugging(workspaceFolder, launchArgs).then(() => { traceVerbose(`Debug session started. runInstance: ${runInstance?.name}`); // Save the debug session after it is started so we can check if it is the one that was terminated. activatedDebugSession = debugManager.activeDebugSession; From 112e3cd63d3c29baff081e0484b3a0d08684a40e Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Wed, 31 Jul 2024 10:25:23 -0700 Subject: [PATCH 08/11] remove console logs --- src/client/testing/common/debugLauncher.ts | 2 -- src/client/testing/testController/controller.ts | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index caac4871fa70..fa2c07cf410b 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -34,7 +34,6 @@ export class DebugLauncher implements ITestDebugLauncher { public async launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise { const deferred = createDeferred(); - console.log('launch debugger', runInstance?.name); let hasCallbackBeenCalled = false; if (options.token && options.token.isCancellationRequested) { hasCallbackBeenCalled = true; @@ -44,7 +43,6 @@ export class DebugLauncher implements ITestDebugLauncher { } options.token?.onCancellationRequested(() => { - console.log('onCancellationRequested', runInstance?.name); deferred.resolve(); callback?.(); hasCallbackBeenCalled = true; diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index e913c5820169..58edfb059666 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -373,14 +373,11 @@ export class PythonTestController implements ITestController, IExtensionSingleAc } else { (this.workspaceService.workspaceFolders || []).forEach((w) => workspaces.push(w)); } - // generate random number - const random = Math.floor(Math.random() * 1000); const runInstance = this.testController.createTestRun( request, - `Running Tests for Workspace(s): ${workspaces.map((w) => w.uri.fsPath).join(';')} random: ${random}`, + `Running Tests for Workspace(s): ${workspaces.map((w) => w.uri.fsPath).join(';')}`, true, ); - console.log('created run isntance', runInstance?.name); const dispose = token.onCancellationRequested(() => { runInstance.appendOutput(`\nRun instance cancelled.\r\n`); runInstance.end(); @@ -482,7 +479,6 @@ export class PythonTestController implements ITestController, IExtensionSingleAc ); } finally { traceVerbose('Finished running tests, ending runInstance.'); - console.log('end run instance', runInstance?.name); runInstance.appendOutput(`Finished running tests!\r\n`); runInstance.end(); dispose.dispose(); From 63ff9d18965af09e7a98c8d6be414f5bc0897e90 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 1 Aug 2024 15:09:34 -0700 Subject: [PATCH 09/11] support testing scenarios --- src/client/testing/common/debugLauncher.ts | 12 ++-- src/client/testing/common/types.ts | 4 +- .../pytest/pytestExecutionAdapter.ts | 12 ++-- .../unittest/testExecutionAdapter.ts | 12 ++-- .../testing/common/debugLauncher.unit.test.ts | 55 ++++++++++++++++++- 5 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index fa2c07cf410b..448b0bd82e9b 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -1,6 +1,6 @@ import { inject, injectable, named } from 'inversify'; import * as path from 'path'; -import { DebugConfiguration, l10n, Uri, WorkspaceFolder, TestRun, DebugSession } from 'vscode'; +import { DebugConfiguration, l10n, Uri, WorkspaceFolder, DebugSession } from 'vscode'; import { IApplicationShell, IDebugService } from '../../common/application/types'; import { EXTENSION_ROOT_DIR } from '../../common/constants'; import * as internalScripts from '../../common/process/internal/scripts'; @@ -32,7 +32,7 @@ export class DebugLauncher implements ITestDebugLauncher { this.configService = this.serviceContainer.get(IConfigurationService); } - public async launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise { + public async launchDebugger(options: LaunchOptions, callback?: () => void): Promise { const deferred = createDeferred(); let hasCallbackBeenCalled = false; if (options.token && options.token.isCancellationRequested) { @@ -58,13 +58,17 @@ export class DebugLauncher implements ITestDebugLauncher { let activatedDebugSession: DebugSession | undefined; debugManager.startDebugging(workspaceFolder, launchArgs).then(() => { - traceVerbose(`Debug session started. runInstance: ${runInstance?.name}`); // Save the debug session after it is started so we can check if it is the one that was terminated. activatedDebugSession = debugManager.activeDebugSession; }); + debugManager.onDidStartDebugSession(() => { + // duplicate of above for different scenarios + activatedDebugSession = debugManager.activeDebugSession; + }); + debugManager.onDidTerminateDebugSession((session) => { - traceVerbose(`Debug session terminated. sessionId: ${session.id}, runInstance: ${runInstance?.name}`); + traceVerbose(`Debug session terminated. sessionId: ${session.id}`); // Only resolve no callback has been made and the session is the one that was started. if ( !hasCallbackBeenCalled && diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 0074bbc77be8..29a6de7768cb 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -1,4 +1,4 @@ -import { CancellationToken, Disposable, OutputChannel, TestRun, Uri } from 'vscode'; +import { CancellationToken, Disposable, OutputChannel, Uri } from 'vscode'; import { Product } from '../../common/types'; import { TestSettingsPropertyNames } from '../configuration/types'; import { TestProvider } from '../types'; @@ -88,7 +88,7 @@ export interface ITestConfigurationManagerFactory { } export const ITestDebugLauncher = Symbol('ITestDebugLauncher'); export interface ITestDebugLauncher { - launchDebugger(options: LaunchOptions, callback?: () => void, runInstance?: TestRun): Promise; + launchDebugger(options: LaunchOptions, callback?: () => void): Promise; } export const IUnitTestSocketServer = Symbol('IUnitTestSocketServer'); diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 777244fbc5ad..5099efde179c 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -166,14 +166,10 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { pytestPort: resultNamedPipeName, }; traceInfo(`Running DEBUG pytest with arguments: ${testArgs} for workspace ${uri.fsPath} \r\n`); - await debugLauncher!.launchDebugger( - launchOptions, - () => { - serverDispose(); // this will resolve deferredTillServerClose - deferredTillEOT?.resolve(); - }, - runInstance, - ); + await debugLauncher!.launchDebugger(launchOptions, () => { + serverDispose(); // this will resolve deferredTillServerClose + deferredTillEOT?.resolve(); + }); } else { // deferredTillExecClose is resolved when all stdout and stderr is read const deferredTillExecClose: Deferred = utils.createTestingDeferred(); diff --git a/src/client/testing/testController/unittest/testExecutionAdapter.ts b/src/client/testing/testController/unittest/testExecutionAdapter.ts index 4c632a32d834..4746c3101752 100644 --- a/src/client/testing/testController/unittest/testExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/testExecutionAdapter.ts @@ -176,14 +176,10 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { traceError('Debug launcher is not defined'); throw new Error('Debug launcher is not defined'); } - await debugLauncher.launchDebugger( - launchOptions, - () => { - serverDispose(); // this will resolve the deferredTillAllServerClose - deferredTillEOT?.resolve(); - }, - runInstance, - ); + await debugLauncher.launchDebugger(launchOptions, () => { + serverDispose(); // this will resolve the deferredTillAllServerClose + deferredTillEOT?.resolve(); + }); } else { // This means it is running the test traceInfo(`Running unittests for workspace ${cwd} with arguments: ${args}\r\n`); diff --git a/src/test/testing/common/debugLauncher.unit.test.ts b/src/test/testing/common/debugLauncher.unit.test.ts index 31ba761eb946..f7a515a20c6a 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -10,7 +10,7 @@ import * as sinon from 'sinon'; import * as TypeMoq from 'typemoq'; import * as fs from 'fs-extra'; import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis'; -import { CancellationTokenSource, DebugConfiguration, Uri, WorkspaceFolder } from 'vscode'; +import { CancellationTokenSource, DebugConfiguration, DebugSession, Uri, WorkspaceFolder } from 'vscode'; import { IInvalidPythonPathInDebuggerService } from '../../../client/application/diagnostics/types'; import { IApplicationShell, IDebugService } from '../../../client/common/application/types'; import { EXTENSION_ROOT_DIR } from '../../../client/common/constants'; @@ -30,6 +30,7 @@ import { TestProvider } from '../../../client/testing/types'; import { isOs, OSType } from '../../common'; import { IEnvironmentActivationService } from '../../../client/interpreter/activation/types'; import * as util from '../../../client/testing/testController/common/utils'; +import { createDeferred } from '../../../client/common/utils/async'; use(chaiAsPromised); @@ -125,20 +126,68 @@ suite('Unit Tests - Debug Launcher', () => { .setup((x) => x.getEnvironmentVariables(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => Promise.resolve(expected.env)); + const deferred = createDeferred(); + + // debugService + // .setup((d) => d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected))) + // .returns( + // async (_wspc: WorkspaceFolder, _expectedParam: DebugConfiguration): Promise => { + // await Promise.resolve(undefined as any); + // // Add your logic here + // deferred.resolve(); + // console.log('Debugging finished'); + // return true; + // }, + // ) + // .verifiable(TypeMoq.Times.once()); debugService .setup((d) => d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected))) .returns((_wspc: WorkspaceFolder, _expectedParam: DebugConfiguration) => { return Promise.resolve(undefined as any); - }) + }); + + // debugService.object.startDebugging(workspaceFolder, expected).then((result) => { + // console.log('startDebugging has finished with result:', result); + // // Add any additional logic you want to execute after startDebugging finishes + // }); + + debugService + .setup((d) => d.onDidStartDebugSession(TypeMoq.It.isAny())) + .returns(() => { + deferred.resolve(); + return undefined as any; + }); + + // create a fake debug session that the debug service will return on terminate + const fakeDebugSession = TypeMoq.Mock.ofType(); + fakeDebugSession.setup((ds) => ds.id).returns(() => 'id-val'); + const debugSessionInstance = fakeDebugSession.object; + + debugService + .setup((d) => d.activeDebugSession) + .returns(() => debugSessionInstance) .verifiable(TypeMoq.Times.once()); debugService .setup((d) => d.onDidTerminateDebugSession(TypeMoq.It.isAny())) .returns((callback) => { - callback(); + deferred.promise.then(() => { + callback(debugSessionInstance); + }); return undefined as any; }) .verifiable(TypeMoq.Times.once()); + + // debugService + // .setup((d) => d.onDidTerminateDebugSession(TypeMoq.It.isAny())) + // .returns((callback) => { + // return { + // dispose: () => { + // callback(debugSessionInstance); + // }, + // }; + // }) + // .verifiable(TypeMoq.Times.once()); } function createWorkspaceFolder(folderPath: string): WorkspaceFolder { return { From b21cd6b345f2e0de8163fd8ed284b88c33964ca8 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Thu, 1 Aug 2024 15:27:11 -0700 Subject: [PATCH 10/11] remove unneeded code --- .../testing/common/debugLauncher.unit.test.ts | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/src/test/testing/common/debugLauncher.unit.test.ts b/src/test/testing/common/debugLauncher.unit.test.ts index f7a515a20c6a..3defa1ea7999 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -128,29 +128,12 @@ suite('Unit Tests - Debug Launcher', () => { const deferred = createDeferred(); - // debugService - // .setup((d) => d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected))) - // .returns( - // async (_wspc: WorkspaceFolder, _expectedParam: DebugConfiguration): Promise => { - // await Promise.resolve(undefined as any); - // // Add your logic here - // deferred.resolve(); - // console.log('Debugging finished'); - // return true; - // }, - // ) - // .verifiable(TypeMoq.Times.once()); debugService .setup((d) => d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected))) .returns((_wspc: WorkspaceFolder, _expectedParam: DebugConfiguration) => { return Promise.resolve(undefined as any); }); - // debugService.object.startDebugging(workspaceFolder, expected).then((result) => { - // console.log('startDebugging has finished with result:', result); - // // Add any additional logic you want to execute after startDebugging finishes - // }); - debugService .setup((d) => d.onDidStartDebugSession(TypeMoq.It.isAny())) .returns(() => { @@ -177,17 +160,6 @@ suite('Unit Tests - Debug Launcher', () => { return undefined as any; }) .verifiable(TypeMoq.Times.once()); - - // debugService - // .setup((d) => d.onDidTerminateDebugSession(TypeMoq.It.isAny())) - // .returns((callback) => { - // return { - // dispose: () => { - // callback(debugSessionInstance); - // }, - // }; - // }) - // .verifiable(TypeMoq.Times.once()); } function createWorkspaceFolder(folderPath: string): WorkspaceFolder { return { From f5c9264f2d72141a385f8a57571c2c0a2a2cb013 Mon Sep 17 00:00:00 2001 From: eleanorjboyd Date: Mon, 5 Aug 2024 10:18:00 -0700 Subject: [PATCH 11/11] remove duplicate event listener --- src/client/testing/common/debugLauncher.ts | 6 ------ src/test/testing/common/debugLauncher.unit.test.ts | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index 448b0bd82e9b..cd4b7181f447 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -61,12 +61,6 @@ export class DebugLauncher implements ITestDebugLauncher { // Save the debug session after it is started so we can check if it is the one that was terminated. activatedDebugSession = debugManager.activeDebugSession; }); - - debugManager.onDidStartDebugSession(() => { - // duplicate of above for different scenarios - activatedDebugSession = debugManager.activeDebugSession; - }); - debugManager.onDidTerminateDebugSession((session) => { traceVerbose(`Debug session terminated. sessionId: ${session.id}`); // Only resolve no callback has been made and the session is the one that was started. diff --git a/src/test/testing/common/debugLauncher.unit.test.ts b/src/test/testing/common/debugLauncher.unit.test.ts index 3defa1ea7999..bdcb7b63762c 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -131,14 +131,8 @@ suite('Unit Tests - Debug Launcher', () => { debugService .setup((d) => d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected))) .returns((_wspc: WorkspaceFolder, _expectedParam: DebugConfiguration) => { - return Promise.resolve(undefined as any); - }); - - debugService - .setup((d) => d.onDidStartDebugSession(TypeMoq.It.isAny())) - .returns(() => { deferred.resolve(); - return undefined as any; + return Promise.resolve(undefined as any); }); // create a fake debug session that the debug service will return on terminate