UNPKG

outputcache

Version:

Cache api responses, react and more using redis, memcached or any other cache provider.

495 lines (419 loc) 17.2 kB
var request = require("supertest"); var requireNew = require("require-new"); var express = require("express"); var app = express(); var cookieParser = require("cookie-parser"); app.use(cookieParser()); var OutputCache = requireNew("../src/outputcache"); var cacheHeaders = new OutputCache(); var cacheNoHeaders = new OutputCache({ noHeaders: true }); var cacheCaseIns = new OutputCache({ caseSensitive: false }); var cache = new OutputCache({ varyByQuery: true, staleWhileRevalidate: 700, varyByCookies: ["hello"] }); app.get("/GetJSON", cache.middleware, function (req, res) { res.setHeader("Content-Type", "application/json"); res.status(200).json({ hello: "world" }); }); app.get("/GetHtml", cache.middleware, function (req, res) { res.status(200).send("<html></html>"); }); app.get("/GetHtmlHeaderTtl", cacheHeaders.middleware, function (req, res) { res.set({ "Cache-Control": "max-age=1068, stale-while-revalidate=2000" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlCustomHeaders", cache.middleware, function (req, res) { res.set({ "X-Custom": "custom-header" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlSkipHeader", cache.middleware, function (req, res) { res.set({ "X-Output-Cache": "ms" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlCustomCacheControl", cache.middleware, function (req, res) { res.set({ "Cache-Control": "max-age=722" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlInvalidCacheControl", cache.middleware, function (req, res) { res.set({ "Cache-Control": "max-age=wrong" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlInvalidCacheControl2", cache.middleware, function (req, res) { res.set({ "Cache-Control": "676" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlNoStore", cache.middleware, function (req, res) { res.set({ "Cache-Control": "no-store" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlNoCache", cache.middleware, function (req, res) { res.set({ "Cache-Control": "no-cache" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlPrivate", cache.middleware, function (req, res) { res.set({ "Cache-Control": "private" }); res.status(200).send("<html></html>"); }); app.get("/GetRedirect", cache.middleware, function (req, res) { res.redirect(301, "/RedirectTarget"); }); app.get("/RedirectTarget", cache.middleware, function (req, res) { res.status(200).send("<html></html>"); }); app.get("/qStringBasedContent", cache.middleware, function (req, res) { var output = "querystring says hello " + req.query.hello; res.status(200).send(output); }); app.get("/cookieBasedContent", cache.middleware, function (req, res) { var output = "cookie says hello " + req.cookies.hello; res.status(200).send(output); }); app.get("/GetHtmlNoHeader", cacheNoHeaders.middleware, function (req, res) { res.set({ "Cache-Control": "max-age=500" }); res.status(200).send("<html></html>"); }); app.get("/GetHtmlInSensitive", cacheCaseIns.middleware, function (req, res) { res.status(200).send("<html></html>"); }); describe("GET JSON with headers and status", function () { it("origin responds with json and cache miss header", function (done) { request(app) .get("/GetJSON") .set("Accept", "application/json") .expect("Content-Type", /json/) .expect("X-Output-Cache", /ms/) .expect(200, { hello: "world" }, done); }); it("cache responds with json and cache hit header", function (done) { request(app) .get("/GetJSON") .set("Accept", "application/json") .expect("Content-Type", /json/) .expect("X-Output-Cache", /ht 600 700/) .expect(200, { hello: "world" }, done); }); }); describe("GET HTML with headers and status", function () { it("origin responds with html and cache miss header", function (done) { request(app) .get("/GetHtml") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", done); }); it("cache responds with html and cache hit header", function (done) { request(app) .get("/GetHtml") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect(200, "<html></html>", done); }); }); describe("GET Redirect with status and result", function () { it("origin responds with 301 and cache miss header", function (done) { request(app) .get("/GetRedirect") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(301, done); }); it("cache responds with 301 and cache hit header", function (done) { request(app) .get("/GetRedirect") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect(301, done); }); }); describe("Honours cache miss headers", function () { it("no-store cache header causes ms", function (done) { request(app) .get("/GetHtmlNoStore") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>"); request(app) .get("/GetHtmlNoStore") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", done); }); it("no-cache cache header causes ms", function (done) { request(app) .get("/GetHtmlNoCache") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>"); request(app) .get("/GetHtmlNoCache") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", done); }); it("private cache header causes ms", function (done) { request(app) .get("/GetHtmlPrivate") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>"); request(app) .get("/GetHtmlPrivate") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", done); }); }); describe("Honours custom headers", function () { it("origin returns a custom header", function (done) { request(app) .get("/GetHtmlCustomHeaders") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect("X-Custom", /custom-header/) .expect(200, "<html></html>", done); }); it("cache returns same custom header as origin", function (done) { request(app) .get("/GetHtmlCustomHeaders") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect("X-Custom", /custom-header/) .expect(200, "<html></html>", done); }); }); describe("Honours cache control", function () { it("origin returns cache-control value", function (done) { request(app) .get("/GetHtmlCustomCacheControl") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect("Cache-Control", /max-age=722/) .expect(200, "<html></html>", done); }); it("cache returns same cache control value as origin", function (done) { request(app) .get("/GetHtmlCustomCacheControl") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 722 0/) .expect("Cache-Control", /max-age=722/) .expect(200, "<html></html>", done); }); it("returns default cache control header if none set", function (done) { request(app) .get("/GetHtml") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect("Cache-Control", /max-age=600/) .expect("Cache-Control", /stale-while-revalidate=700/) .expect(200, "<html></html>", done); }); it("origin returns supplied max-age when invalid", function (done) { request(app) .get("/GetHtmlInvalidCacheControl") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect("Cache-Control", /max-age=wrong/) .expect(200, "<html></html>", done); }); it("cache miss for invalid cache control header", function (done) { request(app) .get("/GetHtmlInvalidCacheControl") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect("Cache-Control", /max-age=wrong/) .expect(200, "<html></html>", done); }); it("cache miss for invalid cache control header with integer", function (done) { request(app) .get("/GetHtmlInvalidCacheControl2") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect("Cache-Control", /676/) .expect(200, "<html></html>", done); }); it("cache uses headers for ttl if useCacheHeader not false", function (done) { request(app) .get("/GetHtmlHeaderTtl") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect("Cache-Control", /max-age=1068, stale-while-revalidate=2000/) .expect(200, "<html></html>", function () { request(app) .get("/GetHtmlHeaderTtl") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 1068 2000/) .expect(200, "<html></html>", done); }); }); }); describe("Honours querystring", function () { it("origin honours querystring if value set", function (done) { request(app) .get("/qStringBasedContent?hello=world") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "querystring says hello world", done); }); it("cache honours querystring if value set", function (done) { request(app) .get("/qStringBasedContent?hello=world") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect(200, "querystring says hello world", done); }); it("cache miss if querystring changes key", function (done) { request(app) .get("/qStringBasedContent?hello=dave") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "querystring says hello dave", done); }); }); describe("Honours cookies", function () { it("origin returns different content based on cookie", function (done) { request(app) .get("/cookieBasedContent") .set("Accept", "text/html") .set("Cookie", ["hello=world"]) .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "cookie says hello world", done); }); it("cache returns same content based on cookie", function (done) { request(app) .get("/cookieBasedContent") .set("Accept", "text/html") .set("Cookie", ["hello=world"]) .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect(200, "cookie says hello world", done); }); it("cache miss if cookie value changes", function (done) { request(app) .get("/cookieBasedContent") .set("Accept", "text/html") .set("Cookie", ["hello=dave"]) .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "cookie says hello dave", done); }); }); describe("Cache skip", function () { it("cache skip if querystring contains cache=false value pair", function (done) { //miss request(app) .get("/qStringBasedContent?hello=dave") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "querystring says hello dave"); //hit request(app) .get("/qStringBasedContent?hello=dave") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 700/) .expect(200, "querystring says hello dave"); //force skip request(app) .get("/qStringBasedContent?hello=dave&cache=false") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "querystring says hello dave", done); }); it("cache skip if x-output-cache header with ms supplied by origin", function (done) { request(app) .get("/GetHtmlSkipHeader") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>"); request(app) .get("/GetHtmlSkipHeader") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", done); }); }); describe("Honours no header setting", function () { it("response headers do not have x-output-cache header if noHeaders is set ms/ht", function (done) { //miss request(app) .get("/GetHtmlNoHeader") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect(200, "<html></html>") .expect(function xocHeaderMissing(res) { if (res.get("x-output-cache")) { throw new Error("Expected x-output-cache header to be missing but was found"); } }, function () { //hit request(app) .get("/GetHtmlNoHeader") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect(200, "<html></html>") .expect(function xocHeaderMissing(res) { if (res.get("x-output-cache")) { throw new Error("Expected x-output-cache header to be missing but was found"); } }); }).end(done); }); }); describe("Casing toggle", function () { it("cache miss when key casing changes and caseSensitive enabled (default)", function (done) { request(app) .get("/GetHtmlHeaderTtl?test=lower") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", function () { request(app) .get("/GetHtmlHeaderTtl?TEST=LOWER") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", done); }); }); it("cache hit when key casing changes and caseSensitive disabled", function (done) { request(app) .get("/GetHtmlInSensitive?test=lower") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ms/) .expect(200, "<html></html>", function () { request(app) .get("/GetHtmlInSensitive?TEST=LOWER") .set("Accept", "text/html") .expect("Content-Type", /html/) .expect("X-Output-Cache", /ht 600 0/) .expect(200, "<html></html>", done); }); }); });