3
0
Fork 0
mirror of https://code.forgejo.org/actions/cache.git synced 2026-02-19 09:04:25 +00:00

add compression-level inputs

This commit is contained in:
StephenHodgson 2025-12-13 16:00:25 -05:00
parent 9255dc7a25
commit 6018dbe2dc
15 changed files with 916 additions and 583 deletions

View file

@ -1,5 +1,6 @@
import * as cache from "@actions/cache";
import * as core from "@actions/core";
import * as zlib from "zlib";
import { Events, RefKey } from "../src/constants";
import * as actionUtils from "../src/utils/actionUtils";
@ -24,6 +25,11 @@ beforeEach(() => {
delete process.env[RefKey];
});
afterEach(() => {
delete process.env["ZSTD_CLEVEL"];
delete process.env["GZIP"];
});
afterAll(() => {
process.env = pristineEnv;
});
@ -177,6 +183,51 @@ test("getInputAsInt returns undefined if input is invalid or NaN", () => {
expect(actionUtils.getInputAsInt("foo")).toBeUndefined();
});
test("getCompressionLevel returns undefined if input not set", () => {
expect(actionUtils.getCompressionLevel("undefined")).toBeUndefined();
});
test("getCompressionLevel returns value if input is valid", () => {
testUtils.setInput("foo", "9");
expect(actionUtils.getCompressionLevel("foo")).toBe(9);
});
test("getCompressionLevel allows zero for no compression", () => {
testUtils.setInput("foo", "0");
expect(actionUtils.getCompressionLevel("foo")).toBe(0);
});
test("getCompressionLevel returns undefined and warns if input is too large", () => {
const infoMock = jest.spyOn(core, "info");
testUtils.setInput("foo", "11");
expect(actionUtils.getCompressionLevel("foo")).toBeUndefined();
expect(infoMock).toHaveBeenCalledWith(
"[warning]Invalid compression-level provided: 11. Expected a value between 0 (no compression) and 9 (maximum compression)."
);
});
test("setCompressionLevel sets compression env vars", () => {
actionUtils.setCompressionLevel(7);
expect(process.env["ZSTD_CLEVEL"]).toBe("7");
expect(process.env["GZIP"]).toBe("-7");
});
test("setCompressionLevel sets no-compression flag when zero", () => {
actionUtils.setCompressionLevel(0);
expect(process.env["ZSTD_CLEVEL"]).toBe("0");
expect(process.env["GZIP"]).toBe("-0");
});
test("higher compression level produces smaller gzip output", () => {
const data = Buffer.alloc(8 * 1024, "A");
const level0 = zlib.gzipSync(data, { level: 0 });
const level9 = zlib.gzipSync(data, { level: 9 });
expect(level0.byteLength).toBeGreaterThan(level9.byteLength);
expect(level0.byteLength - level9.byteLength).toBeGreaterThan(1000);
});
test("getInputAsInt throws if required and value missing", () => {
expect(() =>
actionUtils.getInputAsInt("undefined", { required: true })

View file

@ -43,6 +43,22 @@ beforeAll(() => {
}
);
jest.spyOn(actionUtils, "getCompressionLevel").mockImplementation(
(name, options) => {
return jest
.requireActual("../src/utils/actionUtils")
.getCompressionLevel(name, options);
}
);
jest.spyOn(actionUtils, "setCompressionLevel").mockImplementation(
compressionLevel => {
return jest
.requireActual("../src/utils/actionUtils")
.setCompressionLevel(compressionLevel);
}
);
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
(key, cacheResult) => {
return jest
@ -71,6 +87,8 @@ afterEach(() => {
testUtils.clearInputs();
delete process.env[Events.Key];
delete process.env[RefKey];
delete process.env["ZSTD_CLEVEL"];
delete process.env["GZIP"];
});
test("save with valid inputs uploads a cache", async () => {
@ -92,6 +110,7 @@ test("save with valid inputs uploads a cache", async () => {
const inputPath = "node_modules";
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
testUtils.setInput(Inputs.CompressionLevel, "8");
const cacheId = 4;
const saveCacheMock = jest
@ -102,6 +121,9 @@ test("save with valid inputs uploads a cache", async () => {
await saveRun();
expect(process.env["ZSTD_CLEVEL"]).toBe("8");
expect(process.env["GZIP"]).toBe("-8");
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],

View file

@ -40,6 +40,22 @@ beforeAll(() => {
}
);
jest.spyOn(actionUtils, "getCompressionLevel").mockImplementation(
(name, options) => {
return jest
.requireActual("../src/utils/actionUtils")
.getCompressionLevel(name, options);
}
);
jest.spyOn(actionUtils, "setCompressionLevel").mockImplementation(
compressionLevel => {
return jest
.requireActual("../src/utils/actionUtils")
.setCompressionLevel(compressionLevel);
}
);
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
(key, cacheResult) => {
return jest
@ -69,6 +85,8 @@ afterEach(() => {
testUtils.clearInputs();
delete process.env[Events.Key];
delete process.env[RefKey];
delete process.env["ZSTD_CLEVEL"];
delete process.env["GZIP"];
});
test("save with invalid event outputs warning", async () => {
@ -406,3 +424,97 @@ test("save with valid inputs uploads a cache", async () => {
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("save applies compression level when provided", async () => {
const failedMock = jest.spyOn(core, "setFailed");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
// Cache Entry State
.mockImplementationOnce(() => {
return savedCacheKey;
})
// Cache Key State
.mockImplementationOnce(() => {
return primaryKey;
});
const inputPath = "node_modules";
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
testUtils.setInput(Inputs.CompressionLevel, "9");
const cacheId = 4;
const saveCacheMock = jest
.spyOn(cache, "saveCache")
.mockImplementationOnce(() => {
return Promise.resolve(cacheId);
});
await saveImpl(new StateProvider());
expect(process.env["ZSTD_CLEVEL"]).toBe("9");
expect(process.env["GZIP"]).toBe("-9");
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],
primaryKey,
{
uploadChunkSize: 4000000
},
false
);
expect(failedMock).toHaveBeenCalledTimes(0);
});
test("save skips setting compression when value is out of range", async () => {
const failedMock = jest.spyOn(core, "setFailed");
const setCompressionLevelMock = jest.spyOn(actionUtils, "setCompressionLevel");
const primaryKey = "Linux-node-bb828da54c148048dd17899ba9fda624811cfb43";
const savedCacheKey = "Linux-node-";
jest.spyOn(core, "getState")
// Cache Entry State
.mockImplementationOnce(() => {
return savedCacheKey;
})
// Cache Key State
.mockImplementationOnce(() => {
return primaryKey;
});
const inputPath = "node_modules";
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
testUtils.setInput(Inputs.CompressionLevel, "99");
const cacheId = 4;
const saveCacheMock = jest
.spyOn(cache, "saveCache")
.mockImplementationOnce(() => {
return Promise.resolve(cacheId);
});
await saveImpl(new StateProvider());
expect(process.env["ZSTD_CLEVEL"]).toBeUndefined();
expect(process.env["GZIP"]).toBeUndefined();
expect(setCompressionLevelMock).not.toHaveBeenCalled();
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],
primaryKey,
{
uploadChunkSize: 4000000
},
false
);
expect(failedMock).toHaveBeenCalledTimes(0);
});

View file

@ -43,6 +43,22 @@ beforeAll(() => {
}
);
jest.spyOn(actionUtils, "getCompressionLevel").mockImplementation(
(name, options) => {
return jest
.requireActual("../src/utils/actionUtils")
.getCompressionLevel(name, options);
}
);
jest.spyOn(actionUtils, "setCompressionLevel").mockImplementation(
compressionLevel => {
return jest
.requireActual("../src/utils/actionUtils")
.setCompressionLevel(compressionLevel);
}
);
jest.spyOn(actionUtils, "isExactKeyMatch").mockImplementation(
(key, cacheResult) => {
return jest
@ -71,6 +87,8 @@ afterEach(() => {
testUtils.clearInputs();
delete process.env[Events.Key];
delete process.env[RefKey];
delete process.env["ZSTD_CLEVEL"];
delete process.env["GZIP"];
});
test("save with valid inputs uploads a cache", async () => {
@ -82,6 +100,7 @@ test("save with valid inputs uploads a cache", async () => {
testUtils.setInput(Inputs.Key, primaryKey);
testUtils.setInput(Inputs.Path, inputPath);
testUtils.setInput(Inputs.UploadChunkSize, "4000000");
testUtils.setInput(Inputs.CompressionLevel, "0");
const cacheId = 4;
const saveCacheMock = jest
@ -92,6 +111,9 @@ test("save with valid inputs uploads a cache", async () => {
await saveOnlyRun();
expect(process.env["ZSTD_CLEVEL"]).toBe("0");
expect(process.env["GZIP"]).toBe("-0");
expect(saveCacheMock).toHaveBeenCalledTimes(1);
expect(saveCacheMock).toHaveBeenCalledWith(
[inputPath],