Skip to content

Commit 0115259

Browse files
authored
Merge pull request #2271 from github/koesie10/data-extension-editor-cli-tests
Split and add tests for external API usages query
2 parents ccf9466 + 6dfa726 commit 0115259

File tree

5 files changed

+358
-92
lines changed

5 files changed

+358
-92
lines changed

extensions/ql-vscode/src/contextual/queryResolver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import { redactableError } from "../pure/errors";
2121
import { QLPACK_FILENAMES } from "../pure/ql";
2222

2323
export async function qlpackOfDatabase(
24-
cli: CodeQLCliServer,
25-
db: DatabaseItem,
24+
cli: Pick<CodeQLCliServer, "resolveQlpacks">,
25+
db: Pick<DatabaseItem, "contents">,
2626
): Promise<QlPacksForLanguage> {
2727
if (db.contents === undefined) {
2828
throw new Error("Database is invalid and cannot infer QLPack.");

extensions/ql-vscode/src/data-extensions-editor/data-extensions-editor-view.ts

Lines changed: 24 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,14 @@ import {
1313
ToDataExtensionsEditorMessage,
1414
} from "../pure/interface-types";
1515
import { ProgressUpdate } from "../progress";
16-
import { extLogger, TeeLogger } from "../common";
17-
import { CoreCompletedQuery, QueryRunner } from "../queryRunner";
18-
import { qlpackOfDatabase } from "../contextual/queryResolver";
19-
import { file } from "tmp-promise";
20-
import { readFile, writeFile } from "fs-extra";
21-
import { dump as dumpYaml, load as loadYaml } from "js-yaml";
16+
import { QueryRunner } from "../queryRunner";
2217
import {
23-
getOnDiskWorkspaceFolders,
2418
showAndLogExceptionWithTelemetry,
2519
showAndLogWarningMessage,
2620
} from "../helpers";
21+
import { extLogger } from "../common";
22+
import { readFile, writeFile } from "fs-extra";
23+
import { load as loadYaml } from "js-yaml";
2724
import { DatabaseItem, DatabaseManager } from "../local-databases";
2825
import { CodeQLCliServer } from "../cli";
2926
import { asError, assertNever, getErrorMessage } from "../pure/helpers-pure";
@@ -34,6 +31,7 @@ import { ResolvableLocationValue } from "../pure/bqrs-cli-types";
3431
import { showResolvableLocation } from "../interface-utils";
3532
import { decodeBqrsToExternalApiUsages } from "./bqrs";
3633
import { redactableError } from "../pure/errors";
34+
import { readQueryResults, runQuery } from "./external-api-usage-query";
3735
import { createDataExtensionYaml, loadDataExtensionYaml } from "./yaml";
3836
import { ExternalApiUsage } from "./external-api-usage";
3937
import { ModeledMethod } from "./modeled-method";
@@ -192,22 +190,36 @@ export class DataExtensionsEditorView extends AbstractWebview<
192190
}
193191

194192
protected async loadExternalApiUsages(): Promise<void> {
193+
const cancellationTokenSource = new CancellationTokenSource();
194+
195195
try {
196-
const queryResult = await this.runQuery();
196+
const queryResult = await runQuery({
197+
cliServer: this.cliServer,
198+
queryRunner: this.queryRunner,
199+
databaseItem: this.databaseItem,
200+
queryStorageDir: this.queryStorageDir,
201+
logger: extLogger,
202+
progress: (progressUpdate: ProgressUpdate) => {
203+
void this.showProgress(progressUpdate, 1500);
204+
},
205+
token: cancellationTokenSource.token,
206+
});
197207
if (!queryResult) {
198208
await this.clearProgress();
199209
return;
200210
}
201211

202212
await this.showProgress({
203-
message: "Loading results",
213+
message: "Decoding results",
204214
step: 1100,
205215
maxStep: 1500,
206216
});
207217

208-
const bqrsPath = queryResult.outputDir.bqrsPath;
209-
210-
const bqrsChunk = await this.getResults(bqrsPath);
218+
const bqrsChunk = await readQueryResults({
219+
cliServer: this.cliServer,
220+
bqrsPath: queryResult.outputDir.bqrsPath,
221+
logger: extLogger,
222+
});
211223
if (!bqrsChunk) {
212224
await this.clearProgress();
213225
return;
@@ -322,83 +334,6 @@ export class DataExtensionsEditorView extends AbstractWebview<
322334
await this.clearProgress();
323335
}
324336

325-
private async runQuery(): Promise<CoreCompletedQuery | undefined> {
326-
const qlpacks = await qlpackOfDatabase(this.cliServer, this.databaseItem);
327-
328-
const packsToSearch = [qlpacks.dbschemePack];
329-
if (qlpacks.queryPack) {
330-
packsToSearch.push(qlpacks.queryPack);
331-
}
332-
333-
const suiteFile = (
334-
await file({
335-
postfix: ".qls",
336-
})
337-
).path;
338-
const suiteYaml = [];
339-
for (const qlpack of packsToSearch) {
340-
suiteYaml.push({
341-
from: qlpack,
342-
queries: ".",
343-
include: {
344-
id: `${this.databaseItem.language}/telemetry/fetch-external-apis`,
345-
},
346-
});
347-
}
348-
await writeFile(suiteFile, dumpYaml(suiteYaml), "utf8");
349-
350-
const queries = await this.cliServer.resolveQueriesInSuite(
351-
suiteFile,
352-
getOnDiskWorkspaceFolders(),
353-
);
354-
355-
if (queries.length !== 1) {
356-
void extLogger.log(`Expected exactly one query, got ${queries.length}`);
357-
return;
358-
}
359-
360-
const query = queries[0];
361-
362-
const tokenSource = new CancellationTokenSource();
363-
364-
const queryRun = this.queryRunner.createQueryRun(
365-
this.databaseItem.databaseUri.fsPath,
366-
{ queryPath: query, quickEvalPosition: undefined },
367-
false,
368-
getOnDiskWorkspaceFolders(),
369-
undefined,
370-
this.queryStorageDir,
371-
undefined,
372-
undefined,
373-
);
374-
375-
return queryRun.evaluate(
376-
(update) => this.showProgress(update, 1500),
377-
tokenSource.token,
378-
new TeeLogger(this.queryRunner.logger, queryRun.outputDir.logPath),
379-
);
380-
}
381-
382-
private async getResults(bqrsPath: string) {
383-
const bqrsInfo = await this.cliServer.bqrsInfo(bqrsPath);
384-
if (bqrsInfo["result-sets"].length !== 1) {
385-
void extLogger.log(
386-
`Expected exactly one result set, got ${bqrsInfo["result-sets"].length}`,
387-
);
388-
return undefined;
389-
}
390-
391-
const resultSet = bqrsInfo["result-sets"][0];
392-
393-
await this.showProgress({
394-
message: "Decoding results",
395-
step: 1200,
396-
maxStep: 1500,
397-
});
398-
399-
return this.cliServer.bqrsDecode(bqrsPath, resultSet.name);
400-
}
401-
402337
/*
403338
* Progress in this class is a bit weird. Most of the progress is based on running the query.
404339
* Query progress is always between 0 and 1000. However, we still have some steps that need
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { CoreCompletedQuery, QueryRunner } from "../queryRunner";
2+
import { qlpackOfDatabase } from "../contextual/queryResolver";
3+
import { file } from "tmp-promise";
4+
import { writeFile } from "fs-extra";
5+
import { dump as dumpYaml } from "js-yaml";
6+
import { getOnDiskWorkspaceFolders } from "../helpers";
7+
import { Logger, TeeLogger } from "../common";
8+
import { CancellationToken } from "vscode";
9+
import { CodeQLCliServer } from "../cli";
10+
import { DatabaseItem } from "../local-databases";
11+
import { ProgressCallback } from "../progress";
12+
13+
export type RunQueryOptions = {
14+
cliServer: Pick<CodeQLCliServer, "resolveQlpacks" | "resolveQueriesInSuite">;
15+
queryRunner: Pick<QueryRunner, "createQueryRun" | "logger">;
16+
databaseItem: Pick<DatabaseItem, "contents" | "databaseUri" | "language">;
17+
queryStorageDir: string;
18+
logger: Logger;
19+
20+
progress: ProgressCallback;
21+
token: CancellationToken;
22+
};
23+
24+
export async function runQuery({
25+
cliServer,
26+
queryRunner,
27+
databaseItem,
28+
queryStorageDir,
29+
logger,
30+
progress,
31+
token,
32+
}: RunQueryOptions): Promise<CoreCompletedQuery | undefined> {
33+
const qlpacks = await qlpackOfDatabase(cliServer, databaseItem);
34+
35+
const packsToSearch = [qlpacks.dbschemePack];
36+
if (qlpacks.queryPack) {
37+
packsToSearch.push(qlpacks.queryPack);
38+
}
39+
40+
const suiteFile = (
41+
await file({
42+
postfix: ".qls",
43+
})
44+
).path;
45+
const suiteYaml = [];
46+
for (const qlpack of packsToSearch) {
47+
suiteYaml.push({
48+
from: qlpack,
49+
queries: ".",
50+
include: {
51+
id: `${databaseItem.language}/telemetry/fetch-external-apis`,
52+
},
53+
});
54+
}
55+
await writeFile(suiteFile, dumpYaml(suiteYaml), "utf8");
56+
57+
const queries = await cliServer.resolveQueriesInSuite(
58+
suiteFile,
59+
getOnDiskWorkspaceFolders(),
60+
);
61+
62+
if (queries.length !== 1) {
63+
void logger.log(`Expected exactly one query, got ${queries.length}`);
64+
return;
65+
}
66+
67+
const query = queries[0];
68+
69+
const queryRun = queryRunner.createQueryRun(
70+
databaseItem.databaseUri.fsPath,
71+
{ queryPath: query, quickEvalPosition: undefined },
72+
false,
73+
getOnDiskWorkspaceFolders(),
74+
undefined,
75+
queryStorageDir,
76+
undefined,
77+
undefined,
78+
);
79+
80+
return queryRun.evaluate(
81+
progress,
82+
token,
83+
new TeeLogger(queryRunner.logger, queryRun.outputDir.logPath),
84+
);
85+
}
86+
87+
export type GetResultsOptions = {
88+
cliServer: Pick<CodeQLCliServer, "bqrsInfo" | "bqrsDecode">;
89+
bqrsPath: string;
90+
logger: Logger;
91+
};
92+
93+
export async function readQueryResults({
94+
cliServer,
95+
bqrsPath,
96+
logger,
97+
}: GetResultsOptions) {
98+
const bqrsInfo = await cliServer.bqrsInfo(bqrsPath);
99+
if (bqrsInfo["result-sets"].length !== 1) {
100+
void logger.log(
101+
`Expected exactly one result set, got ${bqrsInfo["result-sets"].length}`,
102+
);
103+
return undefined;
104+
}
105+
106+
const resultSet = bqrsInfo["result-sets"][0];
107+
108+
return cliServer.bqrsDecode(bqrsPath, resultSet.name);
109+
}

extensions/ql-vscode/src/helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ function findStandardQueryPack(
478478
}
479479

480480
export async function getQlPackForDbscheme(
481-
cliServer: CodeQLCliServer,
481+
cliServer: Pick<CodeQLCliServer, "resolveQlpacks">,
482482
dbschemePath: string,
483483
): Promise<QlPacksForLanguage> {
484484
const qlpacks = await cliServer.resolveQlpacks(getOnDiskWorkspaceFolders());

0 commit comments

Comments
 (0)