svrjs-cache-mod/tests/index.test.js

219 lines
6.3 KiB
JavaScript
Raw Permalink Normal View History

2024-12-15 19:21:25 +01:00
const mod = require("../src/index.js");
const {
parseCacheControl,
parseVary,
shouldCacheResponse,
isCacheValid
} = require("../src/utils/cacheControlUtils.js");
jest.mock("../src/utils/cacheControlUtils.js", () => ({
parseCacheControl: jest.fn(),
parseVary: jest.fn(),
shouldCacheResponse: jest.fn(),
isCacheValid: jest.fn()
}));
describe("SVR.JS Cache mod", () => {
let req, res, logFacilities, config, next;
2024-12-15 19:21:25 +01:00
beforeEach(() => {
req = {
method: "GET",
headers: {},
url: "/test",
socket: { encrypted: false }
};
res = {
headers: {},
writeHead: jest.fn(),
write: jest.fn(),
end: jest.fn(),
2024-12-15 19:21:25 +01:00
setHeader: jest.fn(),
getHeaderNames: jest.fn(() => []),
getHeaders: jest.fn(() => ({})),
removeHeader: jest.fn(),
on: jest.fn()
};
logFacilities = { resmessage: jest.fn() };
config = {
cacheVaryHeaders: ["accept"],
2024-12-24 12:49:12 +01:00
cacheIgnoreHeaders: [],
2024-12-15 19:21:25 +01:00
maximumCachedResponseSize: 1024
};
next = jest.fn();
});
afterEach(() => {
jest.clearAllMocks();
});
test("should bypass caching for non-GET requests", () => {
req.method = "POST";
mod(req, res, logFacilities, config, next);
expect(res.setHeader).toHaveBeenCalledWith("X-SVRJS-Cache", "BYPASS");
expect(next).toHaveBeenCalled();
});
test("should bypass caching if Cache-Control contains no-store", () => {
req.headers["cache-control"] = "no-store";
parseCacheControl.mockReturnValue({ "no-store": true });
mod(req, res, logFacilities, config, next);
expect(res.setHeader).toHaveBeenCalledWith("X-SVRJS-Cache", "BYPASS");
expect(next).toHaveBeenCalled();
});
test("should cache the response and serve it on subsequent requests", () => {
req.headers.host = "test.com";
req.headers.accept = "application/json";
parseCacheControl.mockReturnValue({});
parseVary.mockReturnValue(["accept"]);
shouldCacheResponse.mockReturnValue(true);
// Mock cache-control headers
res.getHeaders.mockReturnValue({ "cache-control": "max-age=300" });
// First request: cache the response
mod(req, res, logFacilities, config, next);
// Simulate the first response
res.writeHead(200, { "content-type": "application/json" });
res.end("cached response body");
// Assertions for the first request
expect(next).toHaveBeenCalled(); // Proceed to next middleware during first request
// Reset mocks for the second invocation
jest.clearAllMocks();
next.mockReset();
res.setHeader = jest.fn();
res.removeHeader = jest.fn();
res.writeHead = jest.fn();
res.write = jest.fn();
res.end = jest.fn();
2024-12-15 19:21:25 +01:00
// Second request: retrieve from cache
parseCacheControl.mockReturnValue({});
isCacheValid.mockReturnValue(true); // Simulate a valid cache entry
mod(req, res, logFacilities, config, next);
// Assertions for the second request
expect(logFacilities.resmessage).toHaveBeenCalledWith(
"The response is cached."
);
expect(res.setHeader).toHaveBeenCalledWith("X-SVRJS-Cache", "HIT");
expect(res.writeHead).toHaveBeenCalledWith(200, {
2024-12-15 19:21:25 +01:00
"cache-control": "max-age=300",
"content-type": "application/json"
});
expect(res.end).toHaveBeenCalledWith(
Buffer.from("cached response body", "latin1")
2024-12-15 19:21:25 +01:00
);
expect(next).not.toHaveBeenCalled(); // No middleware should be called
});
2024-12-24 12:49:12 +01:00
test("should cache the response and serve it on subsequent requests, while ignoring some headers", () => {
req.headers.host = "ignore.test.com";
req.headers.accept = "application/json";
// Headers to ignore
config.cacheIgnoreHeaders = ["x-header-ignored"];
parseCacheControl.mockReturnValue({});
parseVary.mockReturnValue(["accept"]);
shouldCacheResponse.mockReturnValue(true);
// Mock cache-control headers
res.getHeaders.mockReturnValue({ "cache-control": "max-age=300" });
// First request: cache the response
mod(req, res, logFacilities, config, next);
// Simulate the first response
res.writeHead(200, {
"content-type": "application/json",
"x-header-ignored": "no"
});
res.end("cached response body");
// Assertions for the first request
expect(next).toHaveBeenCalled(); // Proceed to next middleware during first request
// Reset mocks for the second invocation
jest.clearAllMocks();
next.mockReset();
res.setHeader = jest.fn();
res.removeHeader = jest.fn();
res.writeHead = jest.fn();
res.write = jest.fn();
res.end = jest.fn();
// Second request: retrieve from cache
parseCacheControl.mockReturnValue({});
isCacheValid.mockReturnValue(true); // Simulate a valid cache entry
mod(req, res, logFacilities, config, next);
// Assertions for the second request
expect(logFacilities.resmessage).toHaveBeenCalledWith(
"The response is cached."
);
expect(res.setHeader).toHaveBeenCalledWith("X-SVRJS-Cache", "HIT");
expect(res.writeHead).toHaveBeenCalledWith(200, {
"cache-control": "max-age=300",
"content-type": "application/json"
});
expect(res.end).toHaveBeenCalledWith(
Buffer.from("cached response body", "latin1")
);
expect(next).not.toHaveBeenCalled(); // No middleware should be called
});
2024-12-15 19:21:25 +01:00
test("should validate config values correctly", () => {
const validConfig = {
cacheVaryHeaders: ["accept", "user-agent"],
2024-12-24 12:49:12 +01:00
cacheIgnoreHeaders: ["set-cookie"],
2024-12-15 19:21:25 +01:00
maximumCachedResponseSize: 2048
};
expect(
mod.configValidators.cacheVaryHeaders(validConfig.cacheVaryHeaders)
).toBe(true);
2024-12-24 12:49:12 +01:00
expect(
mod.configValidators.cacheIgnoreHeaders(validConfig.cacheIgnoreHeaders)
).toBe(true);
2024-12-15 19:21:25 +01:00
expect(
mod.configValidators.maximumCachedResponseSize(
validConfig.maximumCachedResponseSize
)
).toBe(true);
const invalidConfig = {
cacheVaryHeaders: "invalid",
2024-12-24 12:49:12 +01:00
cacheIgnoreHeaders: "invalid",
2024-12-15 19:21:25 +01:00
maximumCachedResponseSize: "invalid"
};
expect(
mod.configValidators.cacheVaryHeaders(invalidConfig.cacheVaryHeaders)
).toBe(false);
2024-12-24 12:49:12 +01:00
expect(
mod.configValidators.cacheIgnoreHeaders(invalidConfig.cacheIgnoreHeaders)
).toBe(false);
2024-12-15 19:21:25 +01:00
expect(
mod.configValidators.maximumCachedResponseSize(
invalidConfig.maximumCachedResponseSize
)
).toBe(false);
});
});