mirror of https://github.com/actions/cache.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
4.5 KiB
TypeScript
167 lines
4.5 KiB
TypeScript
import * as cache from "@actions/cache";
|
|
import { Storage } from "@google-cloud/storage";
|
|
|
|
import * as actionUtils from "../src/utils/actionUtils";
|
|
import { restoreCache } from "../src/utils/gcsCache";
|
|
|
|
jest.mock("@actions/cache");
|
|
jest.mock("@google-cloud/storage");
|
|
jest.mock("../src/utils/actionUtils");
|
|
jest.mock("@actions/cache/lib/internal/cacheUtils", () => ({
|
|
getCompressionMethod: jest.fn().mockResolvedValue("zstd"),
|
|
getCacheFileName: jest.fn().mockReturnValue("cache.tzst"),
|
|
createTempDirectory: jest.fn().mockResolvedValue("/tmp/gcs-cache-test"),
|
|
getArchiveFileSizeInBytes: jest.fn().mockReturnValue(1024),
|
|
unlinkFile: jest.fn().mockResolvedValue(undefined),
|
|
resolvePaths: jest.fn().mockResolvedValue(["some/path"])
|
|
}));
|
|
jest.mock("@actions/cache/lib/internal/tar", () => ({
|
|
createTar: jest.fn(),
|
|
extractTar: jest.fn(),
|
|
listTar: jest.fn()
|
|
}));
|
|
|
|
const BUCKET = "test-bucket";
|
|
const PREFIX = "github-cache";
|
|
|
|
interface FakeObject {
|
|
name: string;
|
|
updated: string;
|
|
}
|
|
|
|
function mockStorage(objects: FakeObject[]): void {
|
|
const bucketApi = {
|
|
file: (path: string) => ({
|
|
exists: jest
|
|
.fn()
|
|
.mockResolvedValue([objects.some(o => o.name === path)]),
|
|
download: jest.fn().mockResolvedValue(undefined)
|
|
}),
|
|
getFiles: jest.fn(({ prefix }: { prefix: string }) => [
|
|
objects
|
|
.filter(o => o.name.startsWith(prefix))
|
|
.map(o => ({
|
|
name: o.name,
|
|
metadata: { updated: o.updated }
|
|
}))
|
|
])
|
|
};
|
|
(Storage as unknown as jest.Mock).mockImplementation(() => ({
|
|
bucket: () => bucketApi
|
|
}));
|
|
}
|
|
|
|
beforeEach(() => {
|
|
jest.mocked(actionUtils.isGCSAvailable).mockReturnValue(true);
|
|
jest.mocked(actionUtils.getGCSBucket).mockReturnValue(BUCKET);
|
|
jest.mocked(cache.restoreCache).mockResolvedValue(undefined);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
test("primary key exact match returns primary key", async () => {
|
|
mockStorage([
|
|
{
|
|
name: `${PREFIX}/nx-abc123.cache.tzst`,
|
|
updated: "2026-07-01T00:00:00Z"
|
|
}
|
|
]);
|
|
|
|
const result = await restoreCache(["some/path"], "nx-abc123", ["nx-"], {
|
|
lookupOnly: true
|
|
});
|
|
|
|
expect(result).toBe("nx-abc123");
|
|
});
|
|
|
|
test("restore key prefix-matches and returns newest entry's key", async () => {
|
|
mockStorage([
|
|
{
|
|
name: `${PREFIX}/nx-older00.cache.tzst`,
|
|
updated: "2026-07-01T00:00:00Z"
|
|
},
|
|
{
|
|
name: `${PREFIX}/nx-newer00.cache.tzst`,
|
|
updated: "2026-07-20T00:00:00Z"
|
|
}
|
|
]);
|
|
|
|
const result = await restoreCache(["some/path"], "nx-abc123", ["nx-"], {
|
|
lookupOnly: true
|
|
});
|
|
|
|
expect(result).toBe("nx-newer00");
|
|
});
|
|
|
|
test("restore key ignores objects with other compression suffix", async () => {
|
|
mockStorage([
|
|
{
|
|
name: `${PREFIX}/nx-gzipped0.cache.tgz`,
|
|
updated: "2026-07-20T00:00:00Z"
|
|
}
|
|
]);
|
|
|
|
const result = await restoreCache(["some/path"], "nx-abc123", ["nx-"], {
|
|
lookupOnly: true
|
|
});
|
|
|
|
expect(result).toBeUndefined();
|
|
expect(cache.restoreCache).toHaveBeenCalled();
|
|
});
|
|
|
|
test("restore keys are tried in order", async () => {
|
|
mockStorage([
|
|
{
|
|
name: `${PREFIX}/fallback-key.cache.tzst`,
|
|
updated: "2026-07-01T00:00:00Z"
|
|
},
|
|
{
|
|
name: `${PREFIX}/preferred-key.cache.tzst`,
|
|
updated: "2026-06-01T00:00:00Z"
|
|
}
|
|
]);
|
|
|
|
const result = await restoreCache(
|
|
["some/path"],
|
|
"nx-abc123",
|
|
["preferred-", "fallback-"],
|
|
{ lookupOnly: true }
|
|
);
|
|
|
|
expect(result).toBe("preferred-key");
|
|
});
|
|
|
|
test("no match falls back to GitHub cache", async () => {
|
|
mockStorage([]);
|
|
|
|
const result = await restoreCache(["some/path"], "nx-abc123", ["nx-"], {
|
|
lookupOnly: true
|
|
});
|
|
|
|
expect(result).toBeUndefined();
|
|
expect(cache.restoreCache).toHaveBeenCalledWith(
|
|
["some/path"],
|
|
"nx-abc123",
|
|
["nx-"],
|
|
{ lookupOnly: true },
|
|
undefined
|
|
);
|
|
});
|
|
|
|
test("keys containing slashes resolve to the full matched key", async () => {
|
|
mockStorage([
|
|
{
|
|
name: `${PREFIX}/develop/nx-abc.cache.tzst`,
|
|
updated: "2026-07-01T00:00:00Z"
|
|
}
|
|
]);
|
|
|
|
const result = await restoreCache(["some/path"], "develop/nx-xyz", [
|
|
"develop/"
|
|
]);
|
|
|
|
expect(result).toBe("develop/nx-abc");
|
|
});
|