Skip to content

Commit 632260a

Browse files
Merge pull request #1283 from Real-Dev-Squad/feat/cache-invalidator
Add middleware to invalidate cache
2 parents 1e11643 + 004990e commit 632260a

File tree

7 files changed

+313
-20
lines changed

7 files changed

+313
-20
lines changed

constants/cacheKeys.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const ALL_TASKS = "cache:ALL-TASKS";
2+
3+
module.exports = { ALL_TASKS };

routes/taskRequests.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ const router = express.Router();
44
const authenticate = require("../middlewares/authenticate");
55
const authorizeRoles = require("../middlewares/authorizeRoles");
66
const taskRequests = require("../controllers/tasksRequests");
7-
const cache = require("../utils/cache");
7+
const { cacheResponse } = require("../utils/cache");
88
const { validateUser } = require("../middlewares/taskRequests");
99

10-
router.get("/", authenticate, authorizeRoles([SUPERUSER]), cache(), taskRequests.fetchTaskRequests);
10+
router.get("/", authenticate, authorizeRoles([SUPERUSER]), cacheResponse(), taskRequests.fetchTaskRequests);
1111
router.post("/addOrUpdate", authenticate, validateUser, taskRequests.addOrUpdate);
1212
router.patch("/approve", authenticate, authorizeRoles([SUPERUSER]), validateUser, taskRequests.approveTaskRequest);
1313

routes/tasks.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,38 @@ const { createTask, updateTask, updateSelfTask, getTasksValidator } = require(".
66
const authorizeRoles = require("../middlewares/authorizeRoles");
77
const { APPOWNER, SUPERUSER } = require("../constants/roles");
88
const assignTask = require("../middlewares/assignTask");
9-
const cache = require("../utils/cache");
9+
const { cacheResponse, invalidateCache } = require("../utils/cache");
10+
const { ALL_TASKS } = require("../constants/cacheKeys");
1011

11-
router.get("/", getTasksValidator, cache(), tasks.fetchTasks);
12+
router.get("/", getTasksValidator, cacheResponse({ invalidationKey: ALL_TASKS, expiry: 10 }), tasks.fetchTasks);
1213
router.get("/self", authenticate, tasks.getSelfTasks);
1314
router.get("/overdue", authenticate, authorizeRoles([SUPERUSER]), tasks.overdueTasks);
14-
router.post("/", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), createTask, tasks.addNewTask);
15-
router.patch("/:id", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), updateTask, tasks.updateTask);
15+
router.post(
16+
"/",
17+
authenticate,
18+
authorizeRoles([APPOWNER, SUPERUSER]),
19+
invalidateCache({ invalidationKeys: [ALL_TASKS] }),
20+
createTask,
21+
tasks.addNewTask
22+
);
23+
router.patch(
24+
"/:id",
25+
authenticate,
26+
authorizeRoles([APPOWNER, SUPERUSER]),
27+
invalidateCache({ invalidationKeys: [ALL_TASKS] }),
28+
updateTask,
29+
tasks.updateTask
30+
);
1631
router.get("/:id/details", tasks.getTask);
1732
router.get("/:username", tasks.getUserTasks);
18-
router.patch("/self/:id", authenticate, updateSelfTask, tasks.updateTaskStatus, assignTask);
19-
router.patch("/assign/self", authenticate, tasks.assignTask);
33+
router.patch(
34+
"/self/:id",
35+
authenticate,
36+
invalidateCache({ invalidationKeys: [ALL_TASKS] }),
37+
updateSelfTask,
38+
tasks.updateTaskStatus,
39+
assignTask
40+
);
41+
router.patch("/assign/self", authenticate, invalidateCache({ invalidationKeys: [ALL_TASKS] }), tasks.assignTask);
2042

2143
module.exports = router;

test/fixtures/cache/cache.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const dummyResponse = { body: "test" };
2+
3+
module.exports = { dummyResponse };
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const sinon = require("sinon");
2+
const { expect } = require("chai");
3+
const { cacheResponse, invalidateCache } = require("../../../utils/cache");
4+
5+
const { dummyResponse } = require("../../fixtures/cache/cache");
6+
7+
const responseBody = JSON.stringify(dummyResponse);
8+
9+
describe("Middleware | Utils | cache", function () {
10+
afterEach(function () {
11+
sinon.restore();
12+
});
13+
it("should cache the response", function () {
14+
const cacheTestKey = "__cache__1";
15+
16+
const request = {
17+
method: "GET",
18+
originalUrl: "/test1",
19+
};
20+
21+
const response = {
22+
send: sinon.spy(),
23+
};
24+
25+
const nextSpy = sinon.spy();
26+
27+
const cacheMiddleware = cacheResponse({ invalidationKey: cacheTestKey });
28+
29+
cacheMiddleware(request, response, nextSpy);
30+
31+
response.send(responseBody);
32+
33+
expect(nextSpy.callCount).to.equal(1);
34+
expect(response.send.callCount).to.equal(1);
35+
36+
cacheMiddleware(request, response, nextSpy);
37+
38+
expect(nextSpy.callCount).to.equal(1);
39+
expect(response.send.callCount).to.equal(2);
40+
});
41+
42+
it("should invalidate stale the response", function () {
43+
const cacheTestKey = "__cache__2";
44+
45+
const request = {
46+
method: "GET",
47+
originalUrl: "/test2",
48+
};
49+
const response = {
50+
send: sinon.spy(),
51+
};
52+
53+
const nextSpy = sinon.spy();
54+
55+
const cacheMiddlewareForCache = cacheResponse({ invalidationKey: cacheTestKey });
56+
57+
cacheMiddlewareForCache(request, response, nextSpy);
58+
59+
response.send(responseBody);
60+
61+
expect(nextSpy.callCount).to.equal(1);
62+
expect(response.send.callCount).to.equal(1);
63+
64+
const cacheMiddlewareForInvalidation = invalidateCache({ invalidationKeys: [cacheTestKey] });
65+
66+
cacheMiddlewareForInvalidation(request, response, nextSpy);
67+
response.send(responseBody);
68+
69+
expect(nextSpy.callCount).to.equal(2);
70+
expect(response.send.callCount).to.equal(2);
71+
72+
cacheMiddlewareForCache(request, response, nextSpy);
73+
response.send(responseBody);
74+
75+
expect(nextSpy.callCount).to.equal(3);
76+
expect(response.send.callCount).to.equal(3);
77+
});
78+
});

test/unit/utils/cache.test.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const { expect } = require("chai");
2+
const { cachedKeysStore } = require("../../../utils/cache");
3+
4+
describe("cachedKeysStore", function () {
5+
let keyStore;
6+
const modelKey = "modelKey";
7+
beforeEach(function () {
8+
keyStore = cachedKeysStore();
9+
});
10+
11+
describe("getCachedKeys", function () {
12+
it("should return an array of cached keys for a model key", function () {
13+
const cachedKeys = new Set(["key1", "key2", "key3"]);
14+
keyStore.addCachedKey(modelKey, "key1");
15+
keyStore.addCachedKey(modelKey, "key2");
16+
keyStore.addCachedKey(modelKey, "key3");
17+
18+
const result = keyStore.getCachedKeys(modelKey);
19+
20+
expect(result).to.be.an("set");
21+
expect(result).to.be.deep.equal(cachedKeys);
22+
});
23+
});
24+
25+
describe("addCachedKey", function () {
26+
it("should add a cached key to the key store", function () {
27+
const cachedKey = "key1";
28+
29+
keyStore.addCachedKey(modelKey, cachedKey);
30+
31+
const result = keyStore.getCachedKeys(modelKey);
32+
expect(result).to.deep.equal(new Set([cachedKey]));
33+
});
34+
});
35+
36+
describe("removeModelKey", function () {
37+
it("should remove the model key and its associated cached keys from the key store", function () {
38+
keyStore.addCachedKey(modelKey, "key1");
39+
keyStore.addCachedKey(modelKey, "key2");
40+
keyStore.addCachedKey(modelKey, "key3");
41+
42+
keyStore.removeModelKey(modelKey);
43+
44+
const result = keyStore.getCachedKeys(modelKey);
45+
expect(result).to.be.an("set");
46+
expect(result).to.deep.equal(new Set());
47+
});
48+
});
49+
50+
describe("removeCachedKey", function () {
51+
it("should remove a cached key from the key store for a given model key", function () {
52+
const cachedKey = "key1";
53+
keyStore.addCachedKey(modelKey, cachedKey);
54+
55+
keyStore.removeCachedKey(modelKey, cachedKey);
56+
57+
const result = keyStore.getCachedKeys(modelKey);
58+
expect(result).to.be.an("set");
59+
expect(result).to.deep.equal(new Set());
60+
});
61+
62+
it("should not remove other cached keys for the same model key", function () {
63+
keyStore.addCachedKey(modelKey, "key1");
64+
keyStore.addCachedKey(modelKey, "key2");
65+
keyStore.addCachedKey(modelKey, "key3");
66+
67+
keyStore.removeCachedKey(modelKey, "key2");
68+
69+
const result = keyStore.getCachedKeys(modelKey);
70+
expect(result).to.deep.equal(new Set(["key1", "key3"]));
71+
});
72+
});
73+
});

0 commit comments

Comments
 (0)