Skip to content

Commit 5841fbc

Browse files
authored
Merge pull request #1785 from github/jest-migration/cli-integration
Migrate CLI integration tests to Jest
2 parents 91ca948 + 925acbd commit 5841fbc

40 files changed

Lines changed: 1457 additions & 1383 deletions

extensions/ql-vscode/jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = {
88
projects: [
99
"<rootDir>/src/view",
1010
"<rootDir>/test",
11+
"<rootDir>/out/vscode-tests/cli-integration",
1112
"<rootDir>/out/vscode-tests/no-workspace",
1213
"<rootDir>/out/vscode-tests/minimal-workspace",
1314
],

extensions/ql-vscode/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,7 @@
12751275
"integration": "npm-run-all integration:*",
12761276
"integration:no-workspace": "jest --projects out/vscode-tests/no-workspace",
12771277
"integration:minimal-workspace": "jest --projects out/vscode-tests/minimal-workspace",
1278-
"cli-integration": "node ./out/vscode-tests/run-integration-tests.js cli-integration",
1278+
"cli-integration": "jest --projects out/vscode-tests/cli-integration",
12791279
"update-vscode": "node ./node_modules/vscode/bin/install",
12801280
"format": "prettier --write **/*.{ts,tsx} && eslint . --ext .ts,.tsx --fix",
12811281
"lint": "eslint . --ext .ts,.tsx --max-warnings=0",

extensions/ql-vscode/src/distribution.ts

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import * as fs from "fs-extra";
33
import * as os from "os";
44
import * as path from "path";
55
import * as semver from "semver";
6-
import * as unzipper from "unzipper";
76
import * as url from "url";
87
import { ExtensionContext, Event } from "vscode";
98
import { DistributionConfig } from "./config";
@@ -16,6 +15,12 @@ import {
1615
import { logger } from "./logging";
1716
import { getCodeQlCliVersion } from "./cli-version";
1817
import { ProgressCallback, reportStreamProgress } from "./commandRunner";
18+
import {
19+
codeQlLauncherName,
20+
deprecatedCodeQlLauncherName,
21+
extractZipArchive,
22+
getRequiredAssetName,
23+
} from "./pure/distribution";
1924

2025
/**
2126
* distribution.ts
@@ -55,22 +60,6 @@ export interface DistributionProvider {
5560
}
5661

5762
export class DistributionManager implements DistributionProvider {
58-
/**
59-
* Get the name of the codeql cli installation we prefer to install, based on our current platform.
60-
*/
61-
public static getRequiredAssetName(): string {
62-
switch (os.platform()) {
63-
case "linux":
64-
return "codeql-linux64.zip";
65-
case "darwin":
66-
return "codeql-osx64.zip";
67-
case "win32":
68-
return "codeql-win64.zip";
69-
default:
70-
return "codeql.zip";
71-
}
72-
}
73-
7463
constructor(
7564
public readonly config: DistributionConfig,
7665
private readonly versionRange: semver.Range,
@@ -361,7 +350,7 @@ class ExtensionSpecificDistributionManager {
361350
}
362351

363352
// Filter assets to the unique one that we require.
364-
const requiredAssetName = DistributionManager.getRequiredAssetName();
353+
const requiredAssetName = getRequiredAssetName();
365354
const assets = release.assets.filter(
366355
(asset) => asset.name === requiredAssetName,
367356
);
@@ -431,7 +420,7 @@ class ExtensionSpecificDistributionManager {
431420
}
432421

433422
private async getLatestRelease(): Promise<Release> {
434-
const requiredAssetName = DistributionManager.getRequiredAssetName();
423+
const requiredAssetName = getRequiredAssetName();
435424
void logger.log(
436425
`Searching for latest release including ${requiredAssetName}.`,
437426
);
@@ -683,39 +672,6 @@ export class ReleasesApiConsumer {
683672
private static readonly _maxRedirects = 20;
684673
}
685674

686-
export async function extractZipArchive(
687-
archivePath: string,
688-
outPath: string,
689-
): Promise<void> {
690-
const archive = await unzipper.Open.file(archivePath);
691-
await archive.extract({
692-
concurrency: 4,
693-
path: outPath,
694-
});
695-
// Set file permissions for extracted files
696-
await Promise.all(
697-
archive.files.map(async (file) => {
698-
// Only change file permissions if within outPath (path.join normalises the path)
699-
const extractedPath = path.join(outPath, file.path);
700-
if (
701-
extractedPath.indexOf(outPath) !== 0 ||
702-
!(await fs.pathExists(extractedPath))
703-
) {
704-
return Promise.resolve();
705-
}
706-
return fs.chmod(extractedPath, file.externalFileAttributes >>> 16);
707-
}),
708-
);
709-
}
710-
711-
export function codeQlLauncherName(): string {
712-
return os.platform() === "win32" ? "codeql.exe" : "codeql";
713-
}
714-
715-
function deprecatedCodeQlLauncherName(): string | undefined {
716-
return os.platform() === "win32" ? "codeql.cmd" : undefined;
717-
}
718-
719675
function isRedirectStatusCode(statusCode: number): boolean {
720676
return (
721677
statusCode === 301 ||
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import * as os from "os";
2+
import * as unzipper from "unzipper";
3+
import * as path from "path";
4+
import * as fs from "fs-extra";
5+
6+
/**
7+
* Get the name of the codeql cli installation we prefer to install, based on our current platform.
8+
*/
9+
export function getRequiredAssetName(): string {
10+
switch (os.platform()) {
11+
case "linux":
12+
return "codeql-linux64.zip";
13+
case "darwin":
14+
return "codeql-osx64.zip";
15+
case "win32":
16+
return "codeql-win64.zip";
17+
default:
18+
return "codeql.zip";
19+
}
20+
}
21+
22+
export async function extractZipArchive(
23+
archivePath: string,
24+
outPath: string,
25+
): Promise<void> {
26+
const archive = await unzipper.Open.file(archivePath);
27+
await archive.extract({
28+
concurrency: 4,
29+
path: outPath,
30+
});
31+
// Set file permissions for extracted files
32+
await Promise.all(
33+
archive.files.map(async (file) => {
34+
// Only change file permissions if within outPath (path.join normalises the path)
35+
const extractedPath = path.join(outPath, file.path);
36+
if (
37+
extractedPath.indexOf(outPath) !== 0 ||
38+
!(await fs.pathExists(extractedPath))
39+
) {
40+
return Promise.resolve();
41+
}
42+
return fs.chmod(extractedPath, file.externalFileAttributes >>> 16);
43+
}),
44+
);
45+
}
46+
47+
export function codeQlLauncherName(): string {
48+
return os.platform() === "win32" ? "codeql.exe" : "codeql";
49+
}
50+
51+
export function deprecatedCodeQlLauncherName(): string | undefined {
52+
return os.platform() === "win32" ? "codeql.cmd" : undefined;
53+
}

extensions/ql-vscode/src/vscode-tests/cli-integration/databases.test.ts

Lines changed: 37 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import * as sinon from "sinon";
21
import * as path from "path";
3-
import { fail } from "assert";
4-
import { expect } from "chai";
52
import { extensions, CancellationToken, Uri, window } from "vscode";
63

74
import { CodeQLExtensionInterface } from "../../extension";
@@ -12,64 +9,51 @@ import {
129
importArchiveDatabase,
1310
promptImportInternetDatabase,
1411
} from "../../databaseFetcher";
15-
import { ProgressCallback } from "../../commandRunner";
1612
import { cleanDatabases, dbLoc, DB_URL, storagePath } from "./global.helper";
1713

14+
jest.setTimeout(60_000);
15+
1816
/**
1917
* Run various integration tests for databases
2018
*/
21-
describe("Databases", function () {
22-
this.timeout(60000);
23-
19+
describe("Databases", () => {
2420
const LGTM_URL =
2521
"https://lgtm.com/projects/g/aeisenberg/angular-bind-notifier/";
2622

2723
let databaseManager: DatabaseManager;
28-
let sandbox: sinon.SinonSandbox;
29-
let inputBoxStub: sinon.SinonStub;
24+
let inputBoxStub: jest.SpiedFunction<typeof window.showInputBox>;
3025
let cli: CodeQLCliServer;
31-
let progressCallback: ProgressCallback;
26+
const progressCallback = jest.fn();
3227

3328
beforeEach(async () => {
34-
try {
35-
sandbox = sinon.createSandbox();
36-
// the uri.fsPath function on windows returns a lowercase drive letter
37-
// so, force the storage path string to be lowercase, too.
38-
progressCallback = sandbox.spy();
39-
inputBoxStub = sandbox.stub(window, "showInputBox");
40-
sandbox.stub(window, "showErrorMessage");
41-
sandbox.stub(window, "showInformationMessage");
29+
inputBoxStub = jest
30+
.spyOn(window, "showInputBox")
31+
.mockResolvedValue(undefined);
4232

43-
const extension = await extensions
44-
.getExtension<CodeQLExtensionInterface | Record<string, never>>(
45-
"GitHub.vscode-codeql",
46-
)!
47-
.activate();
48-
if ("databaseManager" in extension) {
49-
databaseManager = extension.databaseManager;
50-
} else {
51-
throw new Error(
52-
"Extension not initialized. Make sure cli is downloaded and installed properly.",
53-
);
54-
}
33+
jest.spyOn(window, "showErrorMessage").mockResolvedValue(undefined);
34+
jest.spyOn(window, "showInformationMessage").mockResolvedValue(undefined);
5535

56-
await cleanDatabases(databaseManager);
57-
} catch (e) {
58-
fail(e as Error);
36+
const extension = await extensions
37+
.getExtension<CodeQLExtensionInterface | Record<string, never>>(
38+
"GitHub.vscode-codeql",
39+
)!
40+
.activate();
41+
if ("databaseManager" in extension) {
42+
databaseManager = extension.databaseManager;
43+
} else {
44+
throw new Error(
45+
"Extension not initialized. Make sure cli is downloaded and installed properly.",
46+
);
5947
}
48+
49+
await cleanDatabases(databaseManager);
6050
});
6151

6252
afterEach(async () => {
63-
try {
64-
sandbox.restore();
65-
await cleanDatabases(databaseManager);
66-
} catch (e) {
67-
fail(e as Error);
68-
}
53+
await cleanDatabases(databaseManager);
6954
});
7055

7156
it("should add a database from a folder", async () => {
72-
const progressCallback = sandbox.spy() as ProgressCallback;
7357
const uri = Uri.file(dbLoc);
7458
let dbItem = await importArchiveDatabase(
7559
uri.toString(true),
@@ -79,27 +63,27 @@ describe("Databases", function () {
7963
{} as CancellationToken,
8064
cli,
8165
);
82-
expect(dbItem).to.be.eq(databaseManager.currentDatabaseItem);
83-
expect(dbItem).to.be.eq(databaseManager.databaseItems[0]);
84-
expect(dbItem).not.to.be.undefined;
66+
expect(dbItem).toBe(databaseManager.currentDatabaseItem);
67+
expect(dbItem).toBe(databaseManager.databaseItems[0]);
68+
expect(dbItem).toBeDefined();
8569
dbItem = dbItem!;
86-
expect(dbItem.name).to.eq("db");
87-
expect(dbItem.databaseUri.fsPath).to.eq(path.join(storagePath, "db", "db"));
70+
expect(dbItem.name).toBe("db");
71+
expect(dbItem.databaseUri.fsPath).toBe(path.join(storagePath, "db", "db"));
8872
});
8973

9074
it("should add a database from lgtm with only one language", async () => {
91-
inputBoxStub.resolves(LGTM_URL);
75+
inputBoxStub.mockResolvedValue(LGTM_URL);
9276
let dbItem = await promptImportLgtmDatabase(
9377
databaseManager,
9478
storagePath,
9579
progressCallback,
9680
{} as CancellationToken,
9781
cli,
9882
);
99-
expect(dbItem).not.to.be.undefined;
83+
expect(dbItem).toBeDefined();
10084
dbItem = dbItem!;
101-
expect(dbItem.name).to.eq("aeisenberg_angular-bind-notifier_106179a");
102-
expect(dbItem.databaseUri.fsPath).to.eq(
85+
expect(dbItem.name).toBe("aeisenberg_angular-bind-notifier_106179a");
86+
expect(dbItem.databaseUri.fsPath).toBe(
10387
path.join(
10488
storagePath,
10589
"javascript",
@@ -109,7 +93,7 @@ describe("Databases", function () {
10993
});
11094

11195
it("should add a database from a url", async () => {
112-
inputBoxStub.resolves(DB_URL);
96+
inputBoxStub.mockResolvedValue(DB_URL);
11397

11498
let dbItem = await promptImportInternetDatabase(
11599
databaseManager,
@@ -118,10 +102,10 @@ describe("Databases", function () {
118102
{} as CancellationToken,
119103
cli,
120104
);
121-
expect(dbItem).not.to.be.undefined;
105+
expect(dbItem).toBeDefined();
122106
dbItem = dbItem!;
123-
expect(dbItem.name).to.eq("db");
124-
expect(dbItem.databaseUri.fsPath).to.eq(
107+
expect(dbItem.name).toBe("db");
108+
expect(dbItem.databaseUri.fsPath).toBe(
125109
path.join(storagePath, "simple-db", "db"),
126110
);
127111
});

0 commit comments

Comments
 (0)