Skip to content

Commit 4c3e243

Browse files
authored
Fix issue with in complete unittest runs. (#17313)
1 parent d976a19 commit 4c3e243

File tree

3 files changed

+44
-25
lines changed

3 files changed

+44
-25
lines changed

news/2 Fixes/17282.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix issue with incomplete `unittest` runs.

pythonFiles/visualstudio_py_testlauncher.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,11 @@ def main():
340340
testId = m.id()
341341
if testId.startswith(opts.tests[0]):
342342
suite = cls
343-
if testId == opts.tests[0]:
344-
tests = unittest.TestSuite([m])
345-
break
343+
if testId in opts.tests:
344+
if tests is None:
345+
tests = unittest.TestSuite([m])
346+
else:
347+
tests.addTest(m)
346348
except Exception as err:
347349
errorMessage = traceback.format_exc()
348350
if tests is None:

src/client/testing/testController/unittest/runner.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { Location, TestItem, TestMessage, TestRun, TestRunProfileKind } from 'vs
66
import { traceError, traceInfo } from '../../../common/logger';
77
import * as internalScripts from '../../../common/process/internal/scripts';
88
import { IOutputChannel } from '../../../common/types';
9-
import { createDeferred, Deferred } from '../../../common/utils/async';
109
import { noop } from '../../../common/utils/misc';
1110
import { UNITTEST_PROVIDER } from '../../common/constants';
1211
import { ITestRunner, ITestDebugLauncher, IUnitTestSocketServer, LaunchOptions, Options } from '../../common/types';
@@ -57,7 +56,23 @@ export class UnittestRunner implements ITestsRunner {
5756
): Promise<void> {
5857
runInstance.appendOutput(`Running tests (unittest): ${testNodes.map((t) => t.id).join(' ; ')}\r\n`);
5958
const testCaseNodes: TestItem[] = [];
60-
testNodes.forEach((t) => testCaseNodes.push(...getTestCaseNodes(t)));
59+
const fileToTestCases: Map<string, TestItem[]> = new Map();
60+
61+
testNodes.forEach((t) => {
62+
const nodes = getTestCaseNodes(t);
63+
nodes.forEach((n) => {
64+
if (n.uri) {
65+
const fsRunIds = fileToTestCases.get(n.uri.fsPath);
66+
if (fsRunIds) {
67+
fsRunIds.push(n);
68+
} else {
69+
fileToTestCases.set(n.uri.fsPath, [n]);
70+
}
71+
}
72+
});
73+
testCaseNodes.push(...nodes);
74+
});
75+
6176
const tested: string[] = [];
6277

6378
const counts = {
@@ -70,18 +85,15 @@ export class UnittestRunner implements ITestsRunner {
7085

7186
let failFast = false;
7287
let stopTesting = false;
73-
let testCasePromise: Deferred<void>;
7488
this.server.on('error', (message: string, ...data: string[]) => {
7589
traceError(`${message} ${data.join(' ')}`);
76-
testCasePromise.reject();
7790
});
7891
this.server.on('log', (message: string, ...data: string[]) => {
7992
traceInfo(`${message} ${data.join(' ')}`);
8093
});
8194
this.server.on('connect', noop);
8295
this.server.on('start', noop);
8396
this.server.on('result', (data: ITestData) => {
84-
testCasePromise.resolve();
8597
const testCase = testCaseNodes.find((node) => idToRawData.get(node.id)?.runId === data.test);
8698
const rawTestCase = idToRawData.get(testCase?.id ?? '');
8799
if (testCase && rawTestCase) {
@@ -147,18 +159,15 @@ export class UnittestRunner implements ITestsRunner {
147159
});
148160

149161
const port = await this.server.start();
150-
const runTestInternal = async (testFile = '', testId = ''): Promise<void> => {
162+
const runTestInternal = async (testFilePath: string, testRunIds: string[]): Promise<void> => {
151163
let testArgs = getTestRunArgs(options.args);
152164
failFast = testArgs.indexOf('--uf') >= 0;
153165
testArgs = testArgs.filter((arg) => arg !== '--uf');
154166

155167
testArgs.push(`--result-port=${port}`);
156-
if (testId.length > 0) {
157-
testArgs.push(`-t${testId}`);
158-
}
159-
if (testFile.length > 0) {
160-
testArgs.push(`--testFile=${testFile}`);
161-
}
168+
testRunIds.forEach((i) => testArgs.push(`-t${i}`));
169+
testArgs.push(`--testFile=${testFilePath}`);
170+
162171
if (options.debug === true) {
163172
testArgs.push('--debug');
164173
const launchOptions: LaunchOptions = {
@@ -179,23 +188,30 @@ export class UnittestRunner implements ITestsRunner {
179188
token: options.token,
180189
workspaceFolder: options.workspaceFolder,
181190
};
182-
testCasePromise = createDeferred();
183191
await this.runner.run(UNITTEST_PROVIDER, runOptions);
184-
return testCasePromise.promise;
192+
return Promise.resolve();
185193
};
186194

187195
try {
188-
for (const testCaseNode of testCaseNodes) {
196+
for (const testFile of fileToTestCases.keys()) {
189197
if (stopTesting || options.token.isCancellationRequested) {
190198
break;
191199
}
192-
runInstance.appendOutput(`Running tests: ${testCaseNode.id}\r\n`);
193-
const rawTestCaseNode = idToRawData.get(testCaseNode.id);
194-
if (rawTestCaseNode) {
195-
// VS Code API requires that we set the run state on the leaf nodes. The state of the
196-
// parent nodes are computed based on the state of child nodes.
197-
runInstance.started(testCaseNode);
198-
await runTestInternal(testCaseNode.uri?.fsPath, rawTestCaseNode.runId);
200+
201+
const nodes = fileToTestCases.get(testFile);
202+
if (nodes) {
203+
runInstance.appendOutput(`Running tests: ${nodes.join('\r\n')}\r\n`);
204+
const runIds: string[] = [];
205+
nodes.forEach((n) => {
206+
const rawNode = idToRawData.get(n.id);
207+
if (rawNode) {
208+
// VS Code API requires that we set the run state on the leaf nodes. The state of the
209+
// parent nodes are computed based on the state of child nodes.
210+
runInstance.started(n);
211+
runIds.push(rawNode.runId);
212+
}
213+
});
214+
await runTestInternal(testFile, runIds);
199215
}
200216
}
201217
} catch (ex) {

0 commit comments

Comments
 (0)