Skip to content

Commit 5f03663

Browse files
committed
test(endpoint-cache): add tests for get operation
1 parent 6f75581 commit 5f03663

File tree

2 files changed

+119
-3
lines changed

2 files changed

+119
-3
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { LRUCache } from "mnemonist";
2+
3+
import { Endpoint } from "./Endpoint";
4+
import { EndpointCache } from "./EndpointCache";
5+
6+
jest.mock("mnemonist");
7+
8+
describe(EndpointCache.name, () => {
9+
const now = Date.now();
10+
const set = jest.fn();
11+
const get = jest.fn();
12+
const has = jest.fn();
13+
const clear = jest.fn();
14+
15+
const mockEndpoints = [
16+
{ Address: "addressA", CachePeriodInMinutes: 1 },
17+
{ Address: "addressB", CachePeriodInMinutes: 2 },
18+
];
19+
20+
const getEndpointsWithExpiry = (endpoints: Endpoint[]) =>
21+
endpoints.map(({ Address = "", CachePeriodInMinutes = 1 }) => ({
22+
Address,
23+
Expires: now + CachePeriodInMinutes * 60 * 1000,
24+
}));
25+
26+
const getMaxCachePeriodInMins = (endpoints: Endpoint[]) =>
27+
Math.max(...endpoints.map((endpoint) => endpoint.CachePeriodInMinutes));
28+
29+
beforeEach(() => {
30+
((LRUCache as unknown) as jest.Mock).mockReturnValueOnce({
31+
set,
32+
get,
33+
has,
34+
clear,
35+
});
36+
});
37+
38+
afterEach(() => {
39+
jest.clearAllMocks();
40+
});
41+
42+
it("passes capacity to LRUCache", () => {
43+
const capacity = 100;
44+
new EndpointCache(capacity);
45+
expect(LRUCache).toHaveBeenCalledTimes(1);
46+
expect(LRUCache).toHaveBeenCalledWith(capacity);
47+
});
48+
49+
describe("get", () => {
50+
let endpointCache;
51+
const key = "key";
52+
53+
beforeEach(() => {
54+
has.mockReturnValue(true);
55+
get.mockReturnValue(getEndpointsWithExpiry(mockEndpoints));
56+
jest.spyOn(Date, "now").mockImplementation(() => now);
57+
endpointCache = new EndpointCache(100);
58+
});
59+
60+
const verifyHasAndGetCalls = () => {
61+
expect(has).toHaveBeenCalledTimes(1);
62+
expect(has).toHaveBeenCalledWith(key);
63+
expect(get).toHaveBeenCalledTimes(1);
64+
expect(get).toHaveBeenCalledWith(key);
65+
};
66+
67+
it("returns undefined if cache doesn't have key", () => {
68+
has.mockReturnValueOnce(false);
69+
expect(endpointCache.get(key)).toBeUndefined();
70+
expect(has).toHaveBeenCalledTimes(1);
71+
expect(has).toHaveBeenCalledWith(key);
72+
expect(get).not.toHaveBeenCalled();
73+
});
74+
75+
it("returns undefined if cache returns undefined for key", () => {
76+
get.mockReturnValueOnce(undefined);
77+
expect(endpointCache.get(key)).toBeUndefined();
78+
verifyHasAndGetCalls();
79+
expect(set).not.toHaveBeenCalled();
80+
});
81+
82+
it("returns undefined if endpoints have expired", () => {
83+
const maxCachePeriod = getMaxCachePeriodInMins(mockEndpoints);
84+
jest.spyOn(Date, "now").mockImplementation(() => now + (maxCachePeriod + 1) * 60 * 1000);
85+
expect(endpointCache.get(key)).toBeUndefined();
86+
verifyHasAndGetCalls();
87+
expect(set).toHaveBeenCalledTimes(1);
88+
expect(set).toHaveBeenCalledWith(key, []);
89+
});
90+
91+
it("returns one of the un-expired endpoints", () => {
92+
expect(mockEndpoints.map((endpoint) => endpoint.Address)).toContain(endpointCache.get(key));
93+
verifyHasAndGetCalls();
94+
expect(set).not.toHaveBeenCalled();
95+
});
96+
97+
it("returns un-expired endpoint", () => {
98+
jest.spyOn(Date, "now").mockImplementation(() => now + 90 * 1000);
99+
expect(endpointCache.get(key)).toEqual(mockEndpoints[1].Address);
100+
verifyHasAndGetCalls();
101+
expect(set).not.toHaveBeenCalled();
102+
});
103+
104+
[0, 1].forEach((index) => {
105+
it(`returns un-expired endpoint at index ${index}`, () => {
106+
jest.spyOn(Math, "floor").mockImplementation(() => index);
107+
expect(mockEndpoints.map((endpoint) => endpoint.Address)).toContain(endpointCache.get(key));
108+
verifyHasAndGetCalls();
109+
expect(set).not.toHaveBeenCalled();
110+
});
111+
});
112+
});
113+
});

packages/endpoint-cache/src/EndpointCache.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@ export class EndpointCache {
1616
private getEndpoint(endpointsWithExpiry: EndpointWithExpiry[]) {
1717
const now = Date.now();
1818
const endpoints = endpointsWithExpiry
19-
.filter((endpoint) => now > endpoint.Expires)
19+
.filter((endpoint) => now < endpoint.Expires)
2020
.map((endpoint) => endpoint.Address);
2121
return endpoints[Math.floor(Math.random() * endpoints.length)];
2222
}
2323

2424
get(key: string) {
25-
const endpointsWithExpiry = this.cache.get(key);
25+
if (!this.has(key)) {
26+
return;
27+
}
2628

29+
const endpointsWithExpiry = this.cache.get(key);
2730
if (!endpointsWithExpiry) {
2831
return;
2932
}
@@ -41,7 +44,7 @@ export class EndpointCache {
4144
key,
4245
endpoints.map(({ Address = "", CachePeriodInMinutes = 1 }) => ({
4346
Address,
44-
Expires: now + CachePeriodInMinutes * 60 * 100,
47+
Expires: now + CachePeriodInMinutes * 60 * 1000,
4548
}))
4649
);
4750
}

0 commit comments

Comments
 (0)