cache_test.go

  1package middleware
  2
  3import (
  4	"net/http"
  5	"net/http/httptest"
  6	"testing"
  7	"time"
  8)
  9
 10func TestCache_DefaultPublic(t *testing.T) {
 11	handler := Cache(1 * time.Hour)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 12		w.WriteHeader(http.StatusOK)
 13	}))
 14
 15	req := httptest.NewRequest(http.MethodGet, "/", nil)
 16	rr := httptest.NewRecorder()
 17	handler.ServeHTTP(rr, req)
 18
 19	want := "public, max-age=3600"
 20	if got := rr.Header().Get("Cache-Control"); got != want {
 21		t.Errorf("Cache-Control = %q, want %q", got, want)
 22	}
 23}
 24
 25func TestCache_WithPrivate(t *testing.T) {
 26	handler := Cache(5*time.Minute, WithPrivate())(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 27		w.WriteHeader(http.StatusOK)
 28	}))
 29
 30	req := httptest.NewRequest(http.MethodGet, "/", nil)
 31	rr := httptest.NewRecorder()
 32	handler.ServeHTTP(rr, req)
 33
 34	want := "private, max-age=300"
 35	if got := rr.Header().Get("Cache-Control"); got != want {
 36		t.Errorf("Cache-Control = %q, want %q", got, want)
 37	}
 38}
 39
 40func TestCache_WithImmutable(t *testing.T) {
 41	handler := Cache(365*24*time.Hour, WithImmutable())(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 42		w.WriteHeader(http.StatusOK)
 43	}))
 44
 45	req := httptest.NewRequest(http.MethodGet, "/", nil)
 46	rr := httptest.NewRecorder()
 47	handler.ServeHTTP(rr, req)
 48
 49	want := "public, max-age=31536000, immutable"
 50	if got := rr.Header().Get("Cache-Control"); got != want {
 51		t.Errorf("Cache-Control = %q, want %q", got, want)
 52	}
 53}
 54
 55func TestCache_WithPrivateAndImmutable(t *testing.T) {
 56	handler := Cache(24*time.Hour, WithPrivate(), WithImmutable())(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 57		w.WriteHeader(http.StatusOK)
 58	}))
 59
 60	req := httptest.NewRequest(http.MethodGet, "/", nil)
 61	rr := httptest.NewRecorder()
 62	handler.ServeHTTP(rr, req)
 63
 64	want := "private, max-age=86400, immutable"
 65	if got := rr.Header().Get("Cache-Control"); got != want {
 66		t.Errorf("Cache-Control = %q, want %q", got, want)
 67	}
 68}
 69
 70func TestCache_WithVary(t *testing.T) {
 71	handler := Cache(1*time.Hour, WithVary("Accept-Encoding", "Accept-Language"))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 72		w.WriteHeader(http.StatusOK)
 73	}))
 74
 75	req := httptest.NewRequest(http.MethodGet, "/", nil)
 76	rr := httptest.NewRecorder()
 77	handler.ServeHTTP(rr, req)
 78
 79	vary := rr.Header()["Vary"]
 80	if len(vary) != 2 {
 81		t.Fatalf("expected 2 Vary values, got %d", len(vary))
 82	}
 83	if vary[0] != "Accept-Encoding" {
 84		t.Errorf("Vary[0] = %q, want Accept-Encoding", vary[0])
 85	}
 86	if vary[1] != "Accept-Language" {
 87		t.Errorf("Vary[1] = %q, want Accept-Language", vary[1])
 88	}
 89}
 90
 91func TestCache_MaxAgeCap(t *testing.T) {
 92	handler := Cache(10 * 365 * 24 * time.Hour)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 93		w.WriteHeader(http.StatusOK)
 94	}))
 95
 96	req := httptest.NewRequest(http.MethodGet, "/", nil)
 97	rr := httptest.NewRecorder()
 98	handler.ServeHTTP(rr, req)
 99
100	want := "public, max-age=31536000"
101	if got := rr.Header().Get("Cache-Control"); got != want {
102		t.Errorf("Cache-Control = %q, want %q", got, want)
103	}
104}
105
106func TestCache_WithNoStore(t *testing.T) {
107	handler := Cache(0, WithNoStore())(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
108		w.WriteHeader(http.StatusOK)
109	}))
110
111	req := httptest.NewRequest(http.MethodGet, "/", nil)
112	rr := httptest.NewRecorder()
113	handler.ServeHTTP(rr, req)
114
115	want := "no-store"
116	if got := rr.Header().Get("Cache-Control"); got != want {
117		t.Errorf("Cache-Control = %q, want %q", got, want)
118	}
119}
120
121func TestCache_WithNoStoreOverridesOtherOptions(t *testing.T) {
122	handler := Cache(1*time.Hour, WithNoStore(), WithPrivate(), WithImmutable(), WithVary("Accept-Encoding"))(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
123		w.WriteHeader(http.StatusOK)
124	}))
125
126	req := httptest.NewRequest(http.MethodGet, "/", nil)
127	rr := httptest.NewRecorder()
128	handler.ServeHTTP(rr, req)
129
130	want := "no-store"
131	if got := rr.Header().Get("Cache-Control"); got != want {
132		t.Errorf("Cache-Control = %q, want %q", got, want)
133	}
134	// no-store takes precedence over all other directives, including Vary
135	if got := rr.Header().Get("Vary"); got != "" {
136		t.Errorf("Vary = %q, want empty", got)
137	}
138}
139
140func TestCache_NextHandlerCalled(t *testing.T) {
141	called := false
142	handler := Cache(1 * time.Hour)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
143		called = true
144		w.WriteHeader(http.StatusOK)
145	}))
146
147	req := httptest.NewRequest(http.MethodGet, "/", nil)
148	rr := httptest.NewRecorder()
149	handler.ServeHTTP(rr, req)
150
151	if !called {
152		t.Error("next handler was not called")
153	}
154}
155
156func TestCache_HandlerCanOverride(t *testing.T) {
157	handler := Cache(1 * time.Hour)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
158		w.Header().Set("Cache-Control", "no-cache")
159		w.WriteHeader(http.StatusOK)
160	}))
161
162	req := httptest.NewRequest(http.MethodGet, "/", nil)
163	rr := httptest.NewRecorder()
164	handler.ServeHTTP(rr, req)
165
166	want := "no-cache"
167	if got := rr.Header().Get("Cache-Control"); got != want {
168		t.Errorf("Cache-Control = %q, want %q", got, want)
169	}
170}