Remove remote queries integration tests (#2060)
This commit is contained in:
@@ -1,358 +0,0 @@
|
|||||||
import { join } from "path";
|
|
||||||
import {
|
|
||||||
CancellationTokenSource,
|
|
||||||
commands,
|
|
||||||
ExtensionContext,
|
|
||||||
extensions,
|
|
||||||
QuickPickItem,
|
|
||||||
Uri,
|
|
||||||
window,
|
|
||||||
} from "vscode";
|
|
||||||
import { load } from "js-yaml";
|
|
||||||
|
|
||||||
import { QlPack } from "../../../../src/remote-queries/run-remote-query";
|
|
||||||
import { CodeQLCliServer } from "../../../../src/cli";
|
|
||||||
import { CodeQLExtensionInterface } from "../../../../src/extension";
|
|
||||||
import {
|
|
||||||
setRemoteControllerRepo,
|
|
||||||
setRemoteRepositoryLists,
|
|
||||||
} from "../../../../src/config";
|
|
||||||
import { UserCancellationException } from "../../../../src/commandRunner";
|
|
||||||
import * as ghApiClient from "../../../../src/remote-queries/gh-api/gh-api-client";
|
|
||||||
import { Repository } from "../../../../src/remote-queries/gh-api/repository";
|
|
||||||
import { createMockExtensionContext } from "../../no-workspace";
|
|
||||||
import { OutputChannelLogger } from "../../../../src/common";
|
|
||||||
import { RemoteQueriesSubmission } from "../../../../src/remote-queries/shared/remote-queries";
|
|
||||||
import { readBundledPack } from "../../utils/bundled-pack-helpers";
|
|
||||||
import { RemoteQueriesManager } from "../../../../src/remote-queries/remote-queries-manager";
|
|
||||||
import {
|
|
||||||
fixWorkspaceReferences,
|
|
||||||
restoreWorkspaceReferences,
|
|
||||||
} from "../global.helper";
|
|
||||||
import { createMockApp } from "../../../__mocks__/appMock";
|
|
||||||
import { App } from "../../../../src/common/app";
|
|
||||||
|
|
||||||
// up to 3 minutes per test
|
|
||||||
jest.setTimeout(3 * 60 * 1000);
|
|
||||||
|
|
||||||
describe("Remote queries", () => {
|
|
||||||
const baseDir = join(__dirname, "..");
|
|
||||||
|
|
||||||
const qlpackFileWithWorkspaceRefs = getFile(
|
|
||||||
"data-remote-qlpack/qlpack.yml",
|
|
||||||
).fsPath;
|
|
||||||
|
|
||||||
let cli: CodeQLCliServer;
|
|
||||||
let cancellationTokenSource: CancellationTokenSource;
|
|
||||||
const progress = jest.fn();
|
|
||||||
let showQuickPickSpy: jest.SpiedFunction<typeof window.showQuickPick>;
|
|
||||||
let getRepositoryFromNwoStub: jest.SpiedFunction<
|
|
||||||
typeof ghApiClient.getRepositoryFromNwo
|
|
||||||
>;
|
|
||||||
let ctx: ExtensionContext;
|
|
||||||
let logger: any;
|
|
||||||
let app: App;
|
|
||||||
let remoteQueriesManager: RemoteQueriesManager;
|
|
||||||
|
|
||||||
let originalDeps: Record<string, string> | undefined;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
showQuickPickSpy = jest.spyOn(window, "showQuickPick");
|
|
||||||
getRepositoryFromNwoStub = jest.spyOn(ghApiClient, "getRepositoryFromNwo");
|
|
||||||
|
|
||||||
const extension = await extensions
|
|
||||||
.getExtension<CodeQLExtensionInterface | Record<string, never>>(
|
|
||||||
"GitHub.vscode-codeql",
|
|
||||||
)!
|
|
||||||
.activate();
|
|
||||||
if ("cliServer" in extension) {
|
|
||||||
cli = extension.cliServer;
|
|
||||||
} else {
|
|
||||||
throw new Error(
|
|
||||||
"Extension not initialized. Make sure cli is downloaded and installed properly.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = createMockExtensionContext();
|
|
||||||
|
|
||||||
logger = new OutputChannelLogger("test-logger");
|
|
||||||
app = createMockApp({});
|
|
||||||
remoteQueriesManager = new RemoteQueriesManager(
|
|
||||||
ctx,
|
|
||||||
app,
|
|
||||||
cli,
|
|
||||||
"fake-storage-dir",
|
|
||||||
logger,
|
|
||||||
);
|
|
||||||
|
|
||||||
cancellationTokenSource = new CancellationTokenSource();
|
|
||||||
|
|
||||||
// Should not have asked for a language
|
|
||||||
showQuickPickSpy
|
|
||||||
.mockResolvedValueOnce({
|
|
||||||
repositories: ["github/vscode-codeql"],
|
|
||||||
} as unknown as QuickPickItem)
|
|
||||||
.mockResolvedValue("javascript" as unknown as QuickPickItem);
|
|
||||||
|
|
||||||
const dummyRepository: Repository = {
|
|
||||||
id: 123,
|
|
||||||
name: "vscode-codeql",
|
|
||||||
full_name: "github/vscode-codeql",
|
|
||||||
private: false,
|
|
||||||
};
|
|
||||||
getRepositoryFromNwoStub.mockResolvedValue(dummyRepository);
|
|
||||||
|
|
||||||
// always run in the vscode-codeql repo
|
|
||||||
await setRemoteControllerRepo("github/vscode-codeql");
|
|
||||||
await setRemoteRepositoryLists({
|
|
||||||
"vscode-codeql": ["github/vscode-codeql"],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only new version support `${workspace}` in qlpack.yml
|
|
||||||
originalDeps = await fixWorkspaceReferences(
|
|
||||||
qlpackFileWithWorkspaceRefs,
|
|
||||||
cli,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
await restoreWorkspaceReferences(qlpackFileWithWorkspaceRefs, originalDeps);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("runRemoteQuery", () => {
|
|
||||||
let mockSubmitRemoteQueries: jest.SpiedFunction<
|
|
||||||
typeof ghApiClient.submitRemoteQueries
|
|
||||||
>;
|
|
||||||
let executeCommandSpy: jest.SpiedFunction<typeof commands.executeCommand>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockSubmitRemoteQueries = jest
|
|
||||||
.spyOn(ghApiClient, "submitRemoteQueries")
|
|
||||||
.mockResolvedValue({
|
|
||||||
workflow_run_id: 20,
|
|
||||||
repositories_queried: ["octodemo/hello-world-1"],
|
|
||||||
});
|
|
||||||
|
|
||||||
executeCommandSpy = jest.spyOn(commands, "executeCommand");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should run a remote query that is part of a qlpack", async () => {
|
|
||||||
const fileUri = getFile("data-remote-qlpack/in-pack.ql");
|
|
||||||
|
|
||||||
await remoteQueriesManager.runRemoteQuery(
|
|
||||||
fileUri,
|
|
||||||
progress,
|
|
||||||
cancellationTokenSource.token,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(mockSubmitRemoteQueries).toBeCalledTimes(1);
|
|
||||||
expect(executeCommandSpy).toBeCalledWith(
|
|
||||||
"codeQL.monitorRemoteQuery",
|
|
||||||
expect.any(String),
|
|
||||||
expect.objectContaining({ queryFilePath: fileUri.fsPath }),
|
|
||||||
);
|
|
||||||
|
|
||||||
const request: RemoteQueriesSubmission =
|
|
||||||
mockSubmitRemoteQueries.mock.calls[0][1];
|
|
||||||
|
|
||||||
const packFS = await readBundledPack(request.queryPack);
|
|
||||||
|
|
||||||
// to retrieve the list of repositories
|
|
||||||
expect(showQuickPickSpy).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
expect(getRepositoryFromNwoStub).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
// check a few files that we know should exist and others that we know should not
|
|
||||||
expect(packFS.fileExists("in-pack.ql")).toBe(true);
|
|
||||||
expect(packFS.fileExists("lib.qll")).toBe(true);
|
|
||||||
expect(packFS.fileExists("qlpack.yml")).toBe(true);
|
|
||||||
|
|
||||||
// depending on the cli version, we should have one of these files
|
|
||||||
expect(
|
|
||||||
packFS.fileExists("qlpack.lock.yml") ||
|
|
||||||
packFS.fileExists("codeql-pack.lock.yml"),
|
|
||||||
).toBe(true);
|
|
||||||
expect(packFS.fileExists("not-in-pack.ql")).toBe(false);
|
|
||||||
|
|
||||||
// should have generated a correct qlpack file
|
|
||||||
const qlpackContents: any = load(
|
|
||||||
packFS.fileContents("qlpack.yml").toString("utf-8"),
|
|
||||||
);
|
|
||||||
expect(qlpackContents.name).toBe("codeql-remote/query");
|
|
||||||
|
|
||||||
verifyQlPack("in-pack.ql", packFS.fileContents("qlpack.yml"), "0.0.0");
|
|
||||||
|
|
||||||
const libraryDir = ".codeql/libraries/codeql";
|
|
||||||
const packNames = packFS.directoryContents(libraryDir).sort();
|
|
||||||
|
|
||||||
// check dependencies.
|
|
||||||
expect(packNames).toContain("javascript-all");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should run a remote query that is not part of a qlpack", async () => {
|
|
||||||
const fileUri = getFile("data-remote-no-qlpack/in-pack.ql");
|
|
||||||
|
|
||||||
await remoteQueriesManager.runRemoteQuery(
|
|
||||||
fileUri,
|
|
||||||
progress,
|
|
||||||
cancellationTokenSource.token,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(mockSubmitRemoteQueries).toBeCalledTimes(1);
|
|
||||||
expect(executeCommandSpy).toBeCalledWith(
|
|
||||||
"codeQL.monitorRemoteQuery",
|
|
||||||
expect.any(String),
|
|
||||||
expect.objectContaining({ queryFilePath: fileUri.fsPath }),
|
|
||||||
);
|
|
||||||
|
|
||||||
const request: RemoteQueriesSubmission =
|
|
||||||
mockSubmitRemoteQueries.mock.calls[0][1];
|
|
||||||
|
|
||||||
const packFS = await readBundledPack(request.queryPack);
|
|
||||||
|
|
||||||
// to retrieve the list of repositories
|
|
||||||
// and a second time to ask for the language
|
|
||||||
expect(showQuickPickSpy).toBeCalledTimes(2);
|
|
||||||
|
|
||||||
expect(getRepositoryFromNwoStub).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
// check a few files that we know should exist and others that we know should not
|
|
||||||
expect(packFS.fileExists("in-pack.ql")).toBe(true);
|
|
||||||
expect(packFS.fileExists("qlpack.yml")).toBe(true);
|
|
||||||
// depending on the cli version, we should have one of these files
|
|
||||||
expect(
|
|
||||||
packFS.fileExists("qlpack.lock.yml") ||
|
|
||||||
packFS.fileExists("codeql-pack.lock.yml"),
|
|
||||||
).toBe(true);
|
|
||||||
expect(packFS.fileExists("lib.qll")).toBe(false);
|
|
||||||
expect(packFS.fileExists("not-in-pack.ql")).toBe(false);
|
|
||||||
|
|
||||||
// the compiled pack
|
|
||||||
verifyQlPack("in-pack.ql", packFS.fileContents("qlpack.yml"), "0.0.0");
|
|
||||||
|
|
||||||
// should have generated a correct qlpack file
|
|
||||||
const qlpackContents: any = load(
|
|
||||||
packFS.fileContents("qlpack.yml").toString("utf-8"),
|
|
||||||
);
|
|
||||||
expect(qlpackContents.name).toBe("codeql-remote/query");
|
|
||||||
expect(qlpackContents.version).toBe("0.0.0");
|
|
||||||
expect(qlpackContents.dependencies?.["codeql/javascript-all"]).toBe("*");
|
|
||||||
|
|
||||||
const libraryDir = ".codeql/libraries/codeql";
|
|
||||||
const packNames = packFS.directoryContents(libraryDir).sort();
|
|
||||||
|
|
||||||
// check dependencies.
|
|
||||||
expect(packNames).toContain("javascript-all");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should run a remote query that is nested inside a qlpack", async () => {
|
|
||||||
const fileUri = getFile("data-remote-qlpack-nested/subfolder/in-pack.ql");
|
|
||||||
|
|
||||||
await remoteQueriesManager.runRemoteQuery(
|
|
||||||
fileUri,
|
|
||||||
progress,
|
|
||||||
cancellationTokenSource.token,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(mockSubmitRemoteQueries).toBeCalledTimes(1);
|
|
||||||
expect(executeCommandSpy).toBeCalledWith(
|
|
||||||
"codeQL.monitorRemoteQuery",
|
|
||||||
expect.any(String),
|
|
||||||
expect.objectContaining({ queryFilePath: fileUri.fsPath }),
|
|
||||||
);
|
|
||||||
|
|
||||||
const request: RemoteQueriesSubmission =
|
|
||||||
mockSubmitRemoteQueries.mock.calls[0][1];
|
|
||||||
|
|
||||||
const packFS = await readBundledPack(request.queryPack);
|
|
||||||
|
|
||||||
// to retrieve the list of repositories
|
|
||||||
expect(showQuickPickSpy).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
expect(getRepositoryFromNwoStub).toBeCalledTimes(1);
|
|
||||||
|
|
||||||
// check a few files that we know should exist and others that we know should not
|
|
||||||
expect(packFS.fileExists("subfolder/in-pack.ql")).toBe(true);
|
|
||||||
expect(packFS.fileExists("codeql-pack.yml")).toBe(true);
|
|
||||||
// depending on the cli version, we should have one of these files
|
|
||||||
expect(
|
|
||||||
packFS.fileExists("qlpack.lock.yml") ||
|
|
||||||
packFS.fileExists("codeql-pack.lock.yml"),
|
|
||||||
).toBe(true);
|
|
||||||
expect(packFS.fileExists("otherfolder/lib.qll")).toBe(true);
|
|
||||||
expect(packFS.fileExists("not-in-pack.ql")).toBe(false);
|
|
||||||
|
|
||||||
// the compiled pack
|
|
||||||
verifyQlPack(
|
|
||||||
"subfolder/in-pack.ql",
|
|
||||||
packFS.fileContents("codeql-pack.yml"),
|
|
||||||
"0.0.0",
|
|
||||||
);
|
|
||||||
|
|
||||||
// should have generated a correct qlpack file
|
|
||||||
const qlpackContents: any = load(
|
|
||||||
packFS.fileContents("codeql-pack.yml").toString("utf-8"),
|
|
||||||
);
|
|
||||||
expect(qlpackContents.name).toBe("codeql-remote/query");
|
|
||||||
expect(qlpackContents.version).toBe("0.0.0");
|
|
||||||
expect(qlpackContents.dependencies?.["codeql/javascript-all"]).toBe("*");
|
|
||||||
|
|
||||||
const libraryDir = ".codeql/libraries/codeql";
|
|
||||||
const packNames = packFS.directoryContents(libraryDir).sort();
|
|
||||||
|
|
||||||
// check dependencies.
|
|
||||||
expect(packNames).toContain("javascript-all");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should cancel a run before uploading", async () => {
|
|
||||||
const fileUri = getFile("data-remote-no-qlpack/in-pack.ql");
|
|
||||||
|
|
||||||
const promise = remoteQueriesManager.runRemoteQuery(
|
|
||||||
fileUri,
|
|
||||||
progress,
|
|
||||||
cancellationTokenSource.token,
|
|
||||||
);
|
|
||||||
|
|
||||||
cancellationTokenSource.cancel();
|
|
||||||
|
|
||||||
await expect(promise).rejects.toThrow(UserCancellationException);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function verifyQlPack(
|
|
||||||
queryPath: string,
|
|
||||||
contents: Buffer,
|
|
||||||
packVersion: string,
|
|
||||||
) {
|
|
||||||
const qlPack = load(contents.toString("utf-8")) as QlPack;
|
|
||||||
|
|
||||||
// don't check the build metadata since it is variable
|
|
||||||
delete (qlPack as any).buildMetadata;
|
|
||||||
|
|
||||||
expect(qlPack).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
name: "codeql-remote/query",
|
|
||||||
version: packVersion,
|
|
||||||
dependencies: {
|
|
||||||
"codeql/javascript-all": "*",
|
|
||||||
},
|
|
||||||
defaultSuite: [
|
|
||||||
{
|
|
||||||
description: "Query suite for variant analysis",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
query: queryPath,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
// v2.11.6 and later set this to false.
|
|
||||||
// Earlier versions don't set it at all.
|
|
||||||
expect(qlPack.library).toBeFalsy();
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFile(file: string): Uri {
|
|
||||||
return Uri.file(join(baseDir, file));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
import {
|
|
||||||
cancelRemoteQuery,
|
|
||||||
cancelVariantAnalysis,
|
|
||||||
getRepositoriesMetadata,
|
|
||||||
} from "../../../../../src/remote-queries/gh-api/gh-actions-api-client";
|
|
||||||
import { RemoteQuery } from "../../../../../src/remote-queries/remote-query";
|
|
||||||
import { createMockVariantAnalysis } from "../../../../factories/remote-queries/shared/variant-analysis";
|
|
||||||
import { VariantAnalysis } from "../../../../../src/remote-queries/shared/variant-analysis";
|
|
||||||
import {
|
|
||||||
testCredentialsWithStub,
|
|
||||||
testCredentialsWithRealOctokit,
|
|
||||||
} from "../../../../factories/authentication";
|
|
||||||
|
|
||||||
jest.setTimeout(10000);
|
|
||||||
|
|
||||||
describe("gh-actions-api-client mock responses", () => {
|
|
||||||
const mockRequest = jest.fn();
|
|
||||||
const mockCredentials = testCredentialsWithStub(mockRequest);
|
|
||||||
|
|
||||||
describe("cancelRemoteQuery", () => {
|
|
||||||
it("should cancel a remote query", async () => {
|
|
||||||
mockRequest.mockReturnValue({ status: 202 });
|
|
||||||
await cancelRemoteQuery(mockCredentials, createMockRemoteQuery());
|
|
||||||
|
|
||||||
expect(mockRequest).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRequest).toHaveBeenCalledWith(
|
|
||||||
"POST /repos/github/codeql/actions/runs/123/cancel",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should fail to cancel a remote query", async () => {
|
|
||||||
mockRequest.mockResolvedValue({
|
|
||||||
status: 409,
|
|
||||||
data: { message: "Uh oh!" },
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
cancelRemoteQuery(mockCredentials, createMockRemoteQuery()),
|
|
||||||
).rejects.toThrow(/Error cancelling variant analysis: 409 Uh oh!/);
|
|
||||||
expect(mockRequest).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRequest).toHaveBeenCalledWith(
|
|
||||||
"POST /repos/github/codeql/actions/runs/123/cancel",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
function createMockRemoteQuery(): RemoteQuery {
|
|
||||||
return {
|
|
||||||
actionsWorkflowRunId: 123,
|
|
||||||
controllerRepository: {
|
|
||||||
owner: "github",
|
|
||||||
name: "codeql",
|
|
||||||
},
|
|
||||||
} as unknown as RemoteQuery;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("cancelVariantAnalysis", () => {
|
|
||||||
let variantAnalysis: VariantAnalysis;
|
|
||||||
beforeAll(() => {
|
|
||||||
variantAnalysis = createMockVariantAnalysis({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should cancel a variant analysis", async () => {
|
|
||||||
mockRequest.mockResolvedValue({ status: 202 });
|
|
||||||
await cancelVariantAnalysis(mockCredentials, variantAnalysis);
|
|
||||||
|
|
||||||
expect(mockRequest).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRequest).toHaveBeenCalledWith(
|
|
||||||
`POST /repos/${variantAnalysis.controllerRepo.fullName}/actions/runs/${variantAnalysis.actionsWorkflowRunId}/cancel`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should fail to cancel a variant analysis", async () => {
|
|
||||||
mockRequest.mockResolvedValue({
|
|
||||||
status: 409,
|
|
||||||
data: { message: "Uh oh!" },
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
cancelVariantAnalysis(mockCredentials, variantAnalysis),
|
|
||||||
).rejects.toThrow(/Error cancelling variant analysis: 409 Uh oh!/);
|
|
||||||
expect(mockRequest).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockRequest).toHaveBeenCalledWith(
|
|
||||||
`POST /repos/${variantAnalysis.controllerRepo.fullName}/actions/runs/${variantAnalysis.actionsWorkflowRunId}/cancel`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("gh-actions-api-client real responses", () => {
|
|
||||||
it("should get the stargazers for repos", async () => {
|
|
||||||
if (skip()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const credentials = testCredentialsWithRealOctokit(
|
|
||||||
process.env.VSCODE_CODEQL_GITHUB_TOKEN!,
|
|
||||||
);
|
|
||||||
const stargazers = await getRepositoriesMetadata(
|
|
||||||
credentials,
|
|
||||||
[
|
|
||||||
"github/codeql",
|
|
||||||
"github/vscode-codeql",
|
|
||||||
"rails/rails",
|
|
||||||
"angular/angular",
|
|
||||||
"github/hucairz", // This one should not be in the list
|
|
||||||
],
|
|
||||||
// choose a page size that is small enough to ensure we make multiple requests
|
|
||||||
2,
|
|
||||||
);
|
|
||||||
|
|
||||||
const stargazersKeys = Object.keys(stargazers).sort();
|
|
||||||
expect(stargazersKeys).toEqual([
|
|
||||||
"angular/angular",
|
|
||||||
"github/codeql",
|
|
||||||
"github/vscode-codeql",
|
|
||||||
"rails/rails",
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
function skip() {
|
|
||||||
if (!process.env.VSCODE_CODEQL_GITHUB_TOKEN) {
|
|
||||||
if (process.env.CI) {
|
|
||||||
throw new Error(
|
|
||||||
"The VSCODE_CODEQL_GITHUB_TOKEN must be set to a valid GITHUB token on CI",
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log(
|
|
||||||
"Skipping gh-actions-api-client real responses tests. To run these tests, set the value VSCODE_CODEQL_GITHUB_TOKEN to a GitHub token.",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
import { EOL } from "os";
|
|
||||||
import { parseResponse } from "../../../../src/remote-queries/remote-queries-api";
|
|
||||||
import { Repository } from "../../../../src/remote-queries/shared/repository";
|
|
||||||
|
|
||||||
describe("parseResponse", () => {
|
|
||||||
const controllerRepository: Repository = {
|
|
||||||
id: 123,
|
|
||||||
fullName: "org/name",
|
|
||||||
private: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
it("should parse a successful response", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should parse a response with invalid repos", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
errors: {
|
|
||||||
invalid_repositories: ["e/f", "g/h"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"2 repositories invalid and could not be found:",
|
|
||||||
"e/f, g/h",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should parse a response with repos w/o databases", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
errors: {
|
|
||||||
repositories_without_database: ["e/f", "g/h"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"2 repositories did not have a CodeQL database available:",
|
|
||||||
"e/f, g/h",
|
|
||||||
"For each public repository that has not yet been added to the database service, we will try to create a database next time the store is updated.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should parse a response with private repos", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
errors: {
|
|
||||||
private_repositories: ["e/f", "g/h"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"2 repositories not public:",
|
|
||||||
"e/f, g/h",
|
|
||||||
"When using a public controller repository, only public repositories can be queried.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should parse a response with cutoff repos and cutoff repos count", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
errors: {
|
|
||||||
cutoff_repositories: ["e/f", "g/h"],
|
|
||||||
cutoff_repositories_count: 2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"2 repositories over the limit for a single request:",
|
|
||||||
"e/f, g/h",
|
|
||||||
"Repositories were selected based on how recently they had been updated.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should parse a response with cutoff repos count but not cutoff repos", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
errors: {
|
|
||||||
cutoff_repositories_count: 2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"2 repositories over the limit for a single request.",
|
|
||||||
"Repositories were selected based on how recently they had been updated.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should parse a response with invalid repos and repos w/o databases", () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b", "c/d"],
|
|
||||||
errors: {
|
|
||||||
invalid_repositories: ["e/f", "g/h"],
|
|
||||||
repositories_without_database: ["i/j", "k/l"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 2 repositories. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b, c/d",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"2 repositories invalid and could not be found:",
|
|
||||||
"e/f, g/h",
|
|
||||||
"",
|
|
||||||
"2 repositories did not have a CodeQL database available:",
|
|
||||||
"i/j, k/l",
|
|
||||||
"For each public repository that has not yet been added to the database service, we will try to create a database next time the store is updated.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should parse a response with one repo of each category, and not pluralize "repositories"', () => {
|
|
||||||
const result = parseResponse(controllerRepository, {
|
|
||||||
workflow_run_id: 123,
|
|
||||||
repositories_queried: ["a/b"],
|
|
||||||
errors: {
|
|
||||||
private_repositories: ["e/f"],
|
|
||||||
cutoff_repositories: ["i/j"],
|
|
||||||
cutoff_repositories_count: 1,
|
|
||||||
invalid_repositories: ["m/n"],
|
|
||||||
repositories_without_database: ["q/r"],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result.popupMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 1 repository. [Click here to see the progress](https://github.com/org/name/actions/runs/123).",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled. See extension log for details.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
expect(result.logMessage).toBe(
|
|
||||||
[
|
|
||||||
"Successfully scheduled runs on 1 repository. See https://github.com/org/name/actions/runs/123.",
|
|
||||||
"",
|
|
||||||
"Repositories queried:",
|
|
||||||
"a/b",
|
|
||||||
"",
|
|
||||||
"Some repositories could not be scheduled.",
|
|
||||||
"",
|
|
||||||
"1 repository invalid and could not be found:",
|
|
||||||
"m/n",
|
|
||||||
"",
|
|
||||||
"1 repository did not have a CodeQL database available:",
|
|
||||||
"q/r",
|
|
||||||
"For each public repository that has not yet been added to the database service, we will try to create a database next time the store is updated.",
|
|
||||||
"",
|
|
||||||
"1 repository not public:",
|
|
||||||
"e/f",
|
|
||||||
"When using a public controller repository, only public repositories can be queried.",
|
|
||||||
"",
|
|
||||||
"1 repository over the limit for a single request:",
|
|
||||||
"i/j",
|
|
||||||
"Repositories were selected based on how recently they had been updated.",
|
|
||||||
].join(EOL),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Reference in New Issue
Block a user