diff options
| author | Adam Mathes <adam@adammathes.com> | 2026-02-16 10:51:05 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-16 10:51:05 -0800 |
| commit | c5fdd406503aaedaac5e117e710d7910112af83f (patch) | |
| tree | 3a8b7b1d9277ba0db4c946fea43043d65220fd8d /web/web_bench_test.go | |
| parent | 8b852475d7952f37b630480af76897baca06e937 (diff) | |
| parent | d4caf45b2b9ea6a3276de792cf6f73085e66b1ae (diff) | |
| download | neko-c5fdd406503aaedaac5e117e710d7910112af83f.tar.gz neko-c5fdd406503aaedaac5e117e710d7910112af83f.tar.bz2 neko-c5fdd406503aaedaac5e117e710d7910112af83f.zip | |
Merge pull request #4 from adammathes/claude/performance-stress-testing-qQuV8
Add performance benchmarks, stress tests, and frontend perf tests
Diffstat (limited to 'web/web_bench_test.go')
| -rw-r--r-- | web/web_bench_test.go | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/web/web_bench_test.go b/web/web_bench_test.go new file mode 100644 index 0000000..7897fc7 --- /dev/null +++ b/web/web_bench_test.go @@ -0,0 +1,92 @@ +package web + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + + "adammathes.com/neko/config" +) + +func BenchmarkGzipMiddleware(b *testing.B) { + // Simulate a JSON API response + jsonPayload := `[` + strings.Repeat(`{"_id":"1","title":"Test Item","url":"https://example.com","description":"<p>This is a test description with enough content to be worth compressing in a real scenario</p>","read":false,"starred":false},`, 14) + + `{"_id":"15","title":"Last Item","url":"https://example.com/15","description":"<p>Final item</p>","read":false,"starred":false}]` + + handler := GzipMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(jsonPayload)) + })) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + req := httptest.NewRequest("GET", "/api/stream", nil) + req.Header.Set("Accept-Encoding", "gzip") + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + } +} + +func BenchmarkSecurityHeaders(b *testing.B) { + handler := SecurityHeadersMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + req := httptest.NewRequest("GET", "/", nil) + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + } +} + +func BenchmarkCSRFMiddleware(b *testing.B) { + cfg := &config.Settings{SecureCookies: false} + handler := CSRFMiddleware(cfg, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + + // Pre-generate a CSRF token by doing an initial GET + initReq := httptest.NewRequest("GET", "/", nil) + initRR := httptest.NewRecorder() + handler.ServeHTTP(initRR, initReq) + + var csrfCookie *http.Cookie + for _, c := range initRR.Result().Cookies() { + if c.Name == "csrf_token" { + csrfCookie = c + break + } + } + if csrfCookie == nil { + b.Fatal("no csrf cookie set") + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + req := httptest.NewRequest("POST", "/api/stream", nil) + req.AddCookie(csrfCookie) + req.Header.Set("X-CSRF-Token", csrfCookie.Value) + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + } +} + +func BenchmarkFullMiddlewareStack(b *testing.B) { + cfg := &config.Settings{SecureCookies: false} + inner := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.Write([]byte(`{"status":"ok"}`)) + }) + + handler := SecurityHeadersMiddleware(CSRFMiddleware(cfg, GzipMiddleware(inner))) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + req := httptest.NewRequest("GET", "/", nil) + req.Header.Set("Accept-Encoding", "gzip") + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + } +} |
