diff --git a/src/client/common/application/debugService.ts b/src/client/common/application/debugService.ts index d98262d88926..7de039e946c2 100644 --- a/src/client/common/application/debugService.ts +++ b/src/client/common/application/debugService.ts @@ -13,6 +13,7 @@ import { DebugConsole, DebugSession, DebugSessionCustomEvent, + DebugSessionOptions, Disposable, Event, WorkspaceFolder, @@ -57,7 +58,7 @@ export class DebugService implements IDebugService { public startDebugging( folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, - parentSession?: DebugSession, + parentSession?: DebugSession | DebugSessionOptions, ): Thenable { return debug.startDebugging(folder, nameOrConfiguration, parentSession); } diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index cd4b7181f447..1954072b17b0 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, DebugSession } from 'vscode'; +import { DebugConfiguration, l10n, Uri, WorkspaceFolder, DebugSession, DebugSessionOptions } 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,11 @@ 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, + sessionOptions?: DebugSessionOptions, + ): Promise { const deferred = createDeferred(); let hasCallbackBeenCalled = false; if (options.token && options.token.isCancellationRequested) { @@ -57,7 +61,7 @@ export class DebugLauncher implements ITestDebugLauncher { const debugManager = this.serviceContainer.get(IDebugService); let activatedDebugSession: DebugSession | undefined; - debugManager.startDebugging(workspaceFolder, launchArgs).then(() => { + debugManager.startDebugging(workspaceFolder, launchArgs, sessionOptions).then(() => { // Save the debug session after it is started so we can check if it is the one that was terminated. activatedDebugSession = debugManager.activeDebugSession; }); diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 67a9a44a5706..78acd632ccd1 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, DebugSessionOptions, Disposable, OutputChannel, Uri } from 'vscode'; import { Product } from '../../common/types'; import { TestSettingsPropertyNames } from '../configuration/types'; import { TestProvider } from '../types'; @@ -89,7 +89,7 @@ export interface ITestConfigurationManagerFactory { } export const ITestDebugLauncher = Symbol('ITestDebugLauncher'); export interface ITestDebugLauncher { - launchDebugger(options: LaunchOptions, callback?: () => void): Promise; + launchDebugger(options: LaunchOptions, callback?: () => void, sessionOptions?: DebugSessionOptions): 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 8847738b65cd..bc5ac7dfae9f 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { CancellationTokenSource, TestRun, TestRunProfileKind, Uri } from 'vscode'; +import { CancellationTokenSource, DebugSessionOptions, TestRun, TestRunProfileKind, Uri } from 'vscode'; import * as path from 'path'; import { ChildProcess } from 'child_process'; import { IConfigurationService, ITestOutputChannel } from '../../../common/types'; @@ -167,10 +167,17 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { runTestIdsPort: testIdsFileName, pytestPort: resultNamedPipeName, }; + const sessionOptions: DebugSessionOptions = { + testRun: runInstance, + }; traceInfo(`Running DEBUG pytest with arguments: ${testArgs} for workspace ${uri.fsPath} \r\n`); - await debugLauncher!.launchDebugger(launchOptions, () => { - serverCancel.cancel(); - }); + await debugLauncher!.launchDebugger( + launchOptions, + () => { + serverCancel.cancel(); + }, + sessionOptions, + ); } 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 f69ec4379908..3254e9570fd9 100644 --- a/src/client/testing/testController/unittest/testExecutionAdapter.ts +++ b/src/client/testing/testController/unittest/testExecutionAdapter.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import * as path from 'path'; -import { CancellationTokenSource, TestRun, TestRunProfileKind, Uri } from 'vscode'; +import { CancellationTokenSource, DebugSessionOptions, TestRun, TestRunProfileKind, Uri } from 'vscode'; import { ChildProcess } from 'child_process'; import { IConfigurationService, ITestOutputChannel } from '../../../common/types'; import { Deferred, createDeferred } from '../../../common/utils/async'; @@ -166,15 +166,22 @@ export class UnittestTestExecutionAdapter implements ITestExecutionAdapter { runTestIdsPort: testIdsFileName, pytestPort: resultNamedPipeName, // change this from pytest }; + const sessionOptions: DebugSessionOptions = { + testRun: runInstance, + }; traceInfo(`Running DEBUG unittest for workspace ${options.cwd} with arguments: ${args}\r\n`); if (debugLauncher === undefined) { traceError('Debug launcher is not defined'); throw new Error('Debug launcher is not defined'); } - await debugLauncher.launchDebugger(launchOptions, () => { - serverCancel.cancel(); - }); + await debugLauncher.launchDebugger( + launchOptions, + () => { + serverCancel.cancel(); + }, + sessionOptions, + ); } 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 e31579640c9a..cb4b582639ea 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -129,7 +129,9 @@ suite('Unit Tests - Debug Launcher', () => { const deferred = createDeferred(); debugService - .setup((d) => d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected))) + .setup((d) => + d.startDebugging(TypeMoq.It.isValue(workspaceFolder), TypeMoq.It.isValue(expected), undefined), + ) .returns((_wspc: WorkspaceFolder, _expectedParam: DebugConfiguration) => { deferred.resolve(); return Promise.resolve(undefined as any); @@ -299,7 +301,7 @@ suite('Unit Tests - Debug Launcher', () => { }); test(`Must not launch debugger if cancelled ${testTitleSuffix}`, async () => { debugService - .setup((d) => d.startDebugging(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .setup((d) => d.startDebugging(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => { return Promise.resolve(undefined as any); }) diff --git a/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts b/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts index 9e9b39e91ce8..2eb615dbd1a2 100644 --- a/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts +++ b/src/test/testing/testController/pytest/pytestExecutionAdapter.unit.test.ts @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import * as assert from 'assert'; -import { TestRun, Uri, TestRunProfileKind } from 'vscode'; +import { TestRun, Uri, TestRunProfileKind, DebugSessionOptions } from 'vscode'; import * as typeMoq from 'typemoq'; import * as sinon from 'sinon'; import * as path from 'path'; @@ -238,7 +238,7 @@ suite('pytest test execution adapter', () => { const deferred3 = createDeferred(); utilsWriteTestIdsFileStub.callsFake(() => Promise.resolve('testIdPipe-mockName')); debugLauncher - .setup((dl) => dl.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny())) + .setup((dl) => dl.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny())) .returns(async (_opts, callback) => { traceInfo('stubs launch debugger'); if (typeof callback === 'function') { @@ -273,6 +273,10 @@ suite('pytest test execution adapter', () => { return true; }), typeMoq.It.isAny(), + typeMoq.It.is((sessionOptions) => { + assert.equal(sessionOptions.testRun, testRun.object); + return true; + }), ), typeMoq.Times.once(), ); diff --git a/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts b/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts index 1b90244fb41d..af4903a1515b 100644 --- a/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts +++ b/src/test/testing/testController/testCancellationRunAdapters.unit.test.ts @@ -185,7 +185,7 @@ suite('Execution Flow Run Adapters', () => { // debugLauncher mocked debugLauncher - .setup((dl) => dl.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny())) + .setup((dl) => dl.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny())) .callback((_options, callback) => { if (callback) { callback(); diff --git a/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts b/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts index 9521c4ab9b79..8f2afcc51cd1 100644 --- a/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts +++ b/src/test/testing/testController/unittest/testExecutionAdapter.unit.test.ts @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import * as assert from 'assert'; -import { TestRun, TestRunProfileKind, Uri } from 'vscode'; +import { DebugSessionOptions, TestRun, TestRunProfileKind, Uri } from 'vscode'; import * as typeMoq from 'typemoq'; import * as sinon from 'sinon'; import * as path from 'path'; @@ -237,7 +237,7 @@ suite('Unittest test execution adapter', () => { const deferred3 = createDeferred(); utilsWriteTestIdsFileStub.callsFake(() => Promise.resolve('testIdPipe-mockName')); debugLauncher - .setup((dl) => dl.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny())) + .setup((dl) => dl.launchDebugger(typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny())) .returns(async (_opts, callback) => { traceInfo('stubs launch debugger'); if (typeof callback === 'function') { @@ -271,6 +271,10 @@ suite('Unittest test execution adapter', () => { return true; }), typeMoq.It.isAny(), + typeMoq.It.is((sessionOptions) => { + assert.equal(sessionOptions.testRun, testRun.object); + return true; + }), ), typeMoq.Times.once(), );