Run some unit tests in parallel

This commit is contained in:
Henry Mercer
2026-03-04 12:38:18 +01:00
parent 281b265245
commit 675af55c60
39 changed files with 4647 additions and 4029 deletions

View File

@@ -87,14 +87,14 @@ const sendFailedStatusReportTest = test.macro({
title: (providedTitle = "") => `sendFailedStatusReport - ${providedTitle}`,
});
test(
test.serial(
"reports generic error message for non-StartProxyError error",
sendFailedStatusReportTest,
new Error("Something went wrong today"),
"Error from start-proxy Action omitted (Error).",
);
test(
test.serial(
"reports generic error message for non-StartProxyError error with safe error message",
sendFailedStatusReportTest,
new Error(
@@ -105,7 +105,7 @@ test(
"Error from start-proxy Action omitted (Error).",
);
test(
test.serial(
"reports generic error message for ConfigurationError error",
sendFailedStatusReportTest,
new ConfigurationError("Something went wrong today"),
@@ -124,110 +124,125 @@ const mixedCredentials = [
{ type: "git_source", host: "github.com/github", token: "mno" },
];
test("getCredentials prefers registriesCredentials over registrySecrets", async (t) => {
const registryCredentials = Buffer.from(
JSON.stringify([
{ type: "npm_registry", host: "npm.pkg.github.com", token: "abc" },
]),
).toString("base64");
const registrySecrets = JSON.stringify([
{ type: "npm_registry", host: "registry.npmjs.org", token: "def" },
]);
test.serial(
"getCredentials prefers registriesCredentials over registrySecrets",
async (t) => {
const registryCredentials = Buffer.from(
JSON.stringify([
{ type: "npm_registry", host: "npm.pkg.github.com", token: "abc" },
]),
).toString("base64");
const registrySecrets = JSON.stringify([
{ type: "npm_registry", host: "registry.npmjs.org", token: "def" },
]);
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
registrySecrets,
registryCredentials,
undefined,
);
t.is(credentials.length, 1);
t.is(credentials[0].host, "npm.pkg.github.com");
});
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
registrySecrets,
registryCredentials,
undefined,
);
t.is(credentials.length, 1);
t.is(credentials[0].host, "npm.pkg.github.com");
},
);
test("getCredentials throws an error when configurations are not an array", async (t) => {
const registryCredentials = Buffer.from(
JSON.stringify({ type: "npm_registry", token: "abc" }),
).toString("base64");
test.serial(
"getCredentials throws an error when configurations are not an array",
async (t) => {
const registryCredentials = Buffer.from(
JSON.stringify({ type: "npm_registry", token: "abc" }),
).toString("base64");
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
registryCredentials,
undefined,
),
{
message:
"Expected credentials data to be an array of configurations, but it is not.",
},
);
});
test("getCredentials throws error when credential is not an object", async (t) => {
const testCredentials = [["foo"], [null]].map(toEncodedJSON);
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
registryCredentials,
undefined,
),
{
message: "Invalid credentials - must be an object",
message:
"Expected credentials data to be an array of configurations, but it is not.",
},
);
}
});
},
);
test("getCredentials throws error when credential is missing type", async (t) => {
const testCredentials = [[{ token: "abc", url: "https://localhost" }]].map(
toEncodedJSON,
);
test.serial(
"getCredentials throws error when credential is not an object",
async (t) => {
const testCredentials = [["foo"], [null]].map(toEncodedJSON);
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
undefined,
),
{
message: "Invalid credentials - must have a type",
},
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
undefined,
),
{
message: "Invalid credentials - must be an object",
},
);
}
},
);
test.serial(
"getCredentials throws error when credential is missing type",
async (t) => {
const testCredentials = [[{ token: "abc", url: "https://localhost" }]].map(
toEncodedJSON,
);
}
});
test("getCredentials throws error when credential missing host and url", async (t) => {
const testCredentials = [
[{ type: "npm_registry", token: "abc" }],
[{ type: "npm_registry", token: "abc", host: null }],
[{ type: "npm_registry", token: "abc", url: null }],
].map(toEncodedJSON);
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
undefined,
),
{
message: "Invalid credentials - must have a type",
},
);
}
},
);
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
undefined,
),
{
message: "Invalid credentials - must specify host or url",
},
);
}
});
test.serial(
"getCredentials throws error when credential missing host and url",
async (t) => {
const testCredentials = [
[{ type: "npm_registry", token: "abc" }],
[{ type: "npm_registry", token: "abc", host: null }],
[{ type: "npm_registry", token: "abc", url: null }],
].map(toEncodedJSON);
test("getCredentials filters by language when specified", async (t) => {
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
undefined,
),
{
message: "Invalid credentials - must specify host or url",
},
);
}
},
);
test.serial("getCredentials filters by language when specified", async (t) => {
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
@@ -238,97 +253,113 @@ test("getCredentials filters by language when specified", async (t) => {
t.is(credentials[0].type, "maven_repository");
});
test("getCredentials returns all for a language when specified", async (t) => {
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
toEncodedJSON(mixedCredentials),
KnownLanguage.go,
);
t.is(credentials.length, 2);
const credentialsTypes = credentials.map((c) => c.type);
t.assert(credentialsTypes.includes("goproxy_server"));
t.assert(credentialsTypes.includes("git_source"));
});
test("getCredentials returns all credentials when no language specified", async (t) => {
const credentialsInput = toEncodedJSON(mixedCredentials);
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
credentialsInput,
undefined,
);
t.is(credentials.length, mixedCredentials.length);
});
test("getCredentials throws an error when non-printable characters are used", async (t) => {
const invalidCredentials = [
{ type: "nuget_feed", host: "1nuget.pkg.github.com", token: "abc\u0000" }, // Non-printable character in token
{ type: "nuget_feed", host: "2nuget.pkg.github.com\u0001" }, // Non-printable character in host
{
type: "nuget_feed",
host: "3nuget.pkg.github.com",
password: "ghi\u0002",
}, // Non-printable character in password
{ type: "nuget_feed", host: "4nuget.pkg.github.com", password: "ghi\x00" }, // Non-printable character in password
];
for (const invalidCredential of invalidCredentials) {
const credentialsInput = Buffer.from(
JSON.stringify([invalidCredential]),
).toString("base64");
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
credentialsInput,
undefined,
),
{
message:
"Invalid credentials - fields must contain only printable characters",
},
test.serial(
"getCredentials returns all for a language when specified",
async (t) => {
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
toEncodedJSON(mixedCredentials),
KnownLanguage.go,
);
}
});
t.is(credentials.length, 2);
test("getCredentials logs a warning when a PAT is used without a username", async (t) => {
const loggedMessages = [];
const logger = getRecordingLogger(loggedMessages);
const likelyWrongCredentials = toEncodedJSON([
{
type: "git_server",
host: "https://github.com/",
password: `ghp_${makeTestToken()}`,
},
]);
const credentialsTypes = credentials.map((c) => c.type);
t.assert(credentialsTypes.includes("goproxy_server"));
t.assert(credentialsTypes.includes("git_source"));
},
);
const results = startProxyExports.getCredentials(
logger,
undefined,
likelyWrongCredentials,
undefined,
);
test.serial(
"getCredentials returns all credentials when no language specified",
async (t) => {
const credentialsInput = toEncodedJSON(mixedCredentials);
// The configuration should be accepted, despite the likely problem.
t.assert(results);
t.is(results.length, 1);
t.is(results[0].type, "git_server");
t.is(results[0].host, "https://github.com/");
t.assert(results[0].password?.startsWith("ghp_"));
const credentials = startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
credentialsInput,
undefined,
);
t.is(credentials.length, mixedCredentials.length);
},
);
// A warning should have been logged.
checkExpectedLogMessages(t, loggedMessages, [
"using a GitHub Personal Access Token (PAT), but no username was provided",
]);
});
test.serial(
"getCredentials throws an error when non-printable characters are used",
async (t) => {
const invalidCredentials = [
{ type: "nuget_feed", host: "1nuget.pkg.github.com", token: "abc\u0000" }, // Non-printable character in token
{ type: "nuget_feed", host: "2nuget.pkg.github.com\u0001" }, // Non-printable character in host
{
type: "nuget_feed",
host: "3nuget.pkg.github.com",
password: "ghi\u0002",
}, // Non-printable character in password
{
type: "nuget_feed",
host: "4nuget.pkg.github.com",
password: "ghi\x00",
}, // Non-printable character in password
];
test("parseLanguage", async (t) => {
for (const invalidCredential of invalidCredentials) {
const credentialsInput = Buffer.from(
JSON.stringify([invalidCredential]),
).toString("base64");
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
credentialsInput,
undefined,
),
{
message:
"Invalid credentials - fields must contain only printable characters",
},
);
}
},
);
test.serial(
"getCredentials logs a warning when a PAT is used without a username",
async (t) => {
const loggedMessages = [];
const logger = getRecordingLogger(loggedMessages);
const likelyWrongCredentials = toEncodedJSON([
{
type: "git_server",
host: "https://github.com/",
password: `ghp_${makeTestToken()}`,
},
]);
const results = startProxyExports.getCredentials(
logger,
undefined,
likelyWrongCredentials,
undefined,
);
// The configuration should be accepted, despite the likely problem.
t.assert(results);
t.is(results.length, 1);
t.is(results[0].type, "git_server");
t.is(results[0].host, "https://github.com/");
t.assert(results[0].password?.startsWith("ghp_"));
// A warning should have been logged.
checkExpectedLogMessages(t, loggedMessages, [
"using a GitHub Personal Access Token (PAT), but no username was provided",
]);
},
);
test.serial("parseLanguage", async (t) => {
// Exact matches
t.deepEqual(parseLanguage("csharp"), KnownLanguage.csharp);
t.deepEqual(parseLanguage("cpp"), KnownLanguage.cpp);
@@ -391,34 +422,14 @@ function mockOfflineFeatures(tempDir: string, logger: Logger) {
return setUpFeatureFlagTests(tempDir, logger, gitHubVersion);
}
test("getDownloadUrl returns fallback when `getReleaseByVersion` rejects", async (t) => {
const logger = new RecordingLogger();
mockGetReleaseByTag();
test.serial(
"getDownloadUrl returns fallback when `getReleaseByVersion` rejects",
async (t) => {
const logger = new RecordingLogger();
mockGetReleaseByTag();
await withTmpDir(async (tempDir) => {
const features = mockOfflineFeatures(tempDir, logger);
const info = await startProxyExports.getDownloadUrl(
getRunnerLogger(true),
features,
);
t.is(info.version, startProxyExports.UPDATEJOB_PROXY_VERSION);
t.is(
info.url,
startProxyExports.getFallbackUrl(startProxyExports.getProxyPackage()),
);
});
});
test("getDownloadUrl returns fallback when there's no matching release asset", async (t) => {
const logger = new RecordingLogger();
const testAssets = [[], [{ name: "foo" }]];
await withTmpDir(async (tempDir) => {
const features = mockOfflineFeatures(tempDir, logger);
for (const assets of testAssets) {
const stub = mockGetReleaseByTag(assets);
await withTmpDir(async (tempDir) => {
const features = mockOfflineFeatures(tempDir, logger);
const info = await startProxyExports.getDownloadUrl(
getRunnerLogger(true),
features,
@@ -429,13 +440,39 @@ test("getDownloadUrl returns fallback when there's no matching release asset", a
info.url,
startProxyExports.getFallbackUrl(startProxyExports.getProxyPackage()),
);
});
},
);
stub.restore();
}
});
});
test.serial(
"getDownloadUrl returns fallback when there's no matching release asset",
async (t) => {
const logger = new RecordingLogger();
const testAssets = [[], [{ name: "foo" }]];
test("getDownloadUrl returns matching release asset", async (t) => {
await withTmpDir(async (tempDir) => {
const features = mockOfflineFeatures(tempDir, logger);
for (const assets of testAssets) {
const stub = mockGetReleaseByTag(assets);
const info = await startProxyExports.getDownloadUrl(
getRunnerLogger(true),
features,
);
t.is(info.version, startProxyExports.UPDATEJOB_PROXY_VERSION);
t.is(
info.url,
startProxyExports.getFallbackUrl(startProxyExports.getProxyPackage()),
);
stub.restore();
}
});
},
);
test.serial("getDownloadUrl returns matching release asset", async (t) => {
const logger = new RecordingLogger();
const assets = [
{ name: "foo", url: "other-url" },
@@ -455,7 +492,7 @@ test("getDownloadUrl returns matching release asset", async (t) => {
});
});
test("credentialToStr - hides passwords", (t) => {
test.serial("credentialToStr - hides passwords", (t) => {
const secret = "password123";
const credential = {
type: "maven_credential",
@@ -472,7 +509,7 @@ test("credentialToStr - hides passwords", (t) => {
);
});
test("credentialToStr - hides tokens", (t) => {
test.serial("credentialToStr - hides tokens", (t) => {
const secret = "password123";
const credential = {
type: "maven_credential",
@@ -489,29 +526,35 @@ test("credentialToStr - hides tokens", (t) => {
);
});
test("getSafeErrorMessage - returns actual message for `StartProxyError`", (t) => {
const error = new startProxyExports.StartProxyError(
startProxyExports.StartProxyErrorType.DownloadFailed,
);
t.is(
startProxyExports.getSafeErrorMessage(error),
startProxyExports.getStartProxyErrorMessage(error.errorType),
);
});
test("getSafeErrorMessage - does not return message for arbitrary errors", (t) => {
const error = new Error(
startProxyExports.getStartProxyErrorMessage(
test.serial(
"getSafeErrorMessage - returns actual message for `StartProxyError`",
(t) => {
const error = new startProxyExports.StartProxyError(
startProxyExports.StartProxyErrorType.DownloadFailed,
),
);
);
t.is(
startProxyExports.getSafeErrorMessage(error),
startProxyExports.getStartProxyErrorMessage(error.errorType),
);
},
);
const message = startProxyExports.getSafeErrorMessage(error);
test.serial(
"getSafeErrorMessage - does not return message for arbitrary errors",
(t) => {
const error = new Error(
startProxyExports.getStartProxyErrorMessage(
startProxyExports.StartProxyErrorType.DownloadFailed,
),
);
t.not(message, error.message);
t.assert(message.startsWith("Error from start-proxy Action omitted"));
t.assert(message.includes(error.name));
});
const message = startProxyExports.getSafeErrorMessage(error);
t.not(message, error.message);
t.assert(message.startsWith("Error from start-proxy Action omitted"));
t.assert(message.includes(error.name));
},
);
const wrapFailureTest = test.macro({
exec: async (
@@ -530,7 +573,7 @@ const wrapFailureTest = test.macro({
title: (providedTitle) => `${providedTitle} - wraps errors on failure`,
});
test("downloadProxy - returns file path on success", async (t) => {
test.serial("downloadProxy - returns file path on success", async (t) => {
await withRecordingLoggerAsync(async (logger) => {
const testPath = "/some/path";
sinon.stub(toolcache, "downloadTool").resolves(testPath);
@@ -544,7 +587,7 @@ test("downloadProxy - returns file path on success", async (t) => {
});
});
test(
test.serial(
"downloadProxy",
wrapFailureTest,
() => {
@@ -555,7 +598,7 @@ test(
},
);
test("extractProxy - returns file path on success", async (t) => {
test.serial("extractProxy - returns file path on success", async (t) => {
await withRecordingLoggerAsync(async (logger) => {
const testPath = "/some/path";
sinon.stub(toolcache, "extractTar").resolves(testPath);
@@ -565,7 +608,7 @@ test("extractProxy - returns file path on success", async (t) => {
});
});
test(
test.serial(
"extractProxy",
wrapFailureTest,
() => {
@@ -576,7 +619,7 @@ test(
},
);
test("cacheProxy - returns file path on success", async (t) => {
test.serial("cacheProxy - returns file path on success", async (t) => {
await withRecordingLoggerAsync(async (logger) => {
const testPath = "/some/path";
sinon.stub(toolcache, "cacheDir").resolves(testPath);
@@ -591,7 +634,7 @@ test("cacheProxy - returns file path on success", async (t) => {
});
});
test(
test.serial(
"cacheProxy",
wrapFailureTest,
() => {
@@ -602,100 +645,37 @@ test(
},
);
test("getProxyBinaryPath - returns path from tool cache if available", async (t) => {
const logger = new RecordingLogger();
mockGetReleaseByTag();
test.serial(
"getProxyBinaryPath - returns path from tool cache if available",
async (t) => {
const logger = new RecordingLogger();
mockGetReleaseByTag();
await withTmpDir(async (tempDir) => {
const toolcachePath = "/path/to/proxy/dir";
sinon.stub(toolcache, "find").returns(toolcachePath);
await withTmpDir(async (tempDir) => {
const toolcachePath = "/path/to/proxy/dir";
sinon.stub(toolcache, "find").returns(toolcachePath);
const features = mockOfflineFeatures(tempDir, logger);
const path = await startProxyExports.getProxyBinaryPath(logger, features);
const features = mockOfflineFeatures(tempDir, logger);
const path = await startProxyExports.getProxyBinaryPath(logger, features);
t.assert(path);
t.is(
path,
filepath.join(toolcachePath, startProxyExports.getProxyFilename()),
);
});
});
t.assert(path);
t.is(
path,
filepath.join(toolcachePath, startProxyExports.getProxyFilename()),
);
});
},
);
test("getProxyBinaryPath - downloads proxy if not in cache", async (t) => {
const logger = new RecordingLogger();
const downloadUrl = "url-we-want";
mockGetReleaseByTag([
{ name: startProxyExports.getProxyPackage(), url: downloadUrl },
]);
test.serial(
"getProxyBinaryPath - downloads proxy if not in cache",
async (t) => {
const logger = new RecordingLogger();
const downloadUrl = "url-we-want";
mockGetReleaseByTag([
{ name: startProxyExports.getProxyPackage(), url: downloadUrl },
]);
const toolcachePath = "/path/to/proxy/dir";
const find = sinon.stub(toolcache, "find").returns("");
const getApiDetails = sinon.stub(apiClient, "getApiDetails").returns({
auth: "",
url: "",
apiURL: "",
});
const getAuthorizationHeaderFor = sinon
.stub(apiClient, "getAuthorizationHeaderFor")
.returns(undefined);
const archivePath = "/path/to/archive";
const downloadTool = sinon
.stub(toolcache, "downloadTool")
.resolves(archivePath);
const extractedPath = "/path/to/extracted";
const extractTar = sinon
.stub(toolcache, "extractTar")
.resolves(extractedPath);
const cacheDir = sinon.stub(toolcache, "cacheDir").resolves(toolcachePath);
const path = await startProxyExports.getProxyBinaryPath(
logger,
createFeatures([]),
);
t.assert(find.calledOnce);
t.assert(getApiDetails.calledOnce);
t.assert(getAuthorizationHeaderFor.calledOnce);
t.assert(downloadTool.calledOnceWith(downloadUrl));
t.assert(extractTar.calledOnceWith(archivePath));
t.assert(cacheDir.calledOnceWith(extractedPath));
t.assert(path);
t.is(
path,
filepath.join(toolcachePath, startProxyExports.getProxyFilename()),
);
checkExpectedLogMessages(t, logger.messages, [
`Found '${startProxyExports.getProxyPackage()}' in release '${defaults.bundleVersion}' at '${downloadUrl}'`,
]);
});
test("getProxyBinaryPath - downloads proxy based on features if not in cache", async (t) => {
const logger = new RecordingLogger();
const expectedTag = "codeql-bundle-v2.20.1";
const expectedParams = {
owner: "github",
repo: "codeql-action",
tag: expectedTag,
};
const downloadUrl = "url-we-want";
const assets = [
{
name: startProxyExports.getProxyPackage(),
url: downloadUrl,
},
];
const getReleaseByTag = sinon.stub();
getReleaseByTag.withArgs(sinon.match(expectedParams)).resolves({
status: 200,
data: { assets },
headers: {},
url: "GET /repos/:owner/:repo/releases/tags/:tag",
});
mockGetApiClient({ repos: { getReleaseByTag } });
await withTmpDir(async (tempDir) => {
const toolcachePath = "/path/to/proxy/dir";
const find = sinon.stub(toolcache, "find").returns("");
const getApiDetails = sinon.stub(apiClient, "getApiDetails").returns({
@@ -716,40 +696,114 @@ test("getProxyBinaryPath - downloads proxy based on features if not in cache", a
.resolves(extractedPath);
const cacheDir = sinon.stub(toolcache, "cacheDir").resolves(toolcachePath);
const gitHubVersion: GitHubVersion = {
type: GitHubVariant.DOTCOM,
};
sinon.stub(apiClient, "getGitHubVersion").resolves(gitHubVersion);
const features = setUpFeatureFlagTests(tempDir, logger, gitHubVersion);
sinon.stub(features, "getValue").callsFake(async (_feature, _codeql) => {
return true;
});
const getDefaultCliVersion = sinon
.stub(features, "getDefaultCliVersion")
.resolves({ cliVersion: "2.20.1", tagName: expectedTag });
const path = await startProxyExports.getProxyBinaryPath(logger, features);
t.assert(getDefaultCliVersion.calledOnce);
sinon.assert.calledOnceWithMatch(
getReleaseByTag,
sinon.match(expectedParams),
const path = await startProxyExports.getProxyBinaryPath(
logger,
createFeatures([]),
);
t.assert(find.calledOnce);
t.assert(getApiDetails.calledOnce);
t.assert(getAuthorizationHeaderFor.calledOnce);
t.assert(downloadTool.calledOnceWith(downloadUrl));
t.assert(extractTar.calledOnceWith(archivePath));
t.assert(cacheDir.calledOnceWith(extractedPath));
t.assert(path);
t.is(
path,
filepath.join(toolcachePath, startProxyExports.getProxyFilename()),
);
});
checkExpectedLogMessages(t, logger.messages, [
`Found '${startProxyExports.getProxyPackage()}' in release '${expectedTag}' at '${downloadUrl}'`,
]);
});
checkExpectedLogMessages(t, logger.messages, [
`Found '${startProxyExports.getProxyPackage()}' in release '${defaults.bundleVersion}' at '${downloadUrl}'`,
]);
},
);
test.serial(
"getProxyBinaryPath - downloads proxy based on features if not in cache",
async (t) => {
const logger = new RecordingLogger();
const expectedTag = "codeql-bundle-v2.20.1";
const expectedParams = {
owner: "github",
repo: "codeql-action",
tag: expectedTag,
};
const downloadUrl = "url-we-want";
const assets = [
{
name: startProxyExports.getProxyPackage(),
url: downloadUrl,
},
];
const getReleaseByTag = sinon.stub();
getReleaseByTag.withArgs(sinon.match(expectedParams)).resolves({
status: 200,
data: { assets },
headers: {},
url: "GET /repos/:owner/:repo/releases/tags/:tag",
});
mockGetApiClient({ repos: { getReleaseByTag } });
await withTmpDir(async (tempDir) => {
const toolcachePath = "/path/to/proxy/dir";
const find = sinon.stub(toolcache, "find").returns("");
const getApiDetails = sinon.stub(apiClient, "getApiDetails").returns({
auth: "",
url: "",
apiURL: "",
});
const getAuthorizationHeaderFor = sinon
.stub(apiClient, "getAuthorizationHeaderFor")
.returns(undefined);
const archivePath = "/path/to/archive";
const downloadTool = sinon
.stub(toolcache, "downloadTool")
.resolves(archivePath);
const extractedPath = "/path/to/extracted";
const extractTar = sinon
.stub(toolcache, "extractTar")
.resolves(extractedPath);
const cacheDir = sinon
.stub(toolcache, "cacheDir")
.resolves(toolcachePath);
const gitHubVersion: GitHubVersion = {
type: GitHubVariant.DOTCOM,
};
sinon.stub(apiClient, "getGitHubVersion").resolves(gitHubVersion);
const features = setUpFeatureFlagTests(tempDir, logger, gitHubVersion);
sinon.stub(features, "getValue").callsFake(async (_feature, _codeql) => {
return true;
});
const getDefaultCliVersion = sinon
.stub(features, "getDefaultCliVersion")
.resolves({ cliVersion: "2.20.1", tagName: expectedTag });
const path = await startProxyExports.getProxyBinaryPath(logger, features);
t.assert(getDefaultCliVersion.calledOnce);
sinon.assert.calledOnceWithMatch(
getReleaseByTag,
sinon.match(expectedParams),
);
t.assert(find.calledOnce);
t.assert(getApiDetails.calledOnce);
t.assert(getAuthorizationHeaderFor.calledOnce);
t.assert(downloadTool.calledOnceWith(downloadUrl));
t.assert(extractTar.calledOnceWith(archivePath));
t.assert(cacheDir.calledOnceWith(extractedPath));
t.assert(path);
t.is(
path,
filepath.join(toolcachePath, startProxyExports.getProxyFilename()),
);
});
checkExpectedLogMessages(t, logger.messages, [
`Found '${startProxyExports.getProxyPackage()}' in release '${expectedTag}' at '${downloadUrl}'`,
]);
},
);