Skip to content

Commit

Permalink
testing: add proposed testInvalidateResults API (#183370)
Browse files Browse the repository at this point in the history
* testing: add proposed testInvalidateResults API

For #134970

* fix tests
  • Loading branch information
connor4312 authored May 25, 2023
1 parent 11cabc6 commit 21ec251
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 6 deletions.
1 change: 1 addition & 0 deletions extensions/vscode-api-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"tokenInformation",
"treeItemCheckbox",
"treeViewReveal",
"testInvalidateResults",
"workspaceTrust",
"telemetry",
"windowActivity",
Expand Down
2 changes: 2 additions & 0 deletions src/vs/base/test/browser/dom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ suite('dom', () => {
assert(!element.classList.contains('bar'));
assert(!element.classList.contains('foo'));
assert(!element.classList.contains(''));


});

test('removeClass', () => {
Expand Down
12 changes: 12 additions & 0 deletions src/vs/workbench/api/browser/mainThreadTesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
}));
}

/**
* @inheritdoc
*/
$markTestRetired(testId: string): void {
for (const result of this.resultService.results) {
// all non-live results are already entirely outdated
if (result instanceof LiveTestResult) {
result.markRetired(testId);
}
}
}

/**
* @inheritdoc
*/
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2501,6 +2501,8 @@ export interface MainThreadTestingShape {
$startedExtensionTestRun(req: ExtensionRunTestsRequest): void;
/** Signals that an extension-provided test run finished. */
$finishedExtensionTestRun(runId: string): void;
/** Marks a test (or controller) as retired in all results. */
$markTestRetired(testId: string): void;
}

// --- proxy identifiers
Expand Down
6 changes: 6 additions & 0 deletions src/vs/workbench/api/common/extHostTesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { TestCommandId } from 'vs/workbench/contrib/testing/common/constants';
import { TestId, TestIdPathParts, TestPosition } from 'vs/workbench/contrib/testing/common/testId';
import { InvalidTestItemError } from 'vs/workbench/contrib/testing/common/testItemCollection';
import { AbstractIncrementalTestCollection, CoverageDetails, ICallProfileRunHandler, IFileCoverage, ISerializedTestResults, IStartControllerTests, IStartControllerTestsResult, ITestItem, ITestItemContext, IncrementalChangeCollector, IncrementalTestCollectionItem, InternalTestItem, TestResultState, TestRunProfileBitset, TestsDiff, TestsDiffOp, isStartControllerTests } from 'vs/workbench/contrib/testing/common/testTypes';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
import type * as vscode from 'vscode';

interface ControllerInfo {
Expand Down Expand Up @@ -137,6 +138,11 @@ export class ExtHostTesting implements ExtHostTestingShape {
createTestRun: (request, name, persist = true) => {
return this.runTracker.createTestRun(controllerId, collection, request, name, persist);
},
invalidateTestResults: item => {
checkProposedApiEnabled(extension, 'testInvalidateResults');
const id = item ? TestId.fromExtHostTestItem(item, controllerId).toString() : controllerId;
return this.proxy.$markTestRetired(id);
},
set resolveHandler(fn) {
collection.resolveHandler = fn;
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ export class HierarchicalByLocationProjection extends Disposable implements ITes
// when test states change, reflect in the tree
this._register(results.onTestChanged(ev => {
let result = ev.item;
if (result.ownComputedState === TestResultState.Unset) {
// if the state is unset, or the latest run is not making the change,
// double check that it's valid. Retire calls might cause previous
// emit a state change for a test run that's already long completed.
if (result.ownComputedState === TestResultState.Unset || ev.result !== results.results[0]) {
const fallback = results.getStateById(result.item.extId);
if (fallback) {
result = fallback[1];
Expand Down
12 changes: 12 additions & 0 deletions src/vs/workbench/contrib/testing/common/testResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,18 @@ export class LiveTestResult implements ITestResult {
this.completeEmitter.fire();
}

/**
* Marks the test and all of its children in the run as retired.
*/
public markRetired(testId: string) {
for (const [id, test] of this.testById) {
if (!test.retired && id === testId || TestId.isChild(testId, id)) {
test.retired = true;
this.changeEmitter.fire({ reason: TestResultItemChangeReason.ComputedStateChange, item: test, result: this });
}
}
}

/**
* @inheritdoc
*/
Expand Down
8 changes: 4 additions & 4 deletions src/vs/workbench/contrib/testing/common/testTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,28 +469,28 @@ export interface TestResultItem extends InternalTestItem {
}

export namespace TestResultItem {
/** Serialized version of the TestResultItem */
/**
* Serialized version of the TestResultItem. Note that 'retired' is not
* included since all hydrated items are automatically retired.
*/
export interface Serialized extends InternalTestItem.Serialized {
tasks: ITestTaskState.Serialized[];
ownComputedState: TestResultState;
computedState: TestResultState;
retired?: boolean;
}

export const serializeWithoutMessages = (original: TestResultItem): Serialized => ({
...InternalTestItem.serialize(original),
ownComputedState: original.ownComputedState,
computedState: original.computedState,
tasks: original.tasks.map(ITestTaskState.serializeWithoutMessages),
retired: original.retired,
});

export const serialize = (original: TestResultItem): Serialized => ({
...InternalTestItem.serialize(original),
ownComputedState: original.ownComputedState,
computedState: original.computedState,
tasks: original.tasks.map(ITestTaskState.serialize),
retired: original.retired,
});

export const deserialize = (serialized: Serialized): TestResultItem => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
setup(() => {
onTestChanged = new Emitter();
resultsService = {
results: [],
onResultsChanged: () => undefined,
onTestChanged: onTestChanged.event,
getStateById: () => ({ state: { state: 0 }, computedState: 0 }),
Expand Down Expand Up @@ -102,7 +103,6 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {

test('applies state changes', async () => {
harness.flush();
resultsService.getStateById = () => [undefined, resultInState(TestResultState.Failed)];

const resultInState = (state: TestResultState): TestResultItem => ({
item: {
Expand All @@ -124,6 +124,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
});

// Applies the change:
resultsService.getStateById = () => [undefined, resultInState(TestResultState.Queued)];
onTestChanged.fire({
reason: TestResultItemChangeReason.OwnStateChange,
result: null as any,
Expand All @@ -139,6 +140,7 @@ suite('Workbench - Testing Explorer Hierarchal by Location Projection', () => {
]);

// Falls back if moved into unset state:
resultsService.getStateById = () => [undefined, resultInState(TestResultState.Failed)];
onTestChanged.fire({
reason: TestResultItemChangeReason.OwnStateChange,
result: null as any,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const allApiProposals = Object.freeze({
terminalDimensions: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalDimensions.d.ts',
terminalQuickFixProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalQuickFixProvider.d.ts',
testCoverage: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testCoverage.d.ts',
testInvalidateResults: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testInvalidateResults.d.ts',
testObserver: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.testObserver.d.ts',
textSearchProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.textSearchProvider.d.ts',
timeline: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.timeline.d.ts',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ suite('DomActivityTracker', () => {
clock.restore();
});


test('marks inactive on no input', () => {
assert.equal(uas.isActive, true);
clock.tick(maxTimeToBecomeIdle);
Expand Down
30 changes: 30 additions & 0 deletions src/vscode-dts/vscode.proposed.testInvalidateResults.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// https://github.com/microsoft/vscode/issues/134970

declare module 'vscode' {

export interface TestController {

/**
* Marks an item's results as being outdated. This is commonly called when
* code or configuration changes and previous results should no longer
* be considered relevant. The same logic used to mark results as outdated
* may be used to drive {@link TestRunRequest.continuous continuous test runs}.
*
* If an item is passed to this method, test results for the item and all of
* its children will be marked as outdated. If no item is passed, then all
* test owned by the TestController will be marked as outdated.
*
* Any test runs started before the moment this method is called, including
* runs which may still be ongoing, will be marked as outdated and deprioritized
* in the editor's UI.
*
* @param item Item to mark as outdated. If undefined, all the controller's items are marked outdated.
*/
invalidateTestResults(item?: TestItem): void;
}
}

0 comments on commit 21ec251

Please sign in to comment.