mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-23 19:59:37 +00:00
Adding better test case for not caching cancelled responses
This commit is contained in:
@@ -15,11 +15,10 @@ suite('CachedResponse', () => {
|
||||
const doc = await vscode.workspace.openTextDocument({ language: 'javascript', content: '' });
|
||||
const response = new CachedResponse();
|
||||
|
||||
let seq = 0;
|
||||
const makeRequest = async () => createResponse(`test-${seq++}`);
|
||||
const responder = createSequentialResponder('test');
|
||||
|
||||
assertResult(await response.execute(doc, makeRequest), 'test-0');
|
||||
assertResult(await response.execute(doc, makeRequest), 'test-0');
|
||||
assertResult(await response.execute(doc, responder), 'test-0');
|
||||
assertResult(await response.execute(doc, responder), 'test-0');
|
||||
});
|
||||
|
||||
test('should invalidate cache for new document', async () => {
|
||||
@@ -27,29 +26,32 @@ suite('CachedResponse', () => {
|
||||
const doc2 = await vscode.workspace.openTextDocument({ language: 'javascript', content: '' });
|
||||
const response = new CachedResponse();
|
||||
|
||||
let seq = 0;
|
||||
const makeRequest = async () => createResponse(`test-${seq++}`);
|
||||
const responder = createSequentialResponder('test');
|
||||
|
||||
assertResult(await response.execute(doc1, makeRequest), 'test-0');
|
||||
assertResult(await response.execute(doc1, makeRequest), 'test-0');
|
||||
assertResult(await response.execute(doc2, makeRequest), 'test-1');
|
||||
assertResult(await response.execute(doc2, makeRequest), 'test-1');
|
||||
assertResult(await response.execute(doc1, makeRequest), 'test-2');
|
||||
assertResult(await response.execute(doc1, makeRequest), 'test-2');
|
||||
assertResult(await response.execute(doc1, responder), 'test-0');
|
||||
assertResult(await response.execute(doc1, responder), 'test-0');
|
||||
assertResult(await response.execute(doc2, responder), 'test-1');
|
||||
assertResult(await response.execute(doc2, responder), 'test-1');
|
||||
assertResult(await response.execute(doc1, responder), 'test-2');
|
||||
assertResult(await response.execute(doc1, responder), 'test-2');
|
||||
});
|
||||
|
||||
test('should not cache canceled response', async () => {
|
||||
test('should not cache cancelled responses', async () => {
|
||||
const doc = await vscode.workspace.openTextDocument({ language: 'javascript', content: '' });
|
||||
const response = new CachedResponse();
|
||||
|
||||
let seq = 0;
|
||||
const makeRequest = async () => createResponse(`test-${seq++}`);
|
||||
const responder = createSequentialResponder('test');
|
||||
|
||||
const result1 = await response.execute(doc, async () => new CancelledResponse('cancleed'));
|
||||
assert.strictEqual(result1.type, 'cancelled');
|
||||
const cancelledResponder = createEventualResponder<CancelledResponse>();
|
||||
const result1 = response.execute(doc, () => cancelledResponder.promise);
|
||||
const result2 = response.execute(doc, responder);
|
||||
const result3 = response.execute(doc, responder);
|
||||
|
||||
assertResult(await response.execute(doc, makeRequest), 'test-0');
|
||||
assertResult(await response.execute(doc, makeRequest), 'test-0');
|
||||
cancelledResponder.resolve(new CancelledResponse('cancelled'));
|
||||
|
||||
assert.strictEqual((await result1).type, 'cancelled');
|
||||
assertResult(await result2, 'test-0');
|
||||
assertResult(await result3, 'test-0');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,3 +74,13 @@ function createResponse(command: string): Proto.Response {
|
||||
};
|
||||
}
|
||||
|
||||
function createSequentialResponder(prefix: string) {
|
||||
let count = 0;
|
||||
return async () => createResponse(`${prefix}-${count++}`);
|
||||
}
|
||||
|
||||
function createEventualResponder<T>(): {promise: Promise<T>, resolve: (x: T) => void } {
|
||||
let resolve: (value: T) => void;
|
||||
const promise = new Promise<T>(r => { resolve = r; });
|
||||
return { promise, resolve: resolve! };
|
||||
}
|
||||
|
||||
@@ -7,41 +7,42 @@ import * as vscode from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { ServerResponse } from '../typescriptService';
|
||||
|
||||
type Resolve<T extends Proto.Response> = () => Promise<ServerResponse<T>>;
|
||||
|
||||
/**
|
||||
* Caches a class of TS Server request based on document.
|
||||
*/
|
||||
export class CachedResponse<T extends Proto.Response> {
|
||||
private response?: Promise<ServerResponse<T>>;
|
||||
private version: number = -1;
|
||||
private document: string = '';
|
||||
|
||||
/**
|
||||
* Execute a request. May return cached value or resolve the new value
|
||||
*
|
||||
* Caller must ensure that all input `resolve` functions return equivilent results (keyed only off of document).
|
||||
*/
|
||||
public execute(
|
||||
document: vscode.TextDocument,
|
||||
f: () => Promise<ServerResponse<T>>
|
||||
resolve: Resolve<T>
|
||||
): Promise<ServerResponse<T>> {
|
||||
if (this.response && this.matches(document)) {
|
||||
return this.response.then(result => result.type === 'cancelled' ? f() : result);
|
||||
// Chain so that on cancellation we fall back to the next resolve
|
||||
return this.response = this.response.then(result => result.type === 'cancelled' ? resolve() : result);
|
||||
}
|
||||
return this.update(document, f());
|
||||
return this.reset(document, resolve);
|
||||
}
|
||||
|
||||
private matches(document: vscode.TextDocument): boolean {
|
||||
return this.version === document.version && this.document === document.uri.toString();
|
||||
}
|
||||
|
||||
private async update(
|
||||
private async reset(
|
||||
document: vscode.TextDocument,
|
||||
response: Promise<ServerResponse<T>>
|
||||
resolve: Resolve<T>
|
||||
): Promise<ServerResponse<T>> {
|
||||
this.response = response;
|
||||
this.version = document.version;
|
||||
this.document = document.uri.toString();
|
||||
|
||||
const result = await response;
|
||||
if (this.matches(document)) {
|
||||
if (result.type === 'cancelled') {
|
||||
// invalidate
|
||||
this.version = -1;
|
||||
this.document = '';
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return this.response = resolve();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user