aboutsummaryrefslogtreecommitdiffstats
path: root/web/web_bench_test.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-02-16 18:15:47 +0000
committerClaude <noreply@anthropic.com>2026-02-16 18:15:47 +0000
commitd4caf45b2b9ea6a3276de792cf6f73085e66b1ae (patch)
tree3a8b7b1d9277ba0db4c946fea43043d65220fd8d /web/web_bench_test.go
parentc9c5def76c3a3340373143f846454b795d296c82 (diff)
downloadneko-d4caf45b2b9ea6a3276de792cf6f73085e66b1ae.tar.gz
neko-d4caf45b2b9ea6a3276de792cf6f73085e66b1ae.tar.bz2
neko-d4caf45b2b9ea6a3276de792cf6f73085e66b1ae.zip
Add performance benchmarks, stress tests, and frontend perf tests
Go benchmarks cover item CRUD/filter/sanitization, API endpoints (stream, item update, feed list), middleware stack (gzip, security headers, CSRF), and crawler pipeline (feed parsing, mocked crawl). Stress tests verify concurrent reads/writes and large dataset handling. Frontend perf tests measure template generation, DOM insertion, and store event throughput. New Makefile targets: bench, bench-short, stress, test-perf. https://claude.ai/code/session_01ChDVWFDrQoFjMYHpaLGr9s
Diffstat (limited to 'web/web_bench_test.go')
-rw-r--r--web/web_bench_test.go92
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)
+ }
+}