diff --git a/src/client/unittests/common/debugLauncher.ts b/src/client/unittests/common/debugLauncher.ts new file mode 100644 index 000000000000..099bfaa5b377 --- /dev/null +++ b/src/client/unittests/common/debugLauncher.ts @@ -0,0 +1,63 @@ +import * as os from 'os'; +import { CancellationToken, debug, OutputChannel, workspace, Uri } from 'vscode'; +import { PythonSettings } from '../../common/configSettings'; +import { execPythonFile } from './../../common/utils'; +import { createDeferred } from './../../common/helpers'; + +const pythonSettings = PythonSettings.getInstance(); +export function launchDebugger(rootDirectory: string, testArgs: string[], token?: CancellationToken, outChannel?: OutputChannel) { + const def = createDeferred(); + const launchDef = createDeferred(); + let outputChannelShown = false; + execPythonFile(pythonSettings.pythonPath, testArgs, rootDirectory, true, (data: string) => { + if (data.startsWith('READY' + os.EOL)) { + // debug socket server has started. + launchDef.resolve(); + data = data.substring(('READY' + os.EOL).length); + } + + if (!outputChannelShown) { + outputChannelShown = true; + outChannel.show(); + } + outChannel.append(data); + }, token).catch(reason => { + if (!def.rejected && !def.resolved) { + def.reject(reason); + } + }).then(() => { + if (!def.rejected && !def.resolved) { + def.resolve(); + } + }).catch(reason => { + if (!def.rejected && !def.resolved) { + def.reject(reason); + } + }); + + launchDef.promise.then(() => { + if (!Array.isArray(workspace.workspaceFolders) || workspace.workspaceFolders.length === 0) { + throw new Error('Please open a workspace'); + } + let workspaceFolder = workspace.getWorkspaceFolder(Uri.file(rootDirectory)); + if (!workspaceFolder) { + workspaceFolder = workspace.workspaceFolders[0]; + } + return debug.startDebugging(workspaceFolder, { + "name": "Debug Unit Test", + "type": "python", + "request": "attach", + "localRoot": rootDirectory, + "remoteRoot": rootDirectory, + "port": pythonSettings.unitTest.debugPort, + "secret": "my_secret", + "host": "localhost" + }); + }).catch(reason => { + if (!def.rejected && !def.resolved) { + def.reject(reason); + } + }); + + return def.promise; +} diff --git a/src/client/unittests/nosetest/runner.ts b/src/client/unittests/nosetest/runner.ts index 14c0d3251300..fdaba3ff8254 100644 --- a/src/client/unittests/nosetest/runner.ts +++ b/src/client/unittests/nosetest/runner.ts @@ -6,11 +6,8 @@ import { updateResults } from '../common/testUtils'; import { updateResultsFromXmlLogFile, PassCalculationFormulae } from '../common/xUnitParser'; import { run } from '../common/runner'; import { PythonSettings } from '../../common/configSettings'; -import * as vscode from 'vscode'; -import { execPythonFile } from './../../common/utils'; -import { createDeferred } from './../../common/helpers'; -import * as os from 'os'; import * as path from 'path'; +import { launchDebugger } from '../common/debugLauncher'; const pythonSettings = PythonSettings.getInstance(); const WITH_XUNIT = '--with-xunit'; @@ -65,58 +62,10 @@ export function runTest(rootDirectory: string, tests: Tests, args: string[], tes return promiseToGetXmlLogFile.then(() => { if (debug === true) { - const def = createDeferred(); - const launchDef = createDeferred(); const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py'); - - // start the debug adapter only once we have started the debug process - // pytestlauncherargs const nosetestlauncherargs = [rootDirectory, 'my_secret', pythonSettings.unitTest.debugPort.toString(), 'nose']; - let outputChannelShown = false; - execPythonFile(pythonSettings.pythonPath, [testLauncherFile].concat(nosetestlauncherargs).concat(noseTestArgs.concat(testPaths)), rootDirectory, true, (data: string) => { - if (data.startsWith('READY' + os.EOL)) { - // debug socket server has started - launchDef.resolve(); - data = data.substring(('READY' + os.EOL).length); - } - - if (!outputChannelShown) { - outputChannelShown = true; - outChannel.show(); - } - outChannel.append(data); - }, token).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }).then(() => { - if (!def.rejected && !def.resolved) { - def.resolve(); - } - }).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }); - - launchDef.promise.then(() => { - return vscode.commands.executeCommand('vscode.startDebug', { - "name": "Debug Unit Test", - "type": "python", - "request": "attach", - "localRoot": rootDirectory, - "remoteRoot": rootDirectory, - "port": pythonSettings.unitTest.debugPort, - "secret": "my_secret", - "host": "localhost" - }); - }).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }); - - return def.promise; + const args = [testLauncherFile].concat(nosetestlauncherargs).concat(noseTestArgs.concat(testPaths)); + return launchDebugger(rootDirectory, args, token, outChannel); } else { return run(pythonSettings.unitTest.nosetestPath, noseTestArgs.concat(testPaths), rootDirectory, token, outChannel); diff --git a/src/client/unittests/pytest/runner.ts b/src/client/unittests/pytest/runner.ts index 40c5137653d0..eb564b57c015 100644 --- a/src/client/unittests/pytest/runner.ts +++ b/src/client/unittests/pytest/runner.ts @@ -8,11 +8,8 @@ import { CancellationToken, OutputChannel } from 'vscode'; import { updateResultsFromXmlLogFile, PassCalculationFormulae } from '../common/xUnitParser'; import { run } from '../common/runner'; import { PythonSettings } from '../../common/configSettings'; -import * as vscode from 'vscode'; -import { execPythonFile } from './../../common/utils'; -import { createDeferred } from './../../common/helpers'; -import * as os from 'os'; import * as path from 'path'; +import { launchDebugger } from '../common/debugLauncher'; const pythonSettings = PythonSettings.getInstance(); @@ -43,58 +40,10 @@ export function runTest(rootDirectory: string, tests: Tests, args: string[], tes } const testArgs = testPaths.concat(args, [`--junitxml=${xmlLogFile}`]); if (debug) { - const def = createDeferred(); - const launchDef = createDeferred(); const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py'); - - // start the debug adapter only once we have started the debug process - // pytestlauncherargs const pytestlauncherargs = [rootDirectory, 'my_secret', pythonSettings.unitTest.debugPort.toString(), 'pytest']; - let outputChannelShown = false; - execPythonFile(pythonSettings.pythonPath, [testLauncherFile].concat(pytestlauncherargs).concat(testArgs), rootDirectory, true, (data: string) => { - if (data.startsWith('READY' + os.EOL)) { - // debug socket server has started - launchDef.resolve(); - data = data.substring(('READY' + os.EOL).length); - } - - if (!outputChannelShown) { - outputChannelShown = true; - outChannel.show(); - } - outChannel.append(data); - }, token).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }).then(() => { - if (!def.rejected && !def.resolved) { - def.resolve(); - } - }).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }); - - launchDef.promise.then(() => { - return vscode.commands.executeCommand('vscode.startDebug', { - "name": "Debug Unit Test", - "type": "python", - "request": "attach", - "localRoot": rootDirectory, - "remoteRoot": rootDirectory, - "port": pythonSettings.unitTest.debugPort, - "secret": "my_secret", - "host": "localhost" - }); - }).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }); - - return def.promise; + const args = [testLauncherFile].concat(pytestlauncherargs).concat(testArgs); + return launchDebugger(rootDirectory, args, token, outChannel); } else { return run(pythonSettings.unitTest.pyTestPath, testArgs, rootDirectory, token, outChannel); @@ -115,4 +64,4 @@ export function updateResultsFromLogFiles(tests: Tests, outputXmlFile: string): updateResults(tests); return tests; }); -} \ No newline at end of file +} diff --git a/src/client/unittests/unittest/runner.ts b/src/client/unittests/unittest/runner.ts index b451af48db23..1435dc8b3062 100644 --- a/src/client/unittests/unittest/runner.ts +++ b/src/client/unittests/unittest/runner.ts @@ -9,10 +9,7 @@ import { CancellationToken, OutputChannel } from 'vscode'; import { run } from '../common/runner'; import { Server } from './socketServer'; import { PythonSettings } from '../../common/configSettings'; -import * as vscode from 'vscode'; -import { execPythonFile } from './../../common/utils'; -import { createDeferred } from './../../common/helpers'; -import * as os from 'os'; +import { launchDebugger } from '../common/debugLauncher'; const settings = PythonSettings.getInstance(); interface TestStatusMap { @@ -96,57 +93,7 @@ export function runTest(testManager: BaseTestManager, rootDirectory: string, tes testArgs.push(`--testFile=${testFile}`); } if (debug === true) { - const def = createDeferred(); - const launchDef = createDeferred(); - let outputChannelShown = false; - - // start the debug adapter only once we have started the debug process - execPythonFile(settings.pythonPath, [testLauncherFile].concat(testArgs), rootDirectory, true, (data: string) => { - if (data.startsWith('READY' + os.EOL)) { - // debug socket server has started - launchDef.resolve(); - data = data.substring(('READY' + os.EOL).length); - } - - if (!outputChannelShown) { - outputChannelShown = true; - outChannel.show(); - } - outChannel.append(data); - }, token).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }).then(() => { - if (!def.rejected && !def.resolved) { - def.resolve(); - } - }).catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }); - - launchDef.promise - .then(() => { - return vscode.commands.executeCommand('vscode.startDebug', { - "name": "Debug Unit Test", - "type": "python", - "request": "attach", - "localRoot": rootDirectory, - "remoteRoot": rootDirectory, - "port": settings.unitTest.debugPort, - "secret": "my_secret", - "host": "localhost" - }); - }) - .catch(reason => { - if (!def.rejected && !def.resolved) { - def.reject(reason); - } - }); - - return def.promise; + return launchDebugger(rootDirectory, [testLauncherFile].concat(testArgs), token, outChannel); } else { return run(settings.pythonPath, [testLauncherFile].concat(testArgs), rootDirectory, token, outChannel); @@ -253,4 +200,4 @@ function getIdsOfTestsToRun(tests: Tests, testsToRun: TestsToRun): string[] { testIds.push(...testsToRun.testFunction.map(f => f.nameToRun)); } return testIds; -} \ No newline at end of file +}