edge: add end-to-end cache-before-wake test
1 file changed,
+75
−0
internal/edge/edge_test.go+75 −0
diff --git a/internal/edge/edge_test.go b/internal/edge/edge_test.go| index 591e6379f..a14968d3f 100644 |
| --- a/internal/edge/edge_test.go |
| +++ b/internal/edge/edge_test.go |
| @@ -691,3 +691,78 @@ func TestServeHTTPUpgradeRequestBypassesRecording(t *testing.T) { |
| e.ServeHTTP(rec, req) |
| } |
| + |
| +// activatorFunc adapts a plain function to the Activator interface, for |
| +// tests that want custom wake-counting behavior without a full fake type. |
| +type activatorFunc func(w http.ResponseWriter, r *http.Request, rt registry.Route, proxy http.Handler) bool |
| + |
| +func (f activatorFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, rt registry.Route, proxy http.Handler) bool { |
| + return f(w, r, rt, proxy) |
| +} |
| + |
| +func (f activatorFunc) RetireExcept(keep map[string]bool) { |
| + // No-op for tests that don't need retirement tracking. |
| +} |
| + |
| +// TestCacheBeforeWakeFullCycle exercises the sequence the whole feature |
| +// exists for: a cold miss wakes the instance and populates the cache; a |
| +// repeat request hits the cache and does NOT wake the instance again; a |
| +// write's purge call makes the next request miss and see fresh content. |
| +func TestCacheBeforeWakeFullCycle(t *testing.T) { |
| + body := "version 1" |
| + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| + w.Header().Set("Cache-Control", "max-age=60") |
| + w.WriteHeader(200) |
| + w.Write([]byte(body)) |
| + })) |
| + t.Cleanup(backend.Close) |
| + |
| + wakes := 0 |
| + act := activatorFunc(func(w http.ResponseWriter, r *http.Request, rt registry.Route, proxy http.Handler) bool { |
| + wakes++ |
| + proxy.ServeHTTP(w, r) |
| + return true |
| + }) |
| + |
| + reg := openReg(t) |
| + if err := reg.Upsert(registry.Route{Host: "cycle.example.com", Kind: "instance", Addr: backend.Listener.Addr().String(), Status: "ready", Hibernate: true}); err != nil { |
| + t.Fatalf("upsert: %v", err) |
| + } |
| + e, err := New(reg, act) |
| + if err != nil { |
| + t.Fatalf("New: %v", err) |
| + } |
| + cache := NewCache(DefaultCacheMaxEntries, DefaultCacheMaxBodyBytes) |
| + e.EnableCache(cache) |
| + |
| + get := func() string { |
| + rec := httptest.NewRecorder() |
| + e.ServeHTTP(rec, httptest.NewRequest("GET", "http://cycle.example.com/event", nil)) |
| + return rec.Body.String() |
| + } |
| + |
| + if got := get(); got != "version 1" { |
| + t.Fatalf("first request body = %q, want %q", got, "version 1") |
| + } |
| + if wakes != 1 { |
| + t.Fatalf("expected exactly 1 wake for the cold request, got %d", wakes) |
| + } |
| + |
| + if got := get(); got != "version 1" { |
| + t.Fatalf("second request body = %q, want %q", got, "version 1") |
| + } |
| + if wakes != 1 { |
| + t.Fatalf("expected the second request to hit cache without waking again, wakes = %d", wakes) |
| + } |
| + |
| + // Simulate the write + purge an instance does after a real change. |
| + body = "version 2" |
| + cache.PurgeURL("cycle.example.com", "/event", "") |
| + |
| + if got := get(); got != "version 2" { |
| + t.Fatalf("post-purge request body = %q, want %q", got, "version 2") |
| + } |
| + if wakes != 2 { |
| + t.Fatalf("expected the post-purge request to miss and wake once more, wakes = %d", wakes) |
| + } |
| +} |