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
This commit is contained in:
parent
20d94f4c90
commit
8d6346a008
2 changed files with 56 additions and 1 deletions
|
|
@ -4308,7 +4308,7 @@ if [ "$AUTO_REG_SUCCESS" != true ]; then
|
||||||
fi
|
fi
|
||||||
`, serverName, time.Now().Format("2006-01-02 15:04:05"), pulseIP,
|
`, serverName, time.Now().Format("2006-01-02 15:04:05"), pulseIP,
|
||||||
tokenName, tokenName, tokenName, tokenName, tokenName, tokenName,
|
tokenName, tokenName, tokenName, tokenName, tokenName, tokenName,
|
||||||
authToken, pulseURL, serverHost, tokenName, tokenName, storagePerms, sshKeys.ProxyPublicKey, sshKeys.SensorsPublicKey, pulseURL, pulseURL, pulseURL, pulseURL, authToken, pulseURL, authToken)
|
authToken, pulseURL, serverHost, tokenName, tokenName, storagePerms, sshKeys.ProxyPublicKey, sshKeys.SensorsPublicKey, pulseURL, pulseURL, pulseURL, pulseURL, pulseURL, pulseURL, authToken, pulseURL, authToken, pulseURL, tokenName)
|
||||||
|
|
||||||
} else { // PBS
|
} else { // PBS
|
||||||
script = fmt.Sprintf(`#!/bin/bash
|
script = fmt.Sprintf(`#!/bin/bash
|
||||||
|
|
|
||||||
55
internal/api/rate_limit_config_test.go
Normal file
55
internal/api/rate_limit_config_test.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue