Skip to content

Commit 804a059

Browse files
committed
✅ reattach tests
1 parent f3e1a0e commit 804a059

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
'use strict';
5+
6+
// tslint:disable:no-invalid-this max-func-body-length no-empty no-increment-decrement
7+
8+
import { expect } from 'chai';
9+
import { ChildProcess, spawn } from 'child_process';
10+
import * as getFreePort from 'get-port';
11+
import * as path from 'path';
12+
import { DebugClient } from 'vscode-debugadapter-testsupport';
13+
import { EXTENSION_ROOT_DIR } from '../../client/common/constants';
14+
import '../../client/common/extensions';
15+
import { IS_WINDOWS } from '../../client/common/platform/constants';
16+
import { sleep } from '../common';
17+
import { initialize, IS_APPVEYOR, IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize';
18+
import { DEBUGGER_TIMEOUT } from './common/constants';
19+
import { DebugClientEx } from './debugClient';
20+
21+
const fileToDebug = path.join(EXTENSION_ROOT_DIR, 'src', 'testMultiRootWkspc', 'workspace5', 'remoteDebugger-start-with-ptvsd.re-attach.py');
22+
const ptvsdPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd');
23+
const DEBUG_ADAPTER = path.join(EXTENSION_ROOT_DIR, 'out', 'client', 'debugger', 'mainV2.js');
24+
25+
suite('Attach Debugger - detach and again again - Experimental', () => {
26+
let debugClient: DebugClient;
27+
let procToKill: ChildProcess;
28+
suiteSetup(initialize);
29+
30+
setup(async function () {
31+
if (!IS_MULTI_ROOT_TEST || !TEST_DEBUGGER) {
32+
this.skip();
33+
}
34+
await startDebugger();
35+
});
36+
teardown(async () => {
37+
// Wait for a second before starting another test (sometimes, sockets take a while to get closed).
38+
await sleep(1000);
39+
try {
40+
await debugClient.stop().catch(() => { });
41+
} catch (ex) { }
42+
if (procToKill) {
43+
try {
44+
procToKill.kill();
45+
} catch { }
46+
}
47+
});
48+
async function startDebugger() {
49+
await sleep(1000);
50+
debugClient = createDebugAdapter();
51+
debugClient.defaultTimeout = DEBUGGER_TIMEOUT;
52+
debugClient.defaultTimeout = 1000000;
53+
await debugClient.start();
54+
}
55+
/**
56+
* Creates the debug aimport { AttachRequestArguments } from '../../client/debugger/Common/Contracts';
57+
* We do not need to support code coverage on AppVeyor, lets use the standard test adapter.
58+
* @returns {DebugClient}
59+
*/
60+
function createDebugAdapter(): DebugClient {
61+
if (IS_WINDOWS) {
62+
return new DebugClient('node', DEBUG_ADAPTER, 'pythonExperimental');
63+
} else {
64+
const coverageDirectory = path.join(EXTENSION_ROOT_DIR, 'debug_coverage_attach_ptvsd');
65+
return new DebugClientEx(DEBUG_ADAPTER, 'pythonExperimental', coverageDirectory, { cwd: EXTENSION_ROOT_DIR });
66+
}
67+
}
68+
async function startRemoteProcess() {
69+
const port = await getFreePort({ host: 'localhost', port: 9091 });
70+
const customEnv = { ...process.env };
71+
72+
// Set the path for PTVSD to be picked up.
73+
// tslint:disable-next-line:no-string-literal
74+
customEnv['PYTHONPATH'] = ptvsdPath;
75+
const pythonArgs = ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', fileToDebug.fileToCommandArgument()];
76+
procToKill = spawn('python', pythonArgs, { env: customEnv, cwd: path.dirname(fileToDebug) });
77+
return port;
78+
}
79+
80+
async function waitForDebuggerCondfigurationDone(port: number) {
81+
// Send initialize, attach
82+
const initializePromise = debugClient.initializeRequest({
83+
adapterID: 'pythonExperimental',
84+
linesStartAt1: true,
85+
columnsStartAt1: true,
86+
supportsRunInTerminalRequest: true,
87+
pathFormat: 'path',
88+
supportsVariableType: true,
89+
supportsVariablePaging: true
90+
});
91+
const attachPromise = debugClient.attachRequest({
92+
localRoot: path.dirname(fileToDebug),
93+
remoteRoot: path.dirname(fileToDebug),
94+
type: 'pythonExperimental',
95+
port: port,
96+
host: 'localhost',
97+
logToFile: false,
98+
debugOptions: ['RedirectOutput']
99+
});
100+
101+
await Promise.all([
102+
initializePromise,
103+
attachPromise,
104+
debugClient.waitForEvent('initialized')
105+
]);
106+
107+
await debugClient.configurationDoneRequest();
108+
}
109+
async function testAttaching(port: number) {
110+
await waitForDebuggerCondfigurationDone(port);
111+
let threads = await debugClient.threadsRequest();
112+
expect(threads).to.be.not.equal(undefined, 'no threads response');
113+
expect(threads.body.threads).to.be.lengthOf(1);
114+
115+
await debugClient.setExceptionBreakpointsRequest({ filters: [] });
116+
const breakpointLocation = { path: fileToDebug, column: 1, line: 7 };
117+
await debugClient.setBreakpointsRequest({
118+
lines: [breakpointLocation.line],
119+
breakpoints: [{ line: breakpointLocation.line, column: breakpointLocation.column }],
120+
source: { path: breakpointLocation.path }
121+
});
122+
123+
await debugClient.assertStoppedLocation('breakpoint', breakpointLocation);
124+
await debugClient.setBreakpointsRequest({ lines: [], breakpoints: [], source: { path: breakpointLocation.path } });
125+
126+
threads = await debugClient.threadsRequest();
127+
expect(threads).to.be.not.equal(undefined, 'no threads response');
128+
expect(threads.body.threads).to.be.lengthOf(1);
129+
130+
await debugClient.continueRequest({ threadId: threads.body.threads[0].id });
131+
}
132+
133+
test('Confirm we are able to attach, detach and attach to a running program', async function () {
134+
this.timeout(20000);
135+
// Lets skip this test on AppVeyor (very flaky on AppVeyor).
136+
if (IS_APPVEYOR) {
137+
return;
138+
}
139+
140+
const port = await startRemoteProcess();
141+
await testAttaching(port);
142+
await debugClient.disconnectRequest({});
143+
await startDebugger();
144+
await testAttaching(port);
145+
146+
const terminatedPromise = debugClient.waitForEvent('terminated');
147+
procToKill.kill();
148+
await terminatedPromise;
149+
});
150+
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import sys
2+
import time
3+
# Give the debugger some time to add a breakpoint.
4+
time.sleep(5)
5+
for i in range(10000):
6+
time.sleep(0.5)
7+
print(i)
8+
9+
print('bye')

0 commit comments

Comments
 (0)