Skip to content

Commit 2ca15f3

Browse files
committed
Make it possible to cancel a variant analysis from Query History
This also adds tests for cancelling a local query and a remote query. NB: We only cancel queries that are in progress, so the tests check the behaviour both for in progress and not in progress items.
1 parent 20b127c commit 2ca15f3

File tree

2 files changed

+178
-1
lines changed

2 files changed

+178
-1
lines changed

extensions/ql-vscode/src/query-history.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import * as fs from 'fs-extra';
4040
import { CliVersionConstraint } from './cli';
4141
import { HistoryItemLabelProvider } from './history-item-label-provider';
4242
import { Credentials } from './authentication';
43-
import { cancelRemoteQuery } from './remote-queries/gh-api/gh-actions-api-client';
43+
import { cancelRemoteQuery, cancelVariantAnalysis } from './remote-queries/gh-api/gh-actions-api-client';
4444
import { RemoteQueriesManager } from './remote-queries/remote-queries-manager';
4545
import { RemoteQueryHistoryItem } from './remote-queries/remote-query-history-item';
4646
import { ResultsView } from './interface';
@@ -1109,6 +1109,7 @@ export class QueryHistoryManager extends DisposableObject {
11091109
const { finalSingleItem, finalMultiSelect } = this.determineSelection(singleItem, multiSelect);
11101110

11111111
const selected = finalMultiSelect || [finalSingleItem];
1112+
11121113
const results = selected.map(async item => {
11131114
if (item.status === QueryStatus.InProgress) {
11141115
if (item.t === 'local') {
@@ -1117,6 +1118,10 @@ export class QueryHistoryManager extends DisposableObject {
11171118
void showAndLogInformationMessage('Cancelling variant analysis. This may take a while.');
11181119
const credentials = await this.getCredentials();
11191120
await cancelRemoteQuery(credentials, item.remoteQuery);
1121+
} else if (item.t === 'variant-analysis') {
1122+
void showAndLogInformationMessage('Cancelling variant analysis. This may take a while.');
1123+
const credentials = await this.getCredentials();
1124+
await cancelVariantAnalysis(credentials, item.variantAnalysis);
11201125
}
11211126
}
11221127
});

extensions/ql-vscode/src/vscode-tests/no-workspace/query-history.test.ts

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import { createMockVariantAnalysisHistoryItem } from '../factories/remote-querie
3232
import { VariantAnalysisHistoryItem } from '../../remote-queries/variant-analysis-history-item';
3333
import { QueryStatus } from '../../query-status';
3434
import { VariantAnalysisStatus } from '../../remote-queries/shared/variant-analysis';
35+
import * as ghActionsApiClient from '../../remote-queries/gh-api/gh-actions-api-client';
36+
import { Credentials } from '../../authentication';
3537

3638
describe('query-history', () => {
3739
const mockExtensionLocation = path.join(tmpDir.name, 'mock-extension-location');
@@ -92,10 +94,18 @@ describe('query-history', () => {
9294
} as any as VariantAnalysisManager;
9395

9496
localQueryHistory = [
97+
// completed
9598
createMockLocalQueryInfo({ dbName: 'a', queryWithResults: createMockQueryWithResults({ sandbox, didRunSuccessfully: true }) }),
99+
// completed
96100
createMockLocalQueryInfo({ dbName: 'b', queryWithResults: createMockQueryWithResults({ sandbox, didRunSuccessfully: true }) }),
101+
// failed
97102
createMockLocalQueryInfo({ dbName: 'a', queryWithResults: createMockQueryWithResults({ sandbox, didRunSuccessfully: false }) }),
103+
// completed
98104
createMockLocalQueryInfo({ dbName: 'a', queryWithResults: createMockQueryWithResults({ sandbox, didRunSuccessfully: true }) }),
105+
// in progress
106+
createMockLocalQueryInfo({ resultCount: 0 }),
107+
// in progress
108+
createMockLocalQueryInfo({ resultCount: 0 })
99109
];
100110
remoteQueryHistory = [
101111
createMockRemoteQueryHistoryItem({ status: QueryStatus.Completed }),
@@ -325,6 +335,168 @@ describe('query-history', () => {
325335
});
326336
});
327337

338+
describe('handleCancel', () => {
339+
let mockCredentials: Credentials;
340+
let mockCancelRemoteQuery: sinon.SinonStub;
341+
let mockCancelVariantAnalysis: sinon.SinonStub;
342+
let getOctokitStub: sinon.SinonStub;
343+
344+
beforeEach(async () => {
345+
mockCredentials = {
346+
getOctokit: () => Promise.resolve({
347+
request: getOctokitStub
348+
})
349+
} as unknown as Credentials;
350+
sandbox.stub(Credentials, 'initialize').resolves(mockCredentials);
351+
mockCancelRemoteQuery = sandbox.stub(ghActionsApiClient, 'cancelRemoteQuery');
352+
mockCancelVariantAnalysis = sandbox.stub(ghActionsApiClient, 'cancelVariantAnalysis');
353+
});
354+
355+
describe('if the item is in progress', async () => {
356+
it('should cancel a single local query', async () => {
357+
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
358+
359+
// cancelling the selected item
360+
const inProgress1 = localQueryHistory[4];
361+
const cancelSpy = sandbox.spy(inProgress1, 'cancel');
362+
363+
await queryHistoryManager.handleCancel(inProgress1, [inProgress1]);
364+
expect(cancelSpy).to.have.been.calledOnce;
365+
});
366+
367+
it('should cancel multiple local queries', async () => {
368+
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
369+
370+
// cancelling the selected item
371+
const inProgress1 = localQueryHistory[4];
372+
const inProgress2 = localQueryHistory[5];
373+
374+
const cancelSpy1 = sandbox.spy(inProgress1, 'cancel');
375+
const cancelSpy2 = sandbox.spy(inProgress2, 'cancel');
376+
377+
await queryHistoryManager.handleCancel(inProgress1, [inProgress1, inProgress2]);
378+
expect(cancelSpy1).to.have.been.called;
379+
expect(cancelSpy2).to.have.been.called;
380+
});
381+
382+
it('should cancel a single remote query', async () => {
383+
queryHistoryManager = await createMockQueryHistory(allHistory);
384+
385+
// cancelling the selected item
386+
const inProgress1 = remoteQueryHistory[2];
387+
388+
await queryHistoryManager.handleCancel(inProgress1, [inProgress1]);
389+
expect(mockCancelRemoteQuery).to.have.been.calledWith(mockCredentials, inProgress1.remoteQuery);
390+
});
391+
392+
it('should cancel multiple remote queries', async () => {
393+
queryHistoryManager = await createMockQueryHistory(allHistory);
394+
395+
// cancelling the selected item
396+
const inProgress1 = remoteQueryHistory[2];
397+
const inProgress2 = remoteQueryHistory[3];
398+
399+
await queryHistoryManager.handleCancel(inProgress1, [inProgress1, inProgress2]);
400+
expect(mockCancelRemoteQuery).to.have.been.calledWith(mockCredentials, inProgress1.remoteQuery);
401+
expect(mockCancelRemoteQuery).to.have.been.calledWith(mockCredentials, inProgress2.remoteQuery);
402+
});
403+
404+
it('should cancel a single variant analysis', async () => {
405+
queryHistoryManager = await createMockQueryHistory(allHistory);
406+
407+
// cancelling the selected item
408+
const inProgress1 = variantAnalysisHistory[1];
409+
410+
await queryHistoryManager.handleCancel(inProgress1, [inProgress1]);
411+
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, inProgress1.variantAnalysis);
412+
});
413+
414+
it('should cancel multiple variant analyses', async () => {
415+
queryHistoryManager = await createMockQueryHistory(allHistory);
416+
417+
// cancelling the selected item
418+
const inProgress1 = variantAnalysisHistory[1];
419+
const inProgress2 = variantAnalysisHistory[3];
420+
421+
await queryHistoryManager.handleCancel(inProgress1, [inProgress1, inProgress2]);
422+
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, inProgress1.variantAnalysis);
423+
expect(mockCancelVariantAnalysis).to.have.been.calledWith(mockCredentials, inProgress2.variantAnalysis);
424+
});
425+
});
426+
427+
describe('if the item is not in progress', async () => {
428+
it('should not cancel a single local query', async () => {
429+
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
430+
431+
// cancelling the selected item
432+
const completed = localQueryHistory[0];
433+
const cancelSpy = sandbox.spy(completed, 'cancel');
434+
435+
await queryHistoryManager.handleCancel(completed, [completed]);
436+
expect(cancelSpy).to.not.have.been.calledOnce;
437+
});
438+
439+
it('should not cancel multiple local queries', async () => {
440+
queryHistoryManager = await createMockQueryHistory(localQueryHistory);
441+
442+
// cancelling the selected item
443+
const completed = localQueryHistory[0];
444+
const failed = localQueryHistory[2];
445+
446+
const cancelSpy = sandbox.spy(completed, 'cancel');
447+
const cancelSpy2 = sandbox.spy(failed, 'cancel');
448+
449+
await queryHistoryManager.handleCancel(completed, [completed, failed]);
450+
expect(cancelSpy).to.not.have.been.calledOnce;
451+
expect(cancelSpy2).to.not.have.been.calledOnce;
452+
});
453+
454+
it('should not cancel a single remote query', async () => {
455+
queryHistoryManager = await createMockQueryHistory(allHistory);
456+
457+
// cancelling the selected item
458+
const completed = remoteQueryHistory[0];
459+
460+
await queryHistoryManager.handleCancel(completed, [completed]);
461+
expect(mockCancelRemoteQuery).to.not.have.been.calledWith(mockCredentials, completed.remoteQuery);
462+
});
463+
464+
it('should not cancel multiple remote queries', async () => {
465+
queryHistoryManager = await createMockQueryHistory(allHistory);
466+
467+
// cancelling the selected item
468+
const completed = remoteQueryHistory[0];
469+
const failed = remoteQueryHistory[1];
470+
471+
await queryHistoryManager.handleCancel(completed, [completed, failed]);
472+
expect(mockCancelRemoteQuery).to.not.have.been.calledWith(mockCredentials, completed.remoteQuery);
473+
expect(mockCancelRemoteQuery).to.not.have.been.calledWith(mockCredentials, failed.remoteQuery);
474+
});
475+
476+
it('should not cancel a single variant analysis', async () => {
477+
queryHistoryManager = await createMockQueryHistory(allHistory);
478+
479+
// cancelling the selected item
480+
const completedVariantAnalysis = variantAnalysisHistory[0];
481+
482+
await queryHistoryManager.handleCancel(completedVariantAnalysis, [completedVariantAnalysis]);
483+
expect(mockCancelVariantAnalysis).to.not.have.been.calledWith(mockCredentials, completedVariantAnalysis.variantAnalysis);
484+
});
485+
486+
it('should not cancel multiple variant analyses', async () => {
487+
queryHistoryManager = await createMockQueryHistory(allHistory);
488+
489+
// cancelling the selected item
490+
const completedVariantAnalysis = variantAnalysisHistory[0];
491+
const failedVariantAnalysis = variantAnalysisHistory[2];
492+
493+
await queryHistoryManager.handleCancel(completedVariantAnalysis, [completedVariantAnalysis, failedVariantAnalysis]);
494+
expect(mockCancelVariantAnalysis).to.not.have.been.calledWith(mockCredentials, completedVariantAnalysis.variantAnalysis);
495+
expect(mockCancelVariantAnalysis).to.not.have.been.calledWith(mockCredentials, failedVariantAnalysis.variantAnalysis);
496+
});
497+
});
498+
});
499+
328500
describe('determineSelection', () => {
329501
const singleItem = 'a';
330502
const multipleItems = ['b', 'c', 'd'];

0 commit comments

Comments
 (0)