Pulse/internal/api/rate_limit_config_test.go
rcourtman 8d6346a008 test: add X-RateLimit-Limit header regression test
Add regression test for PR #575 to ensure rate limit headers are formatted
as decimal strings (e.g., "10") instead of Unicode control characters.

Also fixes pre-existing fmt.Sprintf argument count mismatch in PVE setup
script (internal/api/config_handlers.go:3077). The template had 28 format
specifiers (excluding %%s escape sequence) but was only receiving 24
arguments. Added missing pulseURL and tokenName arguments to match template.

Related: #575
2025-10-20 15:10:59 +00:00

55 lines
1.6 KiB
Go

package api
import (
"net/http"
"net/http/httptest"
"strconv"
"testing"
)
func TestUniversalRateLimitMiddleware_HeaderFormat(t *testing.T) {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
middleware := UniversalRateLimitMiddleware(handler)
limiter := GetRateLimiterForEndpoint("/api/login", http.MethodPost)
testIP := "203.0.113.55"
t.Cleanup(func() {
ResetRateLimitForIP(testIP)
})
makeRequest := func() *http.Request {
req := httptest.NewRequest(http.MethodPost, "/api/login", nil)
req.RemoteAddr = testIP + ":12345"
return req
}
// Make requests up to the limit - all should succeed
for i := 0; i < limiter.limit; i++ {
rr := httptest.NewRecorder()
middleware.ServeHTTP(rr, makeRequest())
if rr.Code != http.StatusOK {
t.Fatalf("expected OK while under limit, got %d on request %d", rr.Code, i+1)
}
}
// Next request should trigger rate limit
rr := httptest.NewRecorder()
middleware.ServeHTTP(rr, makeRequest())
if rr.Code != http.StatusTooManyRequests {
t.Fatalf("expected rate-limit status, got %d", rr.Code)
}
// Verify X-RateLimit-Limit header is a proper decimal string
limitHeader := rr.Result().Header.Get("X-RateLimit-Limit")
expected := strconv.Itoa(limiter.limit)
if limitHeader != expected {
t.Fatalf("expected X-RateLimit-Limit %q, got %q", expected, limitHeader)
}
// Verify the header parses as a valid integer (not a control character)
if _, err := strconv.Atoi(limitHeader); err != nil {
t.Fatalf("header %q should parse as decimal: %v", limitHeader, err)
}
}