From 2e60c7b211ad31de8412f9e79dd32a46599115ef Mon Sep 17 00:00:00 2001 From: yutak23 <79501292+yutak23@users.noreply.github.com> Date: Thu, 11 Jan 2024 23:47:00 +0900 Subject: [PATCH] feat: content-type are also cached (#59) --- index.js | 4 +- test/app-cache.js | 29 ++++++++++++ test/index.js | 29 ++++++++++++ test/params.js | 40 ++++++++++++++++ test/ttls.js | 118 +++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 218 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 774db5c..9e92b03 100644 --- a/index.js +++ b/index.js @@ -65,6 +65,7 @@ module.exports.cacheSeconds = function (secondsTTL, cacheKey) { if (value) { // returns the value immediately debug('hit!!', key) + if (value.contentType) res.set('Content-Type', value.contentType) if (value.isJson) { res.status(value.status).json(value.body) } else { @@ -102,7 +103,7 @@ module.exports.cacheSeconds = function (secondsTTL, cacheKey) { didHandle = true const body = data instanceof Buffer ? data.toString() : data - if (res.statusCode < 400) cacheStore.set(key, { status: res.statusCode, body: body, isJson: isJson }, ttl) + if (res.statusCode < 400) cacheStore.set(key, { status: res.statusCode, body: body, isJson: isJson, contentType: res.getHeader('Content-Type') }, ttl) // send this response to everyone in the queue drainQueue(key) @@ -180,6 +181,7 @@ module.exports.cacheSeconds = function (secondsTTL, cacheKey) { return cacheStore.get(key).then((cachedValue) => { const value = cachedValue || {} debug('>> queued hit:', key, value.length) + if (value.contentType) res.set('Content-Type', value.contentType) if (value.isJson) { res.status(value.status || 200).json(value.body) } else { diff --git a/test/app-cache.js b/test/app-cache.js index 3bb8a03..6a1636d 100644 --- a/test/app-cache.js +++ b/test/app-cache.js @@ -6,6 +6,7 @@ var request = require('supertest'), var hitIndex = 0; var noContentIndex = 0; +var contentTypeIndex = 0; var app = express(); var agent = request.agent(app); @@ -43,6 +44,12 @@ describe('App-level cache:', function () { res.status(204).json(); }); + app.get('/content-type', function (req, res) { + contentTypeIndex++; + res.set('Content-Type', 'application/xml'); + res.send('This is some content') + }); + it('1st res.send', function (done) { agent .get('/app-test') @@ -138,4 +145,26 @@ describe('App-level cache:', function () { done() }) }) + + it('1st content-type', function (done) { + agent + .get('/content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) + + it('2st content-type', function (done) { + agent + .get('/content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) }); diff --git a/test/index.js b/test/index.js index 3250423..27c8308 100644 --- a/test/index.js +++ b/test/index.js @@ -9,6 +9,7 @@ let testindex = 0 let noContentIndex = 0 let paramTestindex = 0 let testindexRemove = 0 +let contentTypeIndex = 0 describe('# RouteCache middleware test', function () { const app = express() @@ -31,6 +32,12 @@ describe('# RouteCache middleware test', function () { res.status(204).send() }) + app.get('/content-type', routeCache.cacheSeconds(10), function (req, res) { + contentTypeIndex++ + res.set('Content-Type', 'application/xml') + res.send('This is some content') + }) + app.get('/500', routeCache.cacheSeconds(10), function (req, res) { res.status(500).send('Internal server error: ' + Math.random()) }) @@ -109,6 +116,28 @@ describe('# RouteCache middleware test', function () { }) }) + it('1st content-type', function (done) { + agent + .get('/content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) + + it('2st content-type', function (done) { + agent + .get('/content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) + it('1st Redirect to hello', function (done) { agent .get('/redirect-to-hello') diff --git a/test/params.js b/test/params.js index 7eb1a45..86e65b1 100644 --- a/test/params.js +++ b/test/params.js @@ -6,6 +6,7 @@ var request = require('supertest'), var paramTestIndex = 0 var noContentIndex = 0 +var contentTypeIndex = 0 describe('Params / Querystrings', function () { var app = express() @@ -20,6 +21,12 @@ describe('Params / Querystrings', function () { res.status(204).send() }) + app.get('/params-content-type', routeCache.cacheSeconds(10, '/params-test-content-type'), function (req, res) { + contentTypeIndex++ + res.set('Content-Type', 'application/xml') + res.send('This is some content') + }) + var agent = request.agent(app) it('without params', function (done) { @@ -69,4 +76,37 @@ describe('Params / Querystrings', function () { done() }) }) + + it('content-type without params', function (done) { + agent + .get('/params-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) + + it('content-type with a=1', function (done) { + agent + .get('/params-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) + + it('content-type with a=2', function (done) { + agent + .get('/params-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }) }) diff --git a/test/ttls.js b/test/ttls.js index 6c98b6a..7d1cef7 100644 --- a/test/ttls.js +++ b/test/ttls.js @@ -13,6 +13,7 @@ describe('TTL:', function () { context('disabled (-1)', function () { var hitIndex = 0; var noContentIndex = 0; + var contentTypeIndex = 0; app.get('/cache-disabled', routeCache.cacheSeconds(-1), function (req, res) { hitIndex++; @@ -24,6 +25,12 @@ describe('TTL:', function () { res.status(204).send(); }); + app.get('/cache-disabled-content-type', routeCache.cacheSeconds(-1), function (req, res) { + contentTypeIndex++ + res.set('Content-Type', 'application/xml') + res.send('This is some content') + }) + it('Should get Hit #1', function (done) { agent .get('/cache-disabled') @@ -62,11 +69,36 @@ describe('TTL:', function () { }); }); + it('Should contentTypeIndex is 1', function (done) { + agent + .get('/cache-disabled-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }); + + it('Should contentTypeIndex is 2 (after nextTick)', function (done) { + + process.nextTick(function () { + agent + .get('/cache-disabled-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 2) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }); + }); }) context('zero', function () { var hitIndex = 0; var noContentIndex = 0; + var contentTypeIndex = 0; app.get('/cache-zero', routeCache.cacheSeconds(0), function (req, res) { hitIndex++; @@ -78,6 +110,12 @@ describe('TTL:', function () { res.status(204).send(); }); + app.get('/cache-zero-content-type', routeCache.cacheSeconds(0), function (req, res) { + contentTypeIndex++ + res.set('Content-Type', 'application/xml') + res.send('This is some content') + }) + it('Should get Hit #1', function (done) { agent .get('/cache-zero') @@ -138,11 +176,48 @@ describe('TTL:', function () { }, 200); }); + it('Should contentTypeIndex is 1', function (done) { + agent + .get('/cache-zero-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }); + + it('Should contentTypeIndex is 1 (after nextTick)', function (done) { + process.nextTick(function () { + agent + .get('/cache-zero-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }); + }); + + it('Should contentTypeIndex is 2 (after 200ms delay)', function (done) { + setTimeout(function () { + agent + .get('/cache-zero-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 2) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }, 200); + }); }) context('1 second:', function () { var hitIndex = 0; var noContentIndex = 0; + var contentTypeIndex = 0; app.get('/cache-1s', routeCache.cacheSeconds(1), function (req, res) { hitIndex++; @@ -154,6 +229,12 @@ describe('TTL:', function () { res.status(204).send(); }); + app.get('/cache-1s-content-type', routeCache.cacheSeconds(1), function (req, res) { + contentTypeIndex++ + res.set('Content-Type', 'application/xml') + res.send('This is some content') + }) + it('Should get Hit #1', function (done) { agent .get('/cache-1s') @@ -214,6 +295,41 @@ describe('TTL:', function () { }, 1300); }); - }); + it('Should contentTypeIndex is 1', function (done) { + agent + .get('/cache-1s-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }); + it('Should contentTypeIndex is 1 (after 200ms delay)', function (done) { + setTimeout(function () { + agent + .get('/cache-1s-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 1) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }, 200); + }); + + it('Should contentTypeIndex is 2 (after 1200ms delay)', function (done) { + setTimeout(function () { + agent + .get('/cache-1s-content-type') + .expect(200, (error, response) => { + assert.equal(contentTypeIndex, 2) + assert.equal(response.headers['content-type'], 'application/xml; charset=utf-8') + assert.equal(response.text, 'This is some content') + done() + }) + }, 1200); + }); + }); });