From 77e44cf2dacc7b6de24fe45318ecac2fd0f439f7 Mon Sep 17 00:00:00 2001 From: Eleanor Boyd Date: Fri, 26 Apr 2024 14:36:44 -0700 Subject: [PATCH] Revert "Debug cancelation (#23262)" (#23301) This reverts commit 51cf852852b2b2d1ab05493f3ecff96965e76ee4. CI has been failing and we need CI to pass to get out a build of insiders and prep for the release. --- src/client/testing/common/debugLauncher.ts | 28 +-- .../testing/testController/common/utils.ts | 2 +- .../pytest/pytestExecutionAdapter.ts | 1 - .../testing/common/debugLauncher.unit.test.ts | 6 - .../testing/common/testingAdapter.test.ts | 204 +----------------- 5 files changed, 6 insertions(+), 235 deletions(-) diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index 0ec38eb9c87c..f9c7747d883a 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 { debug, DebugConfiguration, Disposable, l10n, Uri, WorkspaceFolder } from 'vscode'; +import { DebugConfiguration, l10n, Uri, WorkspaceFolder } 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, traceLog } from '../../logging'; +import { traceError } from '../../logging'; import { TestProvider } from '../types'; import { ITestDebugLauncher, LaunchOptions } from './types'; import { getConfigurationsForWorkspace } from '../../debugger/extension/configuration/launch.json/launchJsonReader'; @@ -48,29 +48,7 @@ export class DebugLauncher implements ITestDebugLauncher { ); const debugManager = this.serviceContainer.get(IDebugService); - let disposeOfDebugger: Disposable | undefined; - const disposeOfStartDebugging = debugManager.onDidStartDebugSession((session) => { - if (options.token) { - disposeOfDebugger = options?.token.onCancellationRequested(() => { - console.log('Canceling debugger, due to cancelation token called.'); - debug.stopDebugging(session); - }); - } - }); - - let disposeTerminateWatcher: Disposable | undefined; - // eslint-disable-next-line prefer-const - disposeTerminateWatcher = debugManager.onDidTerminateDebugSession(() => { - traceLog('Terminating the debugging session and disposing of debugger listeners.'); - if (disposeOfDebugger !== undefined) { - disposeOfDebugger.dispose(); - } - if (disposeOfStartDebugging !== undefined) { - disposeOfStartDebugging.dispose(); - } - if (disposeTerminateWatcher !== undefined) { - disposeTerminateWatcher.dispose(); - } + debugManager.onDidTerminateDebugSession(() => { deferred.resolve(); callback?.(); }); diff --git a/src/client/testing/testController/common/utils.ts b/src/client/testing/testController/common/utils.ts index 0bdecc5b8257..759fb0713de4 100644 --- a/src/client/testing/testController/common/utils.ts +++ b/src/client/testing/testController/common/utils.ts @@ -220,7 +220,7 @@ export async function startRunResultNamedPipe( perConnectionDisposables.push( // per connection, add a listener for the cancellation token and the data cancellationToken?.onCancellationRequested(() => { - traceVerbose(`Test Result named pipe ${pipeName} cancelled`); + console.log(`Test Result named pipe ${pipeName} cancelled`); // if cancel is called on one connection, dispose of all connections disposeOfServer(); }), diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index 090ae787ed60..5099efde179c 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -167,7 +167,6 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { }; traceInfo(`Running DEBUG pytest with arguments: ${testArgs} for workspace ${uri.fsPath} \r\n`); await debugLauncher!.launchDebugger(launchOptions, () => { - traceInfo("Debugger callback called, resolving 'till EOT' deferred for the workspace."); serverDispose(); // this will resolve deferredTillServerClose deferredTillEOT?.resolve(); }); diff --git a/src/test/testing/common/debugLauncher.unit.test.ts b/src/test/testing/common/debugLauncher.unit.test.ts index 6a72aa7586f0..ef3e678c13f7 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -139,12 +139,6 @@ suite('Unit Tests - Debug Launcher', () => { return undefined as any; }) .verifiable(TypeMoq.Times.once()); - debugService - .setup((d) => d.onDidStartDebugSession(TypeMoq.It.isAny())) - .returns(() => { - return undefined as any; - }) - .verifiable(TypeMoq.Times.once()); } function createWorkspaceFolder(folderPath: string): WorkspaceFolder { return { diff --git a/src/test/testing/common/testingAdapter.test.ts b/src/test/testing/common/testingAdapter.test.ts index 572ea7e19836..c01fed29bac7 100644 --- a/src/test/testing/common/testingAdapter.test.ts +++ b/src/test/testing/common/testingAdapter.test.ts @@ -1,17 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { CancellationTokenSource, DebugSession, TestController, TestRun, Uri, debug } from 'vscode'; +import { TestController, TestRun, Uri } from 'vscode'; import * as typeMoq from 'typemoq'; import * as path from 'path'; import * as assert from 'assert'; import * as fs from 'fs'; -import * as sinon from 'sinon'; -import { Observable } from 'rxjs'; import * as os from 'os'; import { PytestTestDiscoveryAdapter } from '../../../client/testing/testController/pytest/pytestDiscoveryAdapter'; import { ITestController, ITestResultResolver } from '../../../client/testing/testController/common/types'; -import { IPythonExecutionFactory, IPythonExecutionService, Output } from '../../../client/common/process/types'; +import { IPythonExecutionFactory } from '../../../client/common/process/types'; import { IConfigurationService, ITestOutputChannel } from '../../../client/common/types'; import { IServiceContainer } from '../../../client/ioc/types'; import { EXTENSION_ROOT_DIR_FOR_TESTS, initialize } from '../../initialize'; @@ -23,9 +21,6 @@ import { PythonResultResolver } from '../../../client/testing/testController/com import { TestProvider } from '../../../client/testing/types'; import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../../client/testing/common/constants'; import { IEnvironmentVariablesProvider } from '../../../client/common/variables/types'; -import { ITestDebugLauncher } from '../../../client/testing/common/types'; -import { MockChildProcess } from '../../mocks/mockChildProcess'; -import { createDeferred } from '../../../client/common/utils/async'; suite('End to End Tests: test adapters', () => { let resultResolver: ITestResultResolver; @@ -155,9 +150,6 @@ suite('End to End Tests: test adapters', () => { traceLog('Symlink was not found to remove after tests, exiting successfully, nestedSymlink.'); } }); - teardown(async () => { - sinon.restore(); - }); test('unittest discovery adapter small workspace', async () => { // result resolver and saved data for assertions let actualData: { @@ -1081,196 +1073,4 @@ suite('End to End Tests: test adapters', () => { assert.strictEqual(failureOccurred, false, failureMsg); }); }); - test('Pytest debug cancelation', async () => { - const debugLauncher = serviceContainer.get(ITestDebugLauncher); - const stopDebuggingStub = sinon.stub(debug, 'stopDebugging'); - let calledStopDebugging = false; - stopDebuggingStub.callsFake(() => { - calledStopDebugging = true; - return Promise.resolve(); - }); - - // // mock exec service and exec factory, not very necessary for this test - const execServiceStub = typeMoq.Mock.ofType(); - const execFactoryStub = typeMoq.Mock.ofType(); - const cancellationTokenSource = new CancellationTokenSource(); - let mockProc: MockChildProcess; - execServiceStub - .setup((x) => x.execObservable(typeMoq.It.isAny(), typeMoq.It.isAny())) - .returns(() => ({ - proc: mockProc, - out: typeMoq.Mock.ofType>>().object, - dispose: () => { - /* no-body */ - }, - })); - execFactoryStub - .setup((x) => x.createActivatedEnvironment(typeMoq.It.isAny())) - .returns(() => Promise.resolve(execServiceStub.object)); - execFactoryStub.setup((p) => ((p as unknown) as any).then).returns(() => undefined); - execServiceStub.setup((p) => ((p as unknown) as any).then).returns(() => undefined); - - resultResolver = new PythonResultResolver(testController, pytestProvider, workspaceUri); - - const testId = `${rootPathErrorWorkspace}/test_seg_fault.py::TestSegmentationFault::test_segfault`; - const testIds: string[] = [testId]; - - // set workspace to test workspace folder - workspaceUri = Uri.parse(rootPathErrorWorkspace); - configService.getSettings(workspaceUri).testing.pytestArgs = []; - - const debugSessionStub = typeMoq.Mock.ofType(); - sinon.stub(debug, 'onDidStartDebugSession').callsFake((cb) => { - // run the callback right away to add the cancelation token listener - cb(debugSessionStub.object); - return { - dispose: () => { - /* no-body */ - }, - }; - }); - const awaitStopDebugging = createDeferred(); - - sinon.stub(debug, 'onDidTerminateDebugSession').callsFake((cb) => { - // wait for the stop debugging to be called before resolving the promise - // the terminate debug session does cleanup - awaitStopDebugging.promise.then(() => { - cb(debugSessionStub.object); - }); - return { - dispose: () => { - // void - }, - }; - }); - // handle cancelation token from debugger - sinon.stub(debug, 'startDebugging').callsFake((folder, nameOrConfiguration, _parentSession) => { - // check to make sure start debugging is called correctly - if (typeof nameOrConfiguration !== 'string') { - assert.strictEqual(nameOrConfiguration.type, 'debugpy', 'Expected debugpy'); - } else { - assert.fail('Expected nameOrConfiguration to be an object'); - } - assert.ok(folder, 'Expected folder to be defined'); - assert.strictEqual(folder.name, 'test', 'Expected folder name to be test'); - // cancel the token and trigger the stop debugging callback - awaitStopDebugging.resolve(); - cancellationTokenSource.cancel(); - return Promise.resolve(true); - }); - - // run pytest execution - const executionAdapter = new PytestTestExecutionAdapter( - configService, - testOutputChannel.object, - resultResolver, - envVarsService, - ); - - const testRun = typeMoq.Mock.ofType(); - testRun.setup((t) => t.token).returns(() => cancellationTokenSource.token); - - await executionAdapter - .runTests(workspaceUri, testIds, true, testRun.object, pythonExecFactory, debugLauncher) - .finally(() => { - // verify that the stop debugging was called - assert.ok(calledStopDebugging, 'Expected stopDebugging to be called'); - }); - }); - test('UNITTEST debug cancelation', async () => { - const debugLauncher = serviceContainer.get(ITestDebugLauncher); - const stopDebuggingStub = sinon.stub(debug, 'stopDebugging'); - let calledStopDebugging = false; - stopDebuggingStub.callsFake(() => { - calledStopDebugging = true; - return Promise.resolve(); - }); - - // // mock exec service and exec factory, not very necessary for this test - const execServiceStub = typeMoq.Mock.ofType(); - const execFactoryStub = typeMoq.Mock.ofType(); - const cancellationTokenSource = new CancellationTokenSource(); - let mockProc: MockChildProcess; - execServiceStub - .setup((x) => x.execObservable(typeMoq.It.isAny(), typeMoq.It.isAny())) - .returns(() => ({ - proc: mockProc, - out: typeMoq.Mock.ofType>>().object, - dispose: () => { - /* no-body */ - }, - })); - execFactoryStub - .setup((x) => x.createActivatedEnvironment(typeMoq.It.isAny())) - .returns(() => Promise.resolve(execServiceStub.object)); - execFactoryStub.setup((p) => ((p as unknown) as any).then).returns(() => undefined); - execServiceStub.setup((p) => ((p as unknown) as any).then).returns(() => undefined); - - resultResolver = new PythonResultResolver(testController, pytestProvider, workspaceUri); - - const testId = `${rootPathErrorWorkspace}/test_seg_fault.py::TestSegmentationFault::test_segfault`; - const testIds: string[] = [testId]; - - // set workspace to test workspace folder - workspaceUri = Uri.parse(rootPathErrorWorkspace); - configService.getSettings(workspaceUri).testing.pytestArgs = []; - - const debugSessionStub = typeMoq.Mock.ofType(); - sinon.stub(debug, 'onDidStartDebugSession').callsFake((cb) => { - // run the callback right away to add the cancelation token listener - cb(debugSessionStub.object); - return { - dispose: () => { - /* no-body */ - }, - }; - }); - const awaitStopDebugging = createDeferred(); - - sinon.stub(debug, 'onDidTerminateDebugSession').callsFake((cb) => { - // wait for the stop debugging to be called before resolving the promise - // the terminate debug session does cleanup - awaitStopDebugging.promise.then(() => { - cb(debugSessionStub.object); - }); - return { - dispose: () => { - // void - }, - }; - }); - // handle cancelation token from debugger - sinon.stub(debug, 'startDebugging').callsFake((folder, nameOrConfiguration, _parentSession) => { - // check to make sure start debugging is called correctly - if (typeof nameOrConfiguration !== 'string') { - assert.strictEqual(nameOrConfiguration.type, 'debugpy', 'Expected debugpy'); - } else { - assert.fail('Expected nameOrConfiguration to be an object'); - } - assert.ok(folder, 'Expected folder to be defined'); - assert.strictEqual(folder.name, 'test', 'Expected folder name to be test'); - // cancel the token and trigger the stop debugging callback - awaitStopDebugging.resolve(); - cancellationTokenSource.cancel(); - return Promise.resolve(true); - }); - - // run pytest execution - const executionAdapter = new UnittestTestExecutionAdapter( - configService, - testOutputChannel.object, - resultResolver, - envVarsService, - ); - - const testRun = typeMoq.Mock.ofType(); - testRun.setup((t) => t.token).returns(() => cancellationTokenSource.token); - - await executionAdapter - .runTests(workspaceUri, testIds, true, testRun.object, pythonExecFactory, debugLauncher) - .finally(() => { - // verify that the stop debugging was called - assert.ok(calledStopDebugging, 'Expected stopDebugging to be called'); - }); - }); });