Skip to content

Commit 3c6520a

Browse files
committed
Merge remote-tracking branch 'upstream/master'
* upstream/master: Fix debugging tests (#304)
2 parents 4553c28 + 2b7dc71 commit 3c6520a

File tree

7 files changed

+51
-26
lines changed

7 files changed

+51
-26
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@
15681568
"diff-match-patch": "^1.0.0",
15691569
"fs-extra": "^4.0.2",
15701570
"fuzzy": "^0.1.3",
1571+
"get-port": "^3.2.0",
15711572
"line-by-line": "^0.1.5",
15721573
"lodash": "^4.17.4",
15731574
"minimatch": "^3.0.3",
@@ -1591,6 +1592,7 @@
15911592
"@types/chai": "^4.0.4",
15921593
"@types/chai-as-promised": "^7.1.0",
15931594
"@types/fs-extra": "^4.0.2",
1595+
"@types/get-port": "^3.2.0",
15941596
"@types/jquery": "^1.10.31",
15951597
"@types/lodash": "^4.14.74",
15961598
"@types/mocha": "^2.2.43",

src/client/unittests/common/debugLauncher.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,36 @@
1+
import * as getFreePort from 'get-port';
12
import * as os from 'os';
23
import { CancellationToken, debug, OutputChannel, Uri, workspace } from 'vscode';
34
import { PythonSettings } from '../../common/configSettings';
45
import { createDeferred } from './../../common/helpers';
56
import { execPythonFile } from './../../common/utils';
67
import { ITestDebugLauncher } from './types';
78

9+
const HAND_SHAKE = `READY${os.EOL}`;
10+
811
export class DebugLauncher implements ITestDebugLauncher {
9-
public async launchDebugger(rootDirectory: string, testArgs: string[], token?: CancellationToken, outChannel?: OutputChannel) {
12+
public getPort(resource?: Uri): Promise<number> {
13+
const pythonSettings = PythonSettings.getInstance(resource);
14+
const port = pythonSettings.unitTest.debugPort;
15+
return new Promise<number>((resolve, reject) => getFreePort({ host: 'localhost', port }).then(resolve, reject));
16+
}
17+
public async launchDebugger(rootDirectory: string, testArgs: string[], port: number, token?: CancellationToken, outChannel?: OutputChannel) {
1018
const pythonSettings = PythonSettings.getInstance(rootDirectory ? Uri.file(rootDirectory) : undefined);
1119
// tslint:disable-next-line:no-any
1220
const def = createDeferred<any>();
1321
// tslint:disable-next-line:no-any
1422
const launchDef = createDeferred<any>();
1523
let outputChannelShown = false;
24+
let accumulatedData: string = '';
1625
execPythonFile(rootDirectory, pythonSettings.pythonPath, testArgs, rootDirectory, true, (data: string) => {
17-
if (data.startsWith(`READY${os.EOL}`)) {
18-
// debug socket server has started.
26+
if (!launchDef.resolved) {
27+
accumulatedData += data;
28+
if (!accumulatedData.startsWith(HAND_SHAKE)) {
29+
return;
30+
}
31+
// Socket server has started, lets start the debugger.
1932
launchDef.resolve();
20-
data = data.substring((`READY${os.EOL}`).length);
33+
data = accumulatedData.substring(HAND_SHAKE.length);
2134
}
2235

2336
if (!outputChannelShown) {
@@ -53,7 +66,7 @@ export class DebugLauncher implements ITestDebugLauncher {
5366
request: 'attach',
5467
localRoot: rootDirectory,
5568
remoteRoot: rootDirectory,
56-
port: pythonSettings.unitTest.debugPort,
69+
port,
5770
secret: 'my_secret',
5871
host: 'localhost'
5972
});

src/client/unittests/common/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,6 @@ export interface ITestResultsService {
148148
}
149149

150150
export interface ITestDebugLauncher {
151-
launchDebugger(rootDirectory: string, testArgs: string[], token?: CancellationToken, outChannel?: OutputChannel): Promise<Tests>;
151+
getPort(resource?: Uri): Promise<number>;
152+
launchDebugger(rootDirectory: string, testArgs: string[], port: number, token?: CancellationToken, outChannel?: OutputChannel): Promise<Tests>;
152153
}

src/client/unittests/nosetest/runner.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,17 @@ export function runTest(testResultsService: ITestResultsService, debugLauncher:
5858
}
5959

6060
return promiseToGetXmlLogFile.then(() => {
61-
const pythonSettings = PythonSettings.getInstance(Uri.file(rootDirectory));
6261
if (debug === true) {
63-
const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py');
64-
const nosetestlauncherargs = [rootDirectory, 'my_secret', pythonSettings.unitTest.debugPort.toString(), 'nose'];
65-
const debuggerArgs = [testLauncherFile].concat(nosetestlauncherargs).concat(noseTestArgs.concat(testPaths));
66-
// tslint:disable-next-line:prefer-type-cast no-any
67-
return debugLauncher.launchDebugger(rootDirectory, debuggerArgs, token, outChannel) as Promise<any>;
62+
return debugLauncher.getPort(Uri.file(rootDirectory))
63+
.then(debugPort => {
64+
const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py');
65+
const nosetestlauncherargs = [rootDirectory, 'my_secret', debugPort.toString(), 'nose'];
66+
const debuggerArgs = [testLauncherFile].concat(nosetestlauncherargs).concat(noseTestArgs.concat(testPaths));
67+
// tslint:disable-next-line:prefer-type-cast no-any
68+
return debugLauncher.launchDebugger(rootDirectory, debuggerArgs, debugPort, token, outChannel) as Promise<any>;
69+
});
6870
} else {
71+
const pythonSettings = PythonSettings.getInstance(Uri.file(rootDirectory));
6972
// tslint:disable-next-line:prefer-type-cast no-any
7073
return run(pythonSettings.unitTest.nosetestPath, noseTestArgs.concat(testPaths), rootDirectory, token, outChannel) as Promise<any>;
7174
}

src/client/unittests/pytest/runner.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@ export function runTest(testResultsService: ITestResultsService, debugLauncher:
3333
args = args.filter(arg => arg.trim().startsWith('-'));
3434
}
3535
const testArgs = testPaths.concat(args, [`--junitxml=${xmlLogFile}`]);
36-
const pythonSettings = PythonSettings.getInstance(Uri.file(rootDirectory));
3736
if (debug) {
38-
const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py');
39-
const pytestlauncherargs = [rootDirectory, 'my_secret', pythonSettings.unitTest.debugPort.toString(), 'pytest'];
40-
const debuggerArgs = [testLauncherFile].concat(pytestlauncherargs).concat(testArgs);
41-
// tslint:disable-next-line:prefer-type-cast no-any
42-
return debugLauncher.launchDebugger(rootDirectory, debuggerArgs, token, outChannel) as Promise<any>;
37+
return debugLauncher.getPort(Uri.file(rootDirectory))
38+
.then(debugPort => {
39+
const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py');
40+
const pytestlauncherargs = [rootDirectory, 'my_secret', debugPort.toString(), 'pytest'];
41+
const debuggerArgs = [testLauncherFile].concat(pytestlauncherargs).concat(testArgs);
42+
// tslint:disable-next-line:prefer-type-cast no-any
43+
return debugLauncher.launchDebugger(rootDirectory, debuggerArgs, debugPort, token, outChannel) as Promise<any>;
44+
});
4345
} else {
46+
const pythonSettings = PythonSettings.getInstance(Uri.file(rootDirectory));
4447
// tslint:disable-next-line:prefer-type-cast no-any
4548
return run(pythonSettings.unitTest.pyTestPath, testArgs, rootDirectory, token, outChannel) as Promise<any>;
4649
}

src/client/unittests/unittest/runner.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ export function runTest(testManager: BaseTestManager, testResultsService: ITestR
8585
testArgs = testArgs.filter(arg => arg !== '--uf');
8686

8787
testArgs.push(`--result-port=${port}`);
88-
if (debug === true) {
89-
const debugPort = PythonSettings.getInstance(Uri.file(rootDirectory)).unitTest.debugPort;
90-
testArgs.push(...['--secret=my_secret', `--port=${debugPort}`]);
91-
}
9288
testArgs.push(`--us=${startTestDiscoveryDirectory}`);
9389
if (testId.length > 0) {
9490
testArgs.push(`-t${testId}`);
@@ -97,8 +93,12 @@ export function runTest(testManager: BaseTestManager, testResultsService: ITestR
9793
testArgs.push(`--testFile=${testFile}`);
9894
}
9995
if (debug === true) {
100-
// tslint:disable-next-line:prefer-type-cast no-any
101-
return debugLauncher.launchDebugger(rootDirectory, [testLauncherFile].concat(testArgs), token, outChannel);
96+
return debugLauncher.getPort(Uri.file(rootDirectory))
97+
.then(debugPort => {
98+
testArgs.push(...['--secret=my_secret', `--port=${debugPort}`]);
99+
// tslint:disable-next-line:prefer-type-cast no-any
100+
return debugLauncher.launchDebugger(rootDirectory, [testLauncherFile].concat(testArgs), debugPort, token, outChannel);
101+
});
102102
} else {
103103
// tslint:disable-next-line:prefer-type-cast no-any
104104
return run(PythonSettings.getInstance(Uri.file(rootDirectory)).pythonPath, [testLauncherFile].concat(testArgs), rootDirectory, token, outChannel);

src/test/unittests/mocks.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CancellationToken, Disposable, OutputChannel } from 'vscode';
1+
import { CancellationToken, Disposable, OutputChannel, Uri } from 'vscode';
22
import { createDeferred, Deferred } from '../../client/common/helpers';
33
import { Product } from '../../client/common/installer';
44
import { BaseTestManager } from '../../client/unittests/common/baseTestManager';
@@ -25,7 +25,10 @@ export class MockDebugLauncher implements ITestDebugLauncher, Disposable {
2525
constructor() {
2626
this._launched = createDeferred<boolean>();
2727
}
28-
public async launchDebugger(rootDirectory: string, testArgs: string[], token?: CancellationToken, outChannel?: OutputChannel): Promise<Tests> {
28+
public async getPort(resource?: Uri): Promise<number> {
29+
return 0;
30+
}
31+
public async launchDebugger(rootDirectory: string, testArgs: string[], debugPort: number, token?: CancellationToken, outChannel?: OutputChannel): Promise<Tests> {
2932
this._launched.resolve(true);
3033
// tslint:disable-next-line:no-non-null-assertion
3134
this._token = token!;

0 commit comments

Comments
 (0)