UNPKG

upcache

Version:

nginx proxy cache key protocols implementations

293 lines (251 loc) 7.41 kB
const URL = require('url'); const express = require('express'); const assert = require('assert').strict; const runner = require('../lib/spawner'); const common = require('./common'); const tag = require('..').tag; const ports = { app: 3000, ngx: 3001, memc: 3002 }; describe("Tag", () => { let servers, app; const testPath = '/tag-test'; const conditionalPath = "/conditional"; const conditionalPathNot = "/conditionalnot"; const untaggedPath = '/untagged'; const counters = {}; function count(uri, inc) { if (typeof uri != "string") { if (uri.get) uri = uri.protocol + '://' + uri.get('Host') + uri.path; else uri = URL.format(Object.assign({ protocol: 'http', hostname: 'localhost', pathname: uri.path }, uri)); } let counter = counters[uri]; if (counter == null) counter = counters[uri] = 0; if (inc) counters[uri] += inc; return counters[uri]; } before(async () => { servers = await runner(ports); app = express(); app.server = app.listen(ports.app); app.get('/a', tag('global'), (req, res, next) => { count(req, 1); res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.get(testPath, tag('test'), (req, res, next) => { count(req, 1); res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.post(testPath, tag('test'), (req, res, next) => { res.send('OK'); }); app.post("/a", tag('test'), (req, res, next) => { res.send('OK'); }); app.get('/multiple', tag('one'), tag('two'), (req, res, next) => { count(req, 1); res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.post("/multiple", tag('two'), (req, res, next) => { res.send('OK'); }); app.get(conditionalPath, tag('conditional'), (req, res, next) => { count(req, 1); res.set('ETag', 'W/"myetag"'); res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.get(conditionalPathNot, tag('conditionalnot'), (req, res, next) => { count(req, 1); res.set('ETag', 'W/"myetagnot"'); res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.get('/multiplesame', tag('one'), tag('one', 'two'), tag('+one', 'two', 'three'), (req, res, next) => { count(req, 1); res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.get(untaggedPath, (req, res, next) => { count(req, 1); res.send("ok"); }); app.get("/params/:test", (req, res, next) => { if (req.params.test == "none") req.params.test = null; next(); }, tag('site-:test').for('1min'), (req, res, next) => { res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.get("/params2/:test", tag('prev'), (req, res, next) => { if (req.params.test == "none") req.params.test = null; next(); }, tag('site-:test').for('1min'), (req, res, next) => { res.send({ value: (req.path || '/').substring(1), date: new Date() }); }); app.use(common.errorHandler); }); after(async () => { app.server.close(); await servers.close(); }); it("cache a url", async () => { const req = { port: ports.ngx, path: testPath }; let res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], 'test'); res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], 'test'); assert.equal(count(req), 1); }); it("honor req.params tag replacement", async () => { const req = { port: ports.ngx, path: "/params/me" }; let res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], 'site-me'); assert.equal(res.headers['cache-control'], 'public, max-age=60'); req.path = "/params/none"; res = await common.get(req); assert.equal('x-upcache-tag' in res.headers, false); assert.equal('cache-control' in res.headers, false); }); it("honor req.params tag replacement with a previous tag set", async () => { const req = { port: ports.ngx, path: "/params2/me" }; let res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], 'prev, site-me'); assert.equal(res.headers['cache-control'], 'public, max-age=60'); req.path = "/params2/none"; res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], 'prev'); assert.equal('cache-control' in res.headers, false); }).timeout(0); it("invalidate a tag using a post", async () => { const req = { port: ports.ngx, path: testPath }; let res = await common.get(req); const firstDate = Date.parse(res.body.date); assert.equal(res.headers['x-upcache-tag'], 'test'); res = await common.post(req, 'postbody'); assert.equal(res.headers['x-upcache-tag'], '+test'); res = await common.get(req); assert.ok(Date.parse(res.body.date) > firstDate); }); it("invalidate one tag on a route with multiple tags using a post", async () => { const req = { port: ports.ngx, path: "/multiple" }; let res = await common.get(req); const firstDate = Date.parse(res.body.date); assert.equal(res.headers['x-upcache-tag'], 'one, two'); res = await common.post(req, 'postbody'); assert.equal(res.headers['x-upcache-tag'], '+two'); res = await common.get(req); assert.ok(Date.parse(res.body.date) > firstDate); }); it("invalidate a tag using a post to a different path", async () => { const req = { port: ports.ngx, path: testPath }; let res = await common.get(req); const firstDate = Date.parse(res.body.date); assert.equal(res.headers['x-upcache-tag'], 'test'); res = await common.post({ port: ports.ngx, path: "/a" }, 'postbody'); assert.equal(res.headers['x-upcache-tag'], '+test'); res = await common.get(req); assert.ok(Date.parse(res.body.date) > firstDate); }); it("handle conditional requests from upstream ETag once cached", async () => { const headers = {}; const req = { headers: headers, port: ports.ngx, path: conditionalPath }; let res = await common.get(req); assert.ok('etag' in res.headers); headers['If-None-Match'] = res.headers.etag; res = await common.get(req); assert.equal(res.statusCode, 304); assert.equal(count(req), 1); }); it("not let conditional requests go to upstream", async () => { const headers = {}; const req = { headers: headers, port: ports.ngx, path: conditionalPathNot }; headers['If-None-Match'] = 'W/"myetagnot"'; let res = await common.get(req); assert.equal(res.statusCode, 200); assert.equal(count(req), 1); res = await common.get(req); assert.equal(res.statusCode, 304); assert.equal(count(req), 1); }); it("not cache responses if not tagged by upstream", async () => { const headers = {}; const req = { headers: headers, port: ports.ngx, path: untaggedPath }; let res = await common.get(req); assert.equal(res.statusCode, 200); assert.equal(count(req), 1); res = await common.get(req); assert.equal(res.statusCode, 200); assert.equal(count(req), 2); }); it("not return multiple identical tags", async () => { const req = { port: ports.ngx, path: '/multiplesame' }; let res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], '+one, two, three'); res = await common.get(req); assert.equal(res.headers['x-upcache-tag'], '+one, two, three'); assert.equal(count(req), 1); }); });