Merge pull request #1984 from github/elena/move-tests

Move tests for serialization/deserialization in their own file
This commit is contained in:
Elena Tanasoiu
2023-01-18 17:29:27 +00:00
committed by GitHub
2 changed files with 206 additions and 115 deletions

View File

@@ -21,10 +21,6 @@ import {
import { CodeQLCliServer, SourceInfo } from "../../../src/cli";
import { CancellationTokenSource, Uri } from "vscode";
import { tmpDir } from "../../../src/helpers";
import {
deserializeQueryHistory,
serializeQueryHistory,
} from "../../../src/query-serialization";
import {
formatLegacyMessage,
QueryInProgress,
@@ -438,117 +434,6 @@ describe("query-results", () => {
);
});
describe("serialize and deserialize", () => {
let infoSuccessRaw: LocalQueryInfo;
let infoSuccessInterpreted: LocalQueryInfo;
let infoEarlyFailure: LocalQueryInfo;
let infoLateFailure: LocalQueryInfo;
let infoInprogress: LocalQueryInfo;
let allHistory: LocalQueryInfo[];
beforeEach(() => {
infoSuccessRaw = createMockFullQueryInfo(
"a",
createMockQueryWithResults(
`${queryPath}-a`,
false,
false,
"/a/b/c/a",
false,
),
);
infoSuccessInterpreted = createMockFullQueryInfo(
"b",
createMockQueryWithResults(
`${queryPath}-b`,
true,
true,
"/a/b/c/b",
false,
),
);
infoEarlyFailure = createMockFullQueryInfo("c", undefined, true);
infoLateFailure = createMockFullQueryInfo(
"d",
createMockQueryWithResults(
`${queryPath}-c`,
false,
false,
"/a/b/c/d",
false,
),
);
infoInprogress = createMockFullQueryInfo("e");
allHistory = [
infoSuccessRaw,
infoSuccessInterpreted,
infoEarlyFailure,
infoLateFailure,
infoInprogress,
];
});
it("should serialize and deserialize query history", async () => {
// the expected results only contains the history with completed queries
const expectedHistory = [
infoSuccessRaw,
infoSuccessInterpreted,
infoLateFailure,
];
const allHistoryPath = join(tmpDir.name, "workspace-query-history.json");
// serialize and deserialize
await serializeQueryHistory(allHistory, allHistoryPath);
const allHistoryActual = await deserializeQueryHistory(allHistoryPath);
// the dispose methods will be different. Ignore them.
allHistoryActual.forEach((info) => {
if (info.t === "local" && info.completedQuery) {
const completedQuery = info.completedQuery;
(completedQuery as any).dispose = undefined;
// these fields should be missing on the deserialized value
// but they are undefined on the original value
if (!("logFileLocation" in completedQuery)) {
(completedQuery as any).logFileLocation = undefined;
}
const query = completedQuery.query;
if (!("quickEvalPosition" in query)) {
(query as any).quickEvalPosition = undefined;
}
}
});
expectedHistory.forEach((info) => {
if (info.completedQuery) {
(info.completedQuery as any).dispose = undefined;
}
});
// make the diffs somewhat sane by comparing each element directly
for (let i = 0; i < allHistoryActual.length; i++) {
expect(allHistoryActual[i]).toEqual(expectedHistory[i]);
}
expect(allHistoryActual.length).toEqual(expectedHistory.length);
});
it("should handle an invalid query history version", async () => {
const badPath = join(tmpDir.name, "bad-query-history.json");
writeFileSync(
badPath,
JSON.stringify({
version: 3,
queries: allHistory,
}),
"utf8",
);
const allHistoryActual = await deserializeQueryHistory(badPath);
// version number is invalid. Should return an empty array.
expect(allHistoryActual).toEqual([]);
});
});
function safeDel(file: string) {
try {
unlinkSync(file);

View File

@@ -0,0 +1,206 @@
import {
deserializeQueryHistory,
serializeQueryHistory,
} from "../../../src/query-serialization";
import { join } from "path";
import { writeFileSync, mkdirpSync } from "fs-extra";
import { LocalQueryInfo, InitialQueryInfo } from "../../../src/query-results";
import { QueryWithResults } from "../../../src/run-queries-shared";
import { DatabaseInfo } from "../../../src/pure/interface-types";
import { CancellationTokenSource, Uri } from "vscode";
import { tmpDir } from "../../../src/helpers";
import { QueryResultType } from "../../../src/pure/legacy-messages";
import { QueryInProgress } from "../../../src/legacy-query-server/run-queries";
describe("serialize and deserialize", () => {
let infoSuccessRaw: LocalQueryInfo;
let infoSuccessInterpreted: LocalQueryInfo;
let infoEarlyFailure: LocalQueryInfo;
let infoLateFailure: LocalQueryInfo;
let infoInprogress: LocalQueryInfo;
let allHistory: LocalQueryInfo[];
let queryPath: string;
let cnt = 0;
beforeEach(() => {
queryPath = join(Uri.file(tmpDir.name).fsPath, `query-${cnt++}`);
infoSuccessRaw = createMockFullQueryInfo(
"a",
createMockQueryWithResults(
`${queryPath}-a`,
false,
false,
"/a/b/c/a",
false,
),
);
infoSuccessInterpreted = createMockFullQueryInfo(
"b",
createMockQueryWithResults(
`${queryPath}-b`,
true,
true,
"/a/b/c/b",
false,
),
);
infoEarlyFailure = createMockFullQueryInfo("c", undefined, true);
infoLateFailure = createMockFullQueryInfo(
"d",
createMockQueryWithResults(
`${queryPath}-c`,
false,
false,
"/a/b/c/d",
false,
),
);
infoInprogress = createMockFullQueryInfo("e");
allHistory = [
infoSuccessRaw,
infoSuccessInterpreted,
infoEarlyFailure,
infoLateFailure,
infoInprogress,
];
});
it("should serialize and deserialize query history", async () => {
// the expected results only contains the history with completed queries
const expectedHistory = [
infoSuccessRaw,
infoSuccessInterpreted,
infoLateFailure,
];
const allHistoryPath = join(tmpDir.name, "workspace-query-history.json");
// serialize and deserialize
await serializeQueryHistory(allHistory, allHistoryPath);
const allHistoryActual = await deserializeQueryHistory(allHistoryPath);
// the dispose methods will be different. Ignore them.
allHistoryActual.forEach((info) => {
if (info.t === "local" && info.completedQuery) {
const completedQuery = info.completedQuery;
(completedQuery as any).dispose = undefined;
// these fields should be missing on the deserialized value
// but they are undefined on the original value
if (!("logFileLocation" in completedQuery)) {
(completedQuery as any).logFileLocation = undefined;
}
const query = completedQuery.query;
if (!("quickEvalPosition" in query)) {
(query as any).quickEvalPosition = undefined;
}
}
});
expectedHistory.forEach((info) => {
if (info.completedQuery) {
(info.completedQuery as any).dispose = undefined;
}
});
// make the diffs somewhat sane by comparing each element directly
for (let i = 0; i < allHistoryActual.length; i++) {
expect(allHistoryActual[i]).toEqual(expectedHistory[i]);
}
expect(allHistoryActual.length).toEqual(expectedHistory.length);
});
it("should handle an invalid query history version", async () => {
const badPath = join(tmpDir.name, "bad-query-history.json");
writeFileSync(
badPath,
JSON.stringify({
version: 3,
queries: allHistory,
}),
"utf8",
);
const allHistoryActual = await deserializeQueryHistory(badPath);
// version number is invalid. Should return an empty array.
expect(allHistoryActual).toEqual([]);
});
function createMockFullQueryInfo(
dbName = "a",
queryWithResults?: QueryWithResults,
isFail = false,
): LocalQueryInfo {
const fqi = new LocalQueryInfo(
{
databaseInfo: {
name: dbName,
databaseUri: Uri.parse(`/a/b/c/${dbName}`).fsPath,
} as unknown as DatabaseInfo,
start: new Date(),
queryPath: "path/to/hucairz",
queryText: "some query",
isQuickQuery: false,
isQuickEval: false,
id: `some-id-${dbName}`,
} as InitialQueryInfo,
{
dispose: () => {
/**/
},
} as CancellationTokenSource,
);
if (queryWithResults) {
fqi.completeThisQuery(queryWithResults);
}
if (isFail) {
fqi.failureReason = "failure reason";
}
return fqi;
}
function createMockQueryWithResults(
queryPath: string,
didRunSuccessfully = true,
hasInterpretedResults = true,
dbPath = "/a/b/c",
includeSpies = true,
): QueryWithResults {
// pretend that the results path exists
const resultsPath = join(queryPath, "results.bqrs");
mkdirpSync(queryPath);
writeFileSync(resultsPath, "", "utf8");
const query = new QueryInProgress(
queryPath,
Uri.file(dbPath).fsPath,
true,
"queryDbscheme",
undefined,
{
name: "vwx",
},
);
const result: QueryWithResults = {
query: query.queryEvalInfo,
successful: didRunSuccessfully,
message: "foo",
dispose: jest.fn(),
result: {
evaluationTime: 1,
queryId: 0,
runId: 0,
resultType: QueryResultType.SUCCESS,
},
};
if (includeSpies) {
(query as any).hasInterpretedResults = () =>
Promise.resolve(hasInterpretedResults);
}
return result;
}
});