Add unit test for cleanup

This commit is contained in:
Henry Mercer 2024-05-23 16:15:21 +01:00
parent 6ccd5631d8
commit f7f71927cf
6 changed files with 158 additions and 10 deletions

6
lib/trap-caching.js generated
View file

@ -146,9 +146,10 @@ async function cleanupTrapCaches(config, features, logger) {
} }
try { try {
let totalBytesCleanedUp = 0; let totalBytesCleanedUp = 0;
const allCaches = await apiClient.listActionsCaches(CODEQL_TRAP_CACHE_PREFIX, await actionsUtil.getRef());
for (const language of config.languages) { for (const language of config.languages) {
if (config.trapCaches[language]) { if (config.trapCaches[language]) {
const cachesToRemove = await getTrapCachesForLanguage(language, logger); const cachesToRemove = await getTrapCachesForLanguage(allCaches, language, logger);
// Dates returned by the API are in ISO 8601 format, so we can sort them lexicographically // Dates returned by the API are in ISO 8601 format, so we can sort them lexicographically
cachesToRemove.sort((a, b) => a.created_at.localeCompare(b.created_at)); cachesToRemove.sort((a, b) => a.created_at.localeCompare(b.created_at));
// Keep the most recent cache // Keep the most recent cache
@ -179,9 +180,8 @@ async function cleanupTrapCaches(config, features, logger) {
} }
} }
exports.cleanupTrapCaches = cleanupTrapCaches; exports.cleanupTrapCaches = cleanupTrapCaches;
async function getTrapCachesForLanguage(language, logger) { async function getTrapCachesForLanguage(allCaches, language, logger) {
logger.debug(`Listing TRAP caches for ${language}`); logger.debug(`Listing TRAP caches for ${language}`);
const allCaches = await apiClient.listActionsCaches(CODEQL_TRAP_CACHE_PREFIX, await actionsUtil.getRef());
for (const cache of allCaches) { for (const cache of allCaches) {
if (!cache.created_at || !cache.id || !cache.key || !cache.size_in_bytes) { if (!cache.created_at || !cache.id || !cache.key || !cache.size_in_bytes) {
throw new Error("An unexpected cache item was returned from the API that was missing one or " + throw new Error("An unexpected cache item was returned from the API that was missing one or " +

File diff suppressed because one or more lines are too long

View file

@ -32,8 +32,11 @@ const cache = __importStar(require("@actions/cache"));
const ava_1 = __importDefault(require("ava")); const ava_1 = __importDefault(require("ava"));
const sinon = __importStar(require("sinon")); const sinon = __importStar(require("sinon"));
const actionsUtil = __importStar(require("./actions-util")); const actionsUtil = __importStar(require("./actions-util"));
const apiClient = __importStar(require("./api-client"));
const codeql_1 = require("./codeql"); const codeql_1 = require("./codeql");
const feature_flags_1 = require("./feature-flags");
const languages_1 = require("./languages"); const languages_1 = require("./languages");
const logging_1 = require("./logging");
const testing_utils_1 = require("./testing-utils"); const testing_utils_1 = require("./testing-utils");
const trap_caching_1 = require("./trap-caching"); const trap_caching_1 = require("./trap-caching");
const util = __importStar(require("./util")); const util = __importStar(require("./util"));
@ -168,4 +171,65 @@ function getTestConfigWithTempDir(tempDir) {
t.assert(fs.existsSync(path.resolve(tmpDir, "trapCaches", "javascript"))); t.assert(fs.existsSync(path.resolve(tmpDir, "trapCaches", "javascript")));
}); });
}); });
(0, ava_1.default)("cleanup removes only old CodeQL TRAP caches", async (t) => {
await util.withTmpDir(async (tmpDir) => {
const config = getTestConfigWithTempDir(tmpDir);
sinon.stub(actionsUtil, "getRef").resolves("refs/heads/main");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
const listStub = sinon.stub(apiClient, "listActionsCaches").resolves([
{
id: 1,
key: "some-other-key",
created_at: "2024-05-23T14:25:00Z",
size_in_bytes: 100 * 1024 * 1024,
},
{
id: 2,
key: "codeql-trap-1-2.0.0-javascript-newest",
created_at: "2024-04-23T14:25:00Z",
size_in_bytes: 50 * 1024 * 1024,
},
{
id: 3,
key: "codeql-trap-1-2.0.0-javascript-older",
created_at: "2024-03-22T14:25:00Z",
size_in_bytes: 200 * 1024 * 1024,
},
{
id: 4,
key: "codeql-trap-1-2.0.0-javascript-oldest",
created_at: "2024-02-21T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
{
id: 5,
key: "codeql-trap-1-2.0.0-ruby-newest",
created_at: "2024-02-20T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
{
id: 6,
key: "codeql-trap-1-2.0.0-swift-newest",
created_at: "2024-02-22T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
{
id: 7,
key: "codeql-trap-1-2.0.0-swift-older",
created_at: "2024-02-21T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
]);
const deleteStub = sinon.stub(apiClient, "deleteActionsCache").resolves();
const statusReport = await (0, trap_caching_1.cleanupTrapCaches)(config, (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CleanupTrapCaches]), (0, logging_1.getRunnerLogger)(true));
t.is(listStub.callCount, 1);
t.assert(listStub.calledWithExactly("codeql-trap", "refs/heads/main"));
t.deepEqual(statusReport, {
trap_cache_cleanup_size_bytes: 500 * 1024 * 1024,
});
t.is(deleteStub.callCount, 2);
t.assert(deleteStub.calledWithExactly(3));
t.assert(deleteStub.calledWithExactly(4));
});
});
//# sourceMappingURL=trap-caching.test.js.map //# sourceMappingURL=trap-caching.test.js.map

File diff suppressed because one or more lines are too long

View file

@ -6,20 +6,25 @@ import test from "ava";
import * as sinon from "sinon"; import * as sinon from "sinon";
import * as actionsUtil from "./actions-util"; import * as actionsUtil from "./actions-util";
import * as apiClient from "./api-client";
import { import {
setCodeQL, setCodeQL,
getTrapCachingExtractorConfigArgs, getTrapCachingExtractorConfigArgs,
getTrapCachingExtractorConfigArgsForLang, getTrapCachingExtractorConfigArgsForLang,
} from "./codeql"; } from "./codeql";
import * as configUtils from "./config-utils"; import * as configUtils from "./config-utils";
import { Feature } from "./feature-flags";
import { Language } from "./languages"; import { Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { import {
createFeatures,
createTestConfig, createTestConfig,
getRecordingLogger, getRecordingLogger,
makeVersionInfo, makeVersionInfo,
setupTests, setupTests,
} from "./testing-utils"; } from "./testing-utils";
import { import {
cleanupTrapCaches,
downloadTrapCaches, downloadTrapCaches,
getLanguagesSupportingCaching, getLanguagesSupportingCaching,
uploadTrapCaches, uploadTrapCaches,
@ -189,3 +194,75 @@ test("download cache looks for the right key and creates dir", async (t) => {
t.assert(fs.existsSync(path.resolve(tmpDir, "trapCaches", "javascript"))); t.assert(fs.existsSync(path.resolve(tmpDir, "trapCaches", "javascript")));
}); });
}); });
test("cleanup removes only old CodeQL TRAP caches", async (t) => {
await util.withTmpDir(async (tmpDir) => {
const config = getTestConfigWithTempDir(tmpDir);
sinon.stub(actionsUtil, "getRef").resolves("refs/heads/main");
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
const listStub = sinon.stub(apiClient, "listActionsCaches").resolves([
{
id: 1,
key: "some-other-key",
created_at: "2024-05-23T14:25:00Z",
size_in_bytes: 100 * 1024 * 1024,
},
{
id: 2,
key: "codeql-trap-1-2.0.0-javascript-newest",
created_at: "2024-04-23T14:25:00Z",
size_in_bytes: 50 * 1024 * 1024,
},
{
id: 3,
key: "codeql-trap-1-2.0.0-javascript-older",
created_at: "2024-03-22T14:25:00Z",
size_in_bytes: 200 * 1024 * 1024,
},
{
id: 4,
key: "codeql-trap-1-2.0.0-javascript-oldest",
created_at: "2024-02-21T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
{
id: 5,
key: "codeql-trap-1-2.0.0-ruby-newest",
created_at: "2024-02-20T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
{
id: 6,
key: "codeql-trap-1-2.0.0-swift-newest",
created_at: "2024-02-22T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
{
id: 7,
key: "codeql-trap-1-2.0.0-swift-older",
created_at: "2024-02-21T14:25:00Z",
size_in_bytes: 300 * 1024 * 1024,
},
]);
const deleteStub = sinon.stub(apiClient, "deleteActionsCache").resolves();
const statusReport = await cleanupTrapCaches(
config,
createFeatures([Feature.CleanupTrapCaches]),
getRunnerLogger(true),
);
t.is(listStub.callCount, 1);
t.assert(listStub.calledWithExactly("codeql-trap", "refs/heads/main"));
t.deepEqual(statusReport, {
trap_cache_cleanup_size_bytes: 500 * 1024 * 1024,
});
t.is(deleteStub.callCount, 2);
t.assert(deleteStub.calledWithExactly(3));
t.assert(deleteStub.calledWithExactly(4));
});
});

View file

@ -186,9 +186,19 @@ export async function cleanupTrapCaches(
try { try {
let totalBytesCleanedUp = 0; let totalBytesCleanedUp = 0;
const allCaches = await apiClient.listActionsCaches(
CODEQL_TRAP_CACHE_PREFIX,
await actionsUtil.getRef(),
);
for (const language of config.languages) { for (const language of config.languages) {
if (config.trapCaches[language]) { if (config.trapCaches[language]) {
const cachesToRemove = await getTrapCachesForLanguage(language, logger); const cachesToRemove = await getTrapCachesForLanguage(
allCaches,
language,
logger,
);
// Dates returned by the API are in ISO 8601 format, so we can sort them lexicographically // Dates returned by the API are in ISO 8601 format, so we can sort them lexicographically
cachesToRemove.sort((a, b) => a.created_at.localeCompare(b.created_at)); cachesToRemove.sort((a, b) => a.created_at.localeCompare(b.created_at));
// Keep the most recent cache // Keep the most recent cache
@ -227,14 +237,11 @@ export async function cleanupTrapCaches(
} }
async function getTrapCachesForLanguage( async function getTrapCachesForLanguage(
allCaches: apiClient.ActionsCacheItem[],
language: Language, language: Language,
logger: Logger, logger: Logger,
): Promise<Array<Required<apiClient.ActionsCacheItem>>> { ): Promise<Array<Required<apiClient.ActionsCacheItem>>> {
logger.debug(`Listing TRAP caches for ${language}`); logger.debug(`Listing TRAP caches for ${language}`);
const allCaches = await apiClient.listActionsCaches(
CODEQL_TRAP_CACHE_PREFIX,
await actionsUtil.getRef(),
);
for (const cache of allCaches) { for (const cache of allCaches) {
if (!cache.created_at || !cache.id || !cache.key || !cache.size_in_bytes) { if (!cache.created_at || !cache.id || !cache.key || !cache.size_in_bytes) {