mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-13 15:35:20 +01:00
debug: correlate debug sessions to testing, delegate restarts (#214537)
Implements #214486
This commit is contained in:
@@ -119,7 +119,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
map,
|
||||
task,
|
||||
kind === vscode.TestRunProfileKind.Debug
|
||||
? await runner.debug(currentArgs, req.include)
|
||||
? await runner.debug(task, currentArgs, req.include)
|
||||
: await runner.run(currentArgs, req.include),
|
||||
coverageDir,
|
||||
cancellationToken
|
||||
|
||||
@@ -37,7 +37,7 @@ export abstract class VSCodeTestRunner {
|
||||
return new TestOutputScanner(cp, args);
|
||||
}
|
||||
|
||||
public async debug(baseArgs: ReadonlyArray<string>, filter?: ReadonlyArray<vscode.TestItem>) {
|
||||
public async debug(testRun: vscode.TestRun, baseArgs: ReadonlyArray<string>, filter?: ReadonlyArray<vscode.TestItem>) {
|
||||
const port = await this.findOpenPort();
|
||||
const baseConfiguration = vscode.workspace
|
||||
.getConfiguration('launch', this.repoLocation)
|
||||
@@ -95,7 +95,7 @@ export abstract class VSCodeTestRunner {
|
||||
},
|
||||
});
|
||||
|
||||
vscode.debug.startDebugging(this.repoLocation, { ...baseConfiguration, port });
|
||||
vscode.debug.startDebugging(this.repoLocation, { ...baseConfiguration, port }, { testRun });
|
||||
|
||||
let exited = false;
|
||||
let rootSession: vscode.DebugSession | undefined;
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
"../../../src/vscode-dts/vscode.d.ts",
|
||||
"../../../src/vscode-dts/vscode.proposed.testObserver.d.ts",
|
||||
"../../../src/vscode-dts/vscode.proposed.attributableCoverage.d.ts",
|
||||
"../../../src/vscode-dts/vscode.proposed.testRunInDebug.d.ts",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -329,6 +329,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
|
||||
compact: options.compact,
|
||||
compoundRoot: parentSession?.compoundRoot,
|
||||
saveBeforeRestart: saveBeforeStart,
|
||||
testRun: options.testRun,
|
||||
|
||||
suppressDebugStatusbar: options.suppressDebugStatusbar,
|
||||
suppressDebugToolbar: options.suppressDebugToolbar,
|
||||
|
||||
@@ -84,7 +84,7 @@ import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
|
||||
import { ExtHostTelemetryLogger, IExtHostTelemetry, isNewAppInstall } from 'vs/workbench/api/common/extHostTelemetry';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { IExtHostTerminalShellIntegration } from 'vs/workbench/api/common/extHostTerminalShellIntegration';
|
||||
import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
||||
import { IExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||
import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
|
||||
import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline';
|
||||
@@ -205,7 +205,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostWebviewPanels = rpcProtocol.set(ExtHostContext.ExtHostWebviewPanels, new ExtHostWebviewPanels(rpcProtocol, extHostWebviews, extHostWorkspace));
|
||||
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews, extHostWebviewPanels));
|
||||
const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews));
|
||||
const extHostTesting = rpcProtocol.set(ExtHostContext.ExtHostTesting, new ExtHostTesting(rpcProtocol, extHostLogService, extHostCommands, extHostDocumentsAndEditors));
|
||||
const extHostTesting = rpcProtocol.set(ExtHostContext.ExtHostTesting, accessor.get(IExtHostTesting));
|
||||
const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol));
|
||||
const extHostProfileContentHandlers = rpcProtocol.set(ExtHostContext.ExtHostProfileContentHandlers, new ExtHostProfileContentHandlers(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService));
|
||||
|
||||
@@ -31,6 +31,7 @@ import { ExtHostManagedSockets, IExtHostManagedSockets } from 'vs/workbench/api/
|
||||
import { ExtHostAuthentication, IExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
||||
import { ExtHostLanguageModels, IExtHostLanguageModels } from 'vs/workbench/api/common/extHostLanguageModels';
|
||||
import { IExtHostTerminalShellIntegration, ExtHostTerminalShellIntegration } from 'vs/workbench/api/common/extHostTerminalShellIntegration';
|
||||
import { ExtHostTesting, IExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
||||
|
||||
registerSingleton(IExtHostLocalizationService, ExtHostLocalizationService, InstantiationType.Delayed);
|
||||
registerSingleton(ILoggerService, ExtHostLoggerService, InstantiationType.Delayed);
|
||||
@@ -40,6 +41,7 @@ registerSingleton(IExtHostAuthentication, ExtHostAuthentication, InstantiationTy
|
||||
registerSingleton(IExtHostLanguageModels, ExtHostLanguageModels, InstantiationType.Eager);
|
||||
registerSingleton(IExtHostConfiguration, ExtHostConfiguration, InstantiationType.Eager);
|
||||
registerSingleton(IExtHostConsumerFileSystem, ExtHostConsumerFileSystem, InstantiationType.Eager);
|
||||
registerSingleton(IExtHostTesting, ExtHostTesting, InstantiationType.Eager);
|
||||
registerSingleton(IExtHostDebugService, WorkerExtHostDebugService, InstantiationType.Eager);
|
||||
registerSingleton(IExtHostDecorations, ExtHostDecorations, InstantiationType.Eager);
|
||||
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors, InstantiationType.Eager);
|
||||
|
||||
@@ -55,7 +55,7 @@ import { IChatProgressResponseContent } from 'vs/workbench/contrib/chat/common/c
|
||||
import { IChatFollowup, IChatProgress, IChatResponseErrorDetails, IChatTask, IChatTaskDto, IChatUserActionEvent, ChatAgentVoteDirection } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProgress } from 'vs/workbench/contrib/chat/common/chatVariables';
|
||||
import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata, ILanguageModelChatSelector, ILanguageModelsChangeEvent } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugTestRunReference, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { ICellExecutionComplete, ICellExecutionStateUpdate } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
|
||||
@@ -1566,6 +1566,7 @@ export interface IStartDebuggingOptions {
|
||||
suppressDebugStatusbar?: boolean;
|
||||
suppressDebugView?: boolean;
|
||||
suppressSaveBeforeStart?: boolean;
|
||||
testRun?: IDebugTestRunReference;
|
||||
}
|
||||
|
||||
export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
|
||||
@@ -30,6 +30,7 @@ import { ThemeIcon as ThemeIconUtils } from 'vs/base/common/themables';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import * as Convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { IExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
||||
|
||||
export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtHostDebugService');
|
||||
|
||||
@@ -123,6 +124,7 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
|
||||
@IExtHostEditorTabs protected _editorTabs: IExtHostEditorTabs,
|
||||
@IExtHostVariableResolverProvider private _variableResolver: IExtHostVariableResolverProvider,
|
||||
@IExtHostCommands private _commands: IExtHostCommands,
|
||||
@IExtHostTesting private _testing: IExtHostTesting,
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -466,6 +468,8 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
|
||||
}
|
||||
|
||||
public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean> {
|
||||
const testRunMeta = options.testRun && this._testing.getMetadataForRun(options.testRun);
|
||||
|
||||
return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig, {
|
||||
parentSessionID: options.parentSession ? options.parentSession.id : undefined,
|
||||
lifecycleManagedByParent: options.lifecycleManagedByParent,
|
||||
@@ -473,6 +477,10 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
|
||||
noDebug: options.noDebug,
|
||||
compact: options.compact,
|
||||
suppressSaveBeforeStart: options.suppressSaveBeforeStart,
|
||||
testRun: testRunMeta && {
|
||||
runId: testRunMeta.runId,
|
||||
taskId: testRunMeta.taskId,
|
||||
},
|
||||
|
||||
// Check debugUI for back-compat, #147264
|
||||
suppressDebugStatusbar: options.suppressDebugStatusbar ?? (options as any).debugUI?.simple,
|
||||
@@ -1247,8 +1255,9 @@ export class WorkerExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
@IExtHostConfiguration configurationService: IExtHostConfiguration,
|
||||
@IExtHostEditorTabs editorTabs: IExtHostEditorTabs,
|
||||
@IExtHostVariableResolverProvider variableResolver: IExtHostVariableResolverProvider,
|
||||
@IExtHostCommands commands: IExtHostCommands
|
||||
@IExtHostCommands commands: IExtHostCommands,
|
||||
@IExtHostTesting testing: IExtHostTesting,
|
||||
) {
|
||||
super(extHostRpcService, workspaceService, extensionService, configurationService, editorTabs, variableResolver, commands);
|
||||
super(extHostRpcService, workspaceService, extensionService, configurationService, editorTabs, variableResolver, commands, testing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ import { MarshalledId } from 'vs/base/common/marshallingIds';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IExtensionDescription, IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ExtHostTestingShape, ILocationDto, MainContext, MainThreadTestingShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { ExtHostTestItemCollection, TestItemImpl, TestItemRootImpl, toItemFromContext } from 'vs/workbench/api/common/extHostTestItem';
|
||||
import * as Convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
@@ -45,7 +46,14 @@ let followupCounter = 0;
|
||||
|
||||
const testResultInternalIDs = new WeakMap<vscode.TestRunResult, string>();
|
||||
|
||||
export const IExtHostTesting = createDecorator<IExtHostTesting>('IExtHostTesting');
|
||||
export interface IExtHostTesting extends ExtHostTesting {
|
||||
readonly _serviceBrand: undefined;
|
||||
}
|
||||
|
||||
export class ExtHostTesting extends Disposable implements ExtHostTestingShape {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly resultsChangedEmitter = this._register(new Emitter<void>());
|
||||
protected readonly controllers = new Map</* controller ID */ string, ControllerInfo>();
|
||||
private readonly proxy: MainThreadTestingShape;
|
||||
@@ -61,8 +69,8 @@ export class ExtHostTesting extends Disposable implements ExtHostTestingShape {
|
||||
constructor(
|
||||
@IExtHostRpcService rpc: IExtHostRpcService,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
private readonly commands: ExtHostCommands,
|
||||
private readonly editors: ExtHostDocumentsAndEditors,
|
||||
@IExtHostCommands private readonly commands: IExtHostCommands,
|
||||
@IExtHostDocumentsAndEditors private readonly editors: IExtHostDocumentsAndEditors,
|
||||
) {
|
||||
super();
|
||||
this.proxy = rpc.getProxy(MainContext.MainThreadTesting);
|
||||
@@ -111,6 +119,8 @@ export class ExtHostTesting extends Disposable implements ExtHostTestingShape {
|
||||
});
|
||||
}
|
||||
|
||||
//#region public API
|
||||
|
||||
/**
|
||||
* Implements vscode.test.registerTestProvider
|
||||
*/
|
||||
@@ -236,6 +246,9 @@ export class ExtHostTesting extends Disposable implements ExtHostTestingShape {
|
||||
return { dispose: () => { this.followupProviders.delete(provider); } };
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region RPC methods
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@@ -412,6 +425,32 @@ export class ExtHostTesting extends Disposable implements ExtHostTestingShape {
|
||||
return this.commands.executeCommand(command.command, ...(command.arguments || []));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels an ongoing test run.
|
||||
*/
|
||||
public $cancelExtensionTestRun(runId: string | undefined) {
|
||||
if (runId === undefined) {
|
||||
this.runTracker.cancelAllRuns();
|
||||
} else {
|
||||
this.runTracker.cancelRunById(runId);
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
public getMetadataForRun(run: vscode.TestRun) {
|
||||
for (const tracker of this.runTracker.trackers) {
|
||||
const taskId = tracker.getTaskIdForRun(run);
|
||||
if (!taskId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { taskId, runId: tracker.id };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async runControllerTestRequest(req: ICallProfileRunHandler | ICallProfileRunHandler, isContinuous: boolean, token: CancellationToken): Promise<IStartControllerTestsResult> {
|
||||
const lookup = this.controllers.get(req.controllerId);
|
||||
if (!lookup) {
|
||||
@@ -467,17 +506,6 @@ export class ExtHostTesting extends Disposable implements ExtHostTestingShape {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels an ongoing test run.
|
||||
*/
|
||||
public $cancelExtensionTestRun(runId: string | undefined) {
|
||||
if (runId === undefined) {
|
||||
this.runTracker.cancelAllRuns();
|
||||
} else {
|
||||
this.runTracker.cancelRunById(runId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deadline after being requested by a user that a test run is forcibly cancelled.
|
||||
@@ -543,6 +571,17 @@ class TestRunTracker extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
/** Gets the task ID from a test run object. */
|
||||
public getTaskIdForRun(run: vscode.TestRun) {
|
||||
for (const [taskId, { run: r }] of this.tasks) {
|
||||
if (r === run) {
|
||||
return taskId;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Requests cancellation of the run. On the second call, forces cancellation. */
|
||||
public cancel() {
|
||||
if (this.state === TestRunTrackerState.Running) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/c
|
||||
import type * as vscode from 'vscode';
|
||||
import { ExtHostConfigProvider, IExtHostConfiguration } from '../common/extHostConfiguration';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
|
||||
|
||||
export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
|
||||
@@ -44,8 +45,9 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
|
||||
@IExtHostEditorTabs editorTabs: IExtHostEditorTabs,
|
||||
@IExtHostVariableResolverProvider variableResolver: IExtHostVariableResolverProvider,
|
||||
@IExtHostCommands commands: IExtHostCommands,
|
||||
@IExtHostTesting testing: IExtHostTesting,
|
||||
) {
|
||||
super(extHostRpcService, workspaceService, extensionService, configurationService, editorTabs, variableResolver, commands);
|
||||
super(extHostRpcService, workspaceService, extensionService, configurationService, editorTabs, variableResolver, commands, testing);
|
||||
}
|
||||
|
||||
protected override createDebugAdapter(adapter: IAdapterDescriptor, session: ExtHostDebugSession): AbstractDebugAdapter | undefined {
|
||||
|
||||
@@ -51,6 +51,7 @@ import { ViewModel } from 'vs/workbench/contrib/debug/common/debugViewModel';
|
||||
import { Debugger } from 'vs/workbench/contrib/debug/common/debugger';
|
||||
import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput';
|
||||
import { VIEWLET_ID as EXPLORER_VIEWLET_ID } from 'vs/workbench/contrib/files/common/files';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -112,6 +113,7 @@ export class DebugService implements IDebugService {
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService,
|
||||
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
|
||||
@ITestService private readonly testService: ITestService,
|
||||
) {
|
||||
this.breakpointsToSendOnResourceSaved = new Set<URI>();
|
||||
|
||||
@@ -839,6 +841,21 @@ export class DebugService implements IDebugService {
|
||||
}
|
||||
};
|
||||
|
||||
// For debug sessions spawned by test runs, cancel the test run and stop
|
||||
// the session, then start the test run again; tests have no notion of restarts.
|
||||
if (session.correlatedTestRun) {
|
||||
if (!session.correlatedTestRun.completedAt) {
|
||||
this.testService.cancelTestRun(session.correlatedTestRun.id);
|
||||
await Event.toPromise(session.correlatedTestRun.onComplete);
|
||||
// todo@connor4312 is there any reason to wait for the debug session to
|
||||
// terminate? I don't think so, test extension should already handle any
|
||||
// state conflicts...
|
||||
}
|
||||
|
||||
this.testService.runResolvedTests(session.correlatedTestRun.request);
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.capabilities.supportsRestartRequest) {
|
||||
const taskResult = await runTasks();
|
||||
if (taskResult === TaskRunResult.Success) {
|
||||
|
||||
@@ -42,6 +42,9 @@ import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/b
|
||||
import { getActiveWindow } from 'vs/base/browser/dom';
|
||||
import { mainWindow } from 'vs/base/browser/window';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { ITestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
|
||||
const TRIGGERED_BREAKPOINT_MAX_DELAY = 1500;
|
||||
|
||||
@@ -66,6 +69,11 @@ export class DebugSession implements IDebugSession, IDisposable {
|
||||
private stoppedDetails: IRawStoppedDetails[] = [];
|
||||
private readonly statusQueue = this.rawListeners.add(new ThreadStatusScheduler());
|
||||
|
||||
/** Test run this debug session was spawned by */
|
||||
public readonly correlatedTestRun?: LiveTestResult;
|
||||
/** Whether we terminated the correlated run yet. Used so a 2nd terminate request goes through to the underlying session. */
|
||||
private didTerminateTestRun?: boolean;
|
||||
|
||||
private readonly _onDidChangeState = new Emitter<void>();
|
||||
private readonly _onDidEndAdapter = new Emitter<AdapterEndEvent | undefined>();
|
||||
|
||||
@@ -106,7 +114,9 @@ export class DebugSession implements IDebugSession, IDisposable {
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@ICustomEndpointTelemetryService private readonly customEndpointTelemetryService: ICustomEndpointTelemetryService,
|
||||
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@ITestService private readonly testService: ITestService,
|
||||
@ITestResultService testResultService: ITestResultService,
|
||||
) {
|
||||
this._options = options || {};
|
||||
this.parentSession = this._options.parentSession;
|
||||
@@ -126,6 +136,16 @@ export class DebugSession implements IDebugSession, IDisposable {
|
||||
}));
|
||||
}
|
||||
|
||||
// Cast here, it's not possible to reference a hydrated result in this code path.
|
||||
this.correlatedTestRun = options?.testRun
|
||||
? (testResultService.getResult(options.testRun.runId) as LiveTestResult)
|
||||
: this.parentSession?.correlatedTestRun;
|
||||
|
||||
if (this.correlatedTestRun) {
|
||||
// Listen to the test completing because the user might have taken the cancel action rather than stopping the session.
|
||||
toDispose.add(this.correlatedTestRun.onComplete(() => this.terminate()));
|
||||
}
|
||||
|
||||
const compoundRoot = this._options.compoundRoot;
|
||||
if (compoundRoot) {
|
||||
toDispose.add(compoundRoot.onDidSessionStop(() => this.terminate()));
|
||||
@@ -387,6 +407,9 @@ export class DebugSession implements IDebugSession, IDisposable {
|
||||
this.cancelAllRequests();
|
||||
if (this._options.lifecycleManagedByParent && this.parentSession) {
|
||||
await this.parentSession.terminate(restart);
|
||||
} else if (this.correlatedTestRun && !this.correlatedTestRun.completedAt && !this.didTerminateTestRun) {
|
||||
this.didTerminateTestRun = true;
|
||||
this.testService.cancelTestRun(this.correlatedTestRun.id);
|
||||
} else if (this.raw) {
|
||||
if (this.raw.capabilities.supportsTerminateRequest && this._configuration.resolved.request === 'launch') {
|
||||
await this.raw.terminate(restart);
|
||||
|
||||
@@ -27,6 +27,7 @@ import { DebugCompoundRoot } from 'vs/workbench/contrib/debug/common/debugCompou
|
||||
import { IDataBreakpointOptions, IFunctionBreakpointOptions, IInstructionBreakpointOptions } from 'vs/workbench/contrib/debug/common/debugModel';
|
||||
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
|
||||
import { ITaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
|
||||
export const VIEWLET_ID = 'workbench.view.debug';
|
||||
@@ -219,6 +220,11 @@ export interface LoadedSourceEvent {
|
||||
|
||||
export type IDebugSessionReplMode = 'separate' | 'mergeWithParent';
|
||||
|
||||
export interface IDebugTestRunReference {
|
||||
runId: string;
|
||||
taskId: string;
|
||||
}
|
||||
|
||||
export interface IDebugSessionOptions {
|
||||
noDebug?: boolean;
|
||||
parentSession?: IDebugSession;
|
||||
@@ -231,6 +237,11 @@ export interface IDebugSessionOptions {
|
||||
suppressDebugToolbar?: boolean;
|
||||
suppressDebugStatusbar?: boolean;
|
||||
suppressDebugView?: boolean;
|
||||
/**
|
||||
* Set if the debug session is correlated with a test run. Stopping/restarting
|
||||
* the session will instead stop/restart the test run.
|
||||
*/
|
||||
testRun?: IDebugTestRunReference;
|
||||
}
|
||||
|
||||
export interface IDataBreakpointInfoResponse {
|
||||
@@ -353,6 +364,8 @@ export interface IDebugSession extends ITreeElement {
|
||||
readonly suppressDebugStatusbar: boolean;
|
||||
readonly suppressDebugView: boolean;
|
||||
readonly lifecycleManagedByParent: boolean;
|
||||
/** Test run this debug session was spawned by */
|
||||
readonly correlatedTestRun?: LiveTestResult;
|
||||
|
||||
setSubId(subId: string | undefined): void;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ export function createTestSession(model: DebugModel, name = 'mockSession', optio
|
||||
}
|
||||
};
|
||||
}
|
||||
} as IDebugService, undefined!, undefined!, new TestConfigurationService({ debug: { console: { collapseIdenticalLines: true } } }), undefined!, mockWorkspaceContextService, undefined!, undefined!, undefined!, mockUriIdentityService, new TestInstantiationService(), undefined!, undefined!, new NullLogService());
|
||||
} as IDebugService, undefined!, undefined!, new TestConfigurationService({ debug: { console: { collapseIdenticalLines: true } } }), undefined!, mockWorkspaceContextService, undefined!, undefined!, undefined!, mockUriIdentityService, new TestInstantiationService(), undefined!, undefined!, new NullLogService(), undefined!, undefined!);
|
||||
}
|
||||
|
||||
function createTwoStackFrames(session: DebugSession): { firstStackFrame: StackFrame; secondStackFrame: StackFrame } {
|
||||
@@ -445,7 +445,7 @@ suite('Debug - CallStack', () => {
|
||||
override get state(): State {
|
||||
return State.Stopped;
|
||||
}
|
||||
}(generateUuid(), { resolved: { name: 'stoppedSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, mockWorkspaceContextService, undefined!, undefined!, undefined!, mockUriIdentityService, new TestInstantiationService(), undefined!, undefined!, new NullLogService());
|
||||
}(generateUuid(), { resolved: { name: 'stoppedSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, mockWorkspaceContextService, undefined!, undefined!, undefined!, mockUriIdentityService, new TestInstantiationService(), undefined!, undefined!, new NullLogService(), undefined!, undefined!);
|
||||
disposables.add(session);
|
||||
|
||||
const runningSession = createTestSession(model);
|
||||
|
||||
@@ -118,6 +118,7 @@ export const allApiProposals = Object.freeze({
|
||||
terminalSelection: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalSelection.d.ts',
|
||||
terminalShellIntegration: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalShellIntegration.d.ts',
|
||||
testObserver: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testObserver.d.ts',
|
||||
testRunInDebug: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testRunInDebug.d.ts',
|
||||
textSearchProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchProvider.d.ts',
|
||||
timeline: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.timeline.d.ts',
|
||||
tokenInformation: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.tokenInformation.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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user