Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

testing: add proposed testInvalidateResults API #183370

Merged
merged 2 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -2500,6 +2500,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;
}
}