Make query history tests work with remote / variant analysis queries

We're adding both remote query history items and variant analysis history
items to the query history.

We've introduced a little method to shuffle the query history list
before we run our tests so that we don't accidentally write tests that
depend on a fixed order.

The query history now has increased test coverage for:
- handling an item being clicked
- removing and selecting the next item in query history
- handling single / multi selection
- showing the item results

While we're here we're also:
1. Adding a factory to generate variant analysis history items
2. Providing all fields for remote query history items and ordering them
according to their type definition order. At least one field (`queryId`)
was missing from our factory, which we will need to make the tests work
with remote queries.
This commit is contained in:
Elena Tanasoiu
2022-10-31 17:56:39 +00:00
parent 6289411e08
commit 4b9db6a298
4 changed files with 131 additions and 21 deletions

View File

@@ -1,31 +1,39 @@
import { RemoteQueryHistoryItem } from '../../../remote-queries/remote-query-history-item';
import { QueryStatus } from '../../../query-status';
export function createMockRemoteQueryHistoryItem({
date = new Date('2022-01-01T00:00:00.000Z'),
failureReason = undefined,
resultCount = 16,
userSpecifiedLabel = undefined,
repositoryCount = 0,
userSpecifiedLabel = undefined,
}: {
date?: Date;
failureReason?: string;
resultCount?: number;
userSpecifiedLabel?: string;
repositoryCount?: number;
userSpecifiedLabel?: string;
}): RemoteQueryHistoryItem {
return ({
t: 'remote',
userSpecifiedLabel,
failureReason,
resultCount,
status: QueryStatus.InProgress,
completed: false,
queryId: 'queryId',
remoteQuery: {
executionStartTime: date.getTime(),
queryName: 'query-name',
queryFilePath: 'query-file.ql',
queryText: 'select 1',
language: 'javascript',
controllerRepository: {
owner: 'github',
name: 'vscode-codeql-integration-tests',
},
language: 'javascript',
executionStartTime: date.getTime(),
actionsWorkflowRunId: 1,
repositoryCount,
},
status: 'in progress',
resultCount,
userSpecifiedLabel,
} as unknown) as RemoteQueryHistoryItem;
}

View File

@@ -0,0 +1,40 @@
import { faker } from '@faker-js/faker';
import { VariantAnalysisHistoryItem } from '../../../remote-queries/variant-analysis-history-item';
import { QueryStatus } from '../../../query-status';
import { VariantAnalysisStatus } from '../../../remote-queries/shared/variant-analysis';
export function createMockVariantAnalysisHistoryItem(
historyItemStatus: QueryStatus = QueryStatus.InProgress,
variantAnalysisStatus: VariantAnalysisStatus = VariantAnalysisStatus.Succeeded,
failureReason?: string,
resultCount?: number,
userSpecifiedLabel?: string
): VariantAnalysisHistoryItem {
return ({
t: 'variant-analysis',
failureReason,
resultCount,
status: historyItemStatus,
completed: false,
variantAnalysis: {
'id': faker.datatype.number(),
'controllerRepoId': faker.datatype.number(),
'query': {
'name': 'Variant Analysis Query History Item',
'filePath': 'PLACEHOLDER/q2.ql',
'language': 'ruby',
'text': '/**\n * @name Variant Analysis Query History Item\n * @kind problem\n * @problem.severity warning\n * @id ruby/example/empty-block\n */\nimport ruby\n\nfrom Block b\nwhere b.getNumberOfStatements() = 0\nselect b, \'This is an empty block.\'\n'
},
'databases': {
'repositories': ['92384123', '1230871']
},
'createdAt': faker.date.recent().toISOString(),
'updatedAt': faker.date.recent().toISOString(),
'executionStartTime': faker.date.recent().toISOString(),
'status': variantAnalysisStatus,
'actionsWorkflowRunId': faker.datatype.number()
},
userSpecifiedLabel,
} as unknown) as VariantAnalysisHistoryItem;
}

View File

@@ -22,6 +22,11 @@ import { QueryRunner } from '../../queryRunner';
import { VariantAnalysisManager } from '../../remote-queries/variant-analysis-manager';
import { QueryHistoryInfo } from '../../query-history-info';
import { createMockLocalQuery, createMockQueryWithResults } from '../factories/local-queries/local-query-history-item';
import { createMockRemoteQueryHistoryItem } from '../factories/remote-queries/remote-query-history-item';
import { RemoteQueryHistoryItem } from '../../remote-queries/remote-query-history-item';
import { shuffleHistoryItems } from '../utils/query-history-helpers';
import { createMockVariantAnalysisHistoryItem } from '../factories/remote-queries/variant-analysis-history-item';
import { VariantAnalysisHistoryItem } from '../../remote-queries/variant-analysis-history-item';
describe('query-history', () => {
const mockExtensionLocation = path.join(tmpDir.name, 'mock-extension-location');
@@ -63,13 +68,17 @@ describe('query-history', () => {
remoteQueriesManagerStub = {
onRemoteQueryAdded: sandbox.stub(),
onRemoteQueryRemoved: sandbox.stub(),
onRemoteQueryStatusUpdate: sandbox.stub()
onRemoteQueryStatusUpdate: sandbox.stub(),
removeRemoteQuery: sandbox.stub(),
openRemoteQueryResults: sandbox.stub(),
} as any as RemoteQueriesManager;
variantAnalysisManagerStub = {
onVariantAnalysisAdded: sandbox.stub(),
onVariantAnalysisStatusUpdated: sandbox.stub(),
onVariantAnalysisRemoved: sandbox.stub()
onVariantAnalysisRemoved: sandbox.stub(),
removeVariantAnalysis: sandbox.stub(),
showView: sandbox.stub(),
} as any as VariantAnalysisManager;
});
@@ -124,6 +133,8 @@ describe('query-history', () => {
let allHistory: QueryHistoryInfo[];
let localQueryHistory: LocalQueryInfo[];
let remoteQueryHistory: RemoteQueryHistoryItem[];
let variantAnalysisHistory: VariantAnalysisHistoryItem[];
beforeEach(() => {
localQueryHistory = [
@@ -132,7 +143,19 @@ describe('query-history', () => {
createMockLocalQuery('a', createMockQueryWithResults(sandbox, false)),
createMockLocalQuery('a', createMockQueryWithResults(sandbox, true)),
];
allHistory = [...localQueryHistory];
remoteQueryHistory = [
createMockRemoteQueryHistoryItem({}),
createMockRemoteQueryHistoryItem({}),
createMockRemoteQueryHistoryItem({}),
createMockRemoteQueryHistoryItem({})
];
variantAnalysisHistory = [
createMockVariantAnalysisHistoryItem(),
createMockVariantAnalysisHistoryItem(),
createMockVariantAnalysisHistoryItem(),
createMockVariantAnalysisHistoryItem()
];
allHistory = shuffleHistoryItems([...localQueryHistory, ...remoteQueryHistory, ...variantAnalysisHistory]);
});
describe('Local Queries', () => {
@@ -264,19 +287,30 @@ describe('query-history', () => {
describe('handleItemClicked', () => {
it('should call the selectedCallback when an item is clicked', async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
const itemClicked = allHistory[0];
await queryHistoryManager.handleItemClicked(itemClicked, [itemClicked]);
await queryHistoryManager.handleItemClicked(allHistory[0], [allHistory[0]]);
if (itemClicked.t == 'local') {
expect(localQueriesResultsViewStub.showResults).to.have.been.calledOnceWith(itemClicked);
} else if (itemClicked.t == 'remote') {
expect(remoteQueriesManagerStub.openRemoteQueryResults).to.have.been.calledOnceWith(itemClicked.queryId);
} else if (itemClicked.t == 'variant-analysis') {
expect(variantAnalysisManagerStub.showView).to.have.been.calledOnceWith(itemClicked.variantAnalysis.id);
}
expect(localQueriesResultsViewStub.showResults).to.have.been.calledOnceWith(allHistory[0]);
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.eq(allHistory[0]);
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.eq(itemClicked);
});
it('should do nothing if there is a multi-selection', async () => {
queryHistoryManager = await createMockQueryHistory(allHistory);
const itemClicked = allHistory[0];
const secondItemClicked = allHistory[1];
await queryHistoryManager.handleItemClicked(allHistory[0], [allHistory[0], allHistory[1]]);
await queryHistoryManager.handleItemClicked(itemClicked, [itemClicked, secondItemClicked]);
expect(localQueriesResultsViewStub.showResults).not.to.have.been.called;
expect(remoteQueriesManagerStub.openRemoteQueryResults).not.to.have.been.called;
expect(variantAnalysisManagerStub.showView).not.to.have.been.called;
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.be.undefined;
});
@@ -286,6 +320,8 @@ describe('query-history', () => {
await queryHistoryManager.handleItemClicked(undefined!, []);
expect(localQueriesResultsViewStub.showResults).not.to.have.been.called;
expect(remoteQueriesManagerStub.openRemoteQueryResults).not.to.have.been.called;
expect(variantAnalysisManagerStub.showView).not.to.have.been.called;
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.be.undefined;
});
});
@@ -311,12 +347,23 @@ describe('query-history', () => {
if (toDelete.t == 'local') {
expect(toDelete.completedQuery!.dispose).to.have.been.calledOnce;
} else if (toDelete.t == 'remote') {
expect(remoteQueriesManagerStub.removeRemoteQuery).to.have.been.calledOnceWith((toDelete as RemoteQueryHistoryItem).queryId);
} else if (toDelete.t == 'variant-analysis') {
expect(variantAnalysisManagerStub.removeVariantAnalysis).to.have.been.calledOnceWith((toDelete as VariantAnalysisHistoryItem).variantAnalysis.id);
}
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.deep.eq(selected);
expect(queryHistoryManager.treeDataProvider.allHistory).not.to.contain(toDelete);
// the same item should be selected
expect(localQueriesResultsViewStub.showResults).to.have.been.calledOnceWith(selected);
if (selected.t == 'local') {
expect(localQueriesResultsViewStub.showResults).to.have.been.calledOnceWith(selected);
} else if (toDelete.t == 'remote') {
expect(remoteQueriesManagerStub.openRemoteQueryResults).to.have.been.calledOnceWith((selected as RemoteQueryHistoryItem).queryId);
} else if (toDelete.t == 'variant-analysis') {
expect(variantAnalysisManagerStub.showView).to.have.been.calledOnceWith((selected as VariantAnalysisHistoryItem).variantAnalysis.id);
}
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.deep.eq(selected);
expect(queryHistoryManager.treeDataProvider.allHistory).not.to.contain(toDelete);
});
it('should remove an item and select a new one', async () => {
@@ -333,12 +380,23 @@ describe('query-history', () => {
if (toDelete.t == 'local') {
expect(toDelete.completedQuery!.dispose).to.have.been.calledOnce;
} else if (toDelete.t == 'remote') {
expect(remoteQueriesManagerStub.removeRemoteQuery).to.have.been.calledOnceWith((toDelete as RemoteQueryHistoryItem).queryId);
} else if (toDelete.t == 'variant-analysis') {
expect(variantAnalysisManagerStub.removeVariantAnalysis).to.have.been.calledOnceWith((toDelete as VariantAnalysisHistoryItem).variantAnalysis.id);
}
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.eq(newSelected);
expect(queryHistoryManager.treeDataProvider.allHistory).not.to.contain(toDelete);
// the current item should have been selected
expect(localQueriesResultsViewStub.showResults).to.have.been.calledOnceWith(newSelected);
if (newSelected.t == 'local') {
expect(localQueriesResultsViewStub.showResults).to.have.been.calledOnceWith(newSelected);
} else if (toDelete.t == 'remote') {
expect(remoteQueriesManagerStub.openRemoteQueryResults).to.have.been.calledOnceWith((newSelected as RemoteQueryHistoryItem).queryId);
} else if (toDelete.t == 'variant-analysis') {
expect(variantAnalysisManagerStub.showView).to.have.been.calledOnceWith((newSelected as VariantAnalysisHistoryItem).variantAnalysis.id);
}
expect(queryHistoryManager.treeDataProvider.getCurrent()).to.eq(newSelected);
expect(queryHistoryManager.treeDataProvider.allHistory).not.to.contain(toDelete);
});
describe('HistoryTreeDataProvider', () => {
@@ -355,7 +413,6 @@ describe('query-history', () => {
historyTreeDataProvider.dispose();
});
it('should get a tree item with raw results', async () => {
const mockQuery = createMockLocalQuery('a', createMockQueryWithResults(sandbox, true, /* raw results */ false));
const treeItem = await historyTreeDataProvider.getTreeItem(mockQuery);

View File

@@ -0,0 +1,5 @@
import { QueryHistoryInfo } from '../../query-history-info';
export function shuffleHistoryItems(history: QueryHistoryInfo[]) {
return history.sort(() => Math.random() - 0.5);
}