Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass parent debug session to child debug sessions using new DA API #5581

Merged
merged 5 commits into from
May 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/1 Enhancements/5464.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Pass parent debug session to child debug sessions using new DA API
4 changes: 2 additions & 2 deletions src/client/common/application/debugService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ export class DebugService implements IDebugService {
public registerDebugConfigurationProvider(debugType: string, provider: any): Disposable {
return debug.registerDebugConfigurationProvider(debugType, provider);
}
public startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration): Thenable<boolean> {
return debug.startDebugging(folder, nameOrConfiguration);
public startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSession?: DebugSession): Thenable<boolean> {
return debug.startDebugging(folder, nameOrConfiguration, parentSession);
}
public addBreakpoints(breakpoints: Breakpoint[]): void {
debug.addBreakpoints(breakpoints);
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/application/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -774,7 +774,7 @@ export interface IDebugService {
* @param nameOrConfiguration Either the name of a debug or compound configuration or a [DebugConfiguration](#DebugConfiguration) object.
* @return A thenable that resolves when debugging could be successfully started.
*/
startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration): Thenable<boolean>;
startDebugging(folder: WorkspaceFolder | undefined, nameOrConfiguration: string | DebugConfiguration, parentSession?: DebugSession): Thenable<boolean>;

/**
* Add breakpoints.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ export class ChildProcessAttachEventHandler implements IDebugSessionEventHandler
return;
}
const data = event.body! as ChildProcessLaunchData;
await this.childProcessAttachService.attach(data);
await this.childProcessAttachService.attach(data, event.session);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'use strict';

import { inject, injectable } from 'inversify';
import { DebugConfiguration, WorkspaceFolder } from 'vscode';
import { DebugConfiguration, DebugSession, WorkspaceFolder } from 'vscode';
import { IApplicationShell, IDebugService, IWorkspaceService } from '../../../common/application/types';
import { noop } from '../../../common/utils/misc';
import { captureTelemetry } from '../../../telemetry';
Expand All @@ -26,10 +26,10 @@ export class ChildProcessAttachService implements IChildProcessAttachService {
@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService) { }

@captureTelemetry(EventName.DEBUGGER_ATTACH_TO_CHILD_PROCESS)
public async attach(data: ChildProcessLaunchData): Promise<void> {
public async attach(data: ChildProcessLaunchData, parentSession: DebugSession): Promise<void> {
const folder = this.getRelatedWorkspaceFolder(data);
const debugConfig = this.getAttachConfiguration(data);
const launched = await this.debugService.startDebugging(folder, debugConfig);
const launched = await this.debugService.startDebugging(folder, debugConfig, parentSession);
if (!launched) {
this.appShell.showErrorMessage(`Failed to launch debugger for child process ${data.processId}`).then(noop, noop);
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/debugger/extension/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ export type ChildProcessLaunchData = {

export const IChildProcessAttachService = Symbol('IChildProcessAttachService');
export interface IChildProcessAttachService {
attach(data: ChildProcessLaunchData): Promise<void>;
attach(data: ChildProcessLaunchData, parentSession: DebugSession): Promise<void>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

// tslint:disable:no-any

import { instance, mock, verify, when } from 'ts-mockito';
import { expect } from 'chai';
import { anything, capture, instance, mock, verify, when } from 'ts-mockito';
import { ChildProcessAttachEventHandler } from '../../../../client/debugger/extension/hooks/childProcessAttachHandler';
import { ChildProcessAttachService } from '../../../../client/debugger/extension/hooks/childProcessAttachService';
import { PTVSDEvents } from '../../../../client/debugger/extension/hooks/constants';
Expand All @@ -15,15 +16,17 @@ suite('Debug - Child Process', () => {
const attachService = mock(ChildProcessAttachService);
const handler = new ChildProcessAttachEventHandler(instance(attachService));
const body: any = {};
await handler.handleCustomEvent({ event: 'abc', body, session: {} as any });
verify(attachService.attach(body)).never();
const session: any = {};
await handler.handleCustomEvent({ event: 'abc', body, session });
verify(attachService.attach(body, session)).never();
});
test('Do not attach to child process if event is invalid', async () => {
const attachService = mock(ChildProcessAttachService);
const handler = new ChildProcessAttachEventHandler(instance(attachService));
const body: any = {};
await handler.handleCustomEvent({ event: PTVSDEvents.ChildProcessLaunched, body, session: {} as any });
verify(attachService.attach(body)).once();
const session: any = {};
await handler.handleCustomEvent({ event: PTVSDEvents.ChildProcessLaunched, body, session });
verify(attachService.attach(body, session)).once();
});
test('Exceptions are not bubbled up if data is invalid', async () => {
const attachService = mock(ChildProcessAttachService);
Expand All @@ -34,8 +37,11 @@ suite('Debug - Child Process', () => {
const attachService = mock(ChildProcessAttachService);
const handler = new ChildProcessAttachEventHandler(instance(attachService));
const body: any = {};
when(attachService.attach(body)).thenThrow(new Error('Kaboom'));
const session: any = {};
when(attachService.attach(body, session)).thenThrow(new Error('Kaboom'));
await handler.handleCustomEvent({ event: PTVSDEvents.ChildProcessLaunched, body, session: {} as any });
verify(attachService.attach(body)).once();
verify(attachService.attach(body, anything())).once();
const [, secondArg] = capture(attachService.attach).last();
expect(secondArg).to.deep.equal(session);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ suite('Debug - Attach to Child Process', () => {
command: 'request'
}
};

const session: any = {};
when(workspaceService.hasWorkspaceFolders).thenReturn(false);
when(debugService.startDebugging(anything(), anything())).thenResolve(true as any);
await service.attach(data);
when(debugService.startDebugging(anything(), anything(), anything())).thenResolve(true as any);
await service.attach(data, session);
verify(workspaceService.hasWorkspaceFolders).once();
verify(debugService.startDebugging(anything(), anything())).once();
verify(debugService.startDebugging(anything(), anything(), anything())).once();
});
test('Message is displayed if debugger is not launched', async () => {
const shell = mock(ApplicationShell);
Expand All @@ -68,14 +68,15 @@ suite('Debug - Attach to Child Process', () => {
}
};

const session: any = {};
when(workspaceService.hasWorkspaceFolders).thenReturn(false);
when(debugService.startDebugging(anything(), anything())).thenResolve(false as any);
when(debugService.startDebugging(anything(), anything(), anything())).thenResolve(false as any);
when(shell.showErrorMessage(anything())).thenResolve();

await service.attach(data);
await service.attach(data, session);

verify(workspaceService.hasWorkspaceFolders).once();
verify(debugService.startDebugging(anything(), anything())).once();
verify(debugService.startDebugging(anything(), anything(), anything())).once();
verify(shell.showErrorMessage(anything())).once();
});
test('Use correct workspace folder', async () => {
Expand Down Expand Up @@ -106,14 +107,15 @@ suite('Debug - Attach to Child Process', () => {
}
};

const session: any = {};
when(workspaceService.hasWorkspaceFolders).thenReturn(true);
when(workspaceService.workspaceFolders).thenReturn([wkspace1, rightWorkspaceFolder, wkspace2]);
when(debugService.startDebugging(rightWorkspaceFolder, anything())).thenResolve(true as any);
when(debugService.startDebugging(rightWorkspaceFolder, anything(), anything())).thenResolve(true as any);

await service.attach(data);
await service.attach(data, session);

verify(workspaceService.hasWorkspaceFolders).once();
verify(debugService.startDebugging(rightWorkspaceFolder, anything())).once();
verify(debugService.startDebugging(rightWorkspaceFolder, anything(), anything())).once();
verify(shell.showErrorMessage(anything())).never();
});
test('Use empty workspace folder if right one is not found', async () => {
Expand Down Expand Up @@ -144,14 +146,15 @@ suite('Debug - Attach to Child Process', () => {
}
};

const session: any = {};
when(workspaceService.hasWorkspaceFolders).thenReturn(true);
when(workspaceService.workspaceFolders).thenReturn([wkspace1, wkspace2]);
when(debugService.startDebugging(undefined, anything())).thenResolve(true as any);
when(debugService.startDebugging(undefined, anything(), anything())).thenResolve(true as any);

await service.attach(data);
await service.attach(data, session);

verify(workspaceService.hasWorkspaceFolders).once();
verify(debugService.startDebugging(undefined, anything())).once();
verify(debugService.startDebugging(undefined, anything(), anything())).once();
verify(shell.showErrorMessage(anything())).never();
});
test('Validate debug config when parent/root parent was launched', async () => {
Expand Down Expand Up @@ -183,17 +186,18 @@ suite('Debug - Attach to Child Process', () => {
debugConfig.port = data.port;
debugConfig.name = `Child Process ${data.processId}`;
debugConfig.request = 'attach';
const session: any = {};

when(workspaceService.hasWorkspaceFolders).thenReturn(false);
when(debugService.startDebugging(undefined, anything())).thenResolve(true as any);
// when(debugService.startDebugging(undefined, debugConfig)).thenResolve(true as any);
when(debugService.startDebugging(undefined, anything(), anything())).thenResolve(true as any);

await service.attach(data);
await service.attach(data, session);

verify(workspaceService.hasWorkspaceFolders).once();
verify(debugService.startDebugging(undefined, anything())).once();
const [, secondArg] = capture(debugService.startDebugging).last();
verify(debugService.startDebugging(undefined, anything(), anything())).once();
const [, secondArg, thirdArg] = capture(debugService.startDebugging).last();
expect(secondArg).to.deep.equal(debugConfig);
expect(thirdArg).to.deep.equal(session);
verify(shell.showErrorMessage(anything())).never();
});
test('Validate debug config when parent/root parent was attached', async () => {
Expand Down Expand Up @@ -226,17 +230,18 @@ suite('Debug - Attach to Child Process', () => {
debugConfig.port = data.port;
debugConfig.name = `Child Process ${data.processId}`;
debugConfig.request = 'attach';
const session: any = {};

when(workspaceService.hasWorkspaceFolders).thenReturn(false);
when(debugService.startDebugging(undefined, anything())).thenResolve(true as any);
// when(debugService.startDebugging(undefined, debugConfig)).thenResolve(true as any);
when(debugService.startDebugging(undefined, anything(), anything())).thenResolve(true as any);

await service.attach(data);
await service.attach(data, session);

verify(workspaceService.hasWorkspaceFolders).once();
verify(debugService.startDebugging(undefined, anything())).once();
const [, secondArg] = capture(debugService.startDebugging).last();
verify(debugService.startDebugging(undefined, anything(), anything())).once();
const [, secondArg, thirdArg] = capture(debugService.startDebugging).last();
expect(secondArg).to.deep.equal(debugConfig);
expect(thirdArg).to.deep.equal(session);
verify(shell.showErrorMessage(anything())).never();
});
});