ResumeLens/internal/api/routes_test.go
2026-04-07 13:14:52 -07:00

116 lines
3.0 KiB
Go

package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/go-chi/chi/v5"
)
func buildMountedRouter() http.Handler {
r := chi.NewRouter()
Mount(r)
return r
}
func TestRoutes_7_1_1_AnalyzeEndpointExists(t *testing.T) {
resetRateLimiter()
r := buildMountedRouter()
req := httptest.NewRequest(http.MethodPost, "/api/analyze", nil)
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
if rr.Code == http.StatusNotFound {
t.Fatalf("expected /api/analyze endpoint to exist")
}
}
func TestRoutes_7_1_2_POSTMethodWorks(t *testing.T) {
resetRateLimiter()
r := buildMountedRouter()
req := httptest.NewRequest(http.MethodPost, "/api/analyze", nil)
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
if rr.Code != http.StatusBadRequest && rr.Code != http.StatusOK && rr.Code != http.StatusInternalServerError {
t.Fatalf("expected handled POST status, got %d", rr.Code)
}
}
func TestRoutes_7_1_3_GETMethodReturnsMethodNotAllowed(t *testing.T) {
resetRateLimiter()
r := buildMountedRouter()
req := httptest.NewRequest(http.MethodGet, "/api/analyze", nil)
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
if rr.Code != http.StatusMethodNotAllowed {
t.Fatalf("expected 405 for GET /api/analyze, got %d", rr.Code)
}
}
func TestRoutes_7_1_4_UnknownRoutesReturn404(t *testing.T) {
resetRateLimiter()
r := buildMountedRouter()
req := httptest.NewRequest(http.MethodPost, "/api/unknown", nil)
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
if rr.Code != http.StatusNotFound {
t.Fatalf("expected 404 for unknown route, got %d", rr.Code)
}
}
func TestRoutes_7_2_1_CORSAppliedBeforeRateLimit(t *testing.T) {
resetRateLimiter()
withFixedNow(t, timeNow())
r := buildMountedRouter()
for i := 0; i < 10; i++ {
req := httptest.NewRequest(http.MethodPost, "/api/analyze", nil)
req.Header.Set("Origin", "http://localhost:5173")
req.RemoteAddr = "127.0.0.1:12345"
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
}
blockedReq := httptest.NewRequest(http.MethodPost, "/api/analyze", nil)
blockedReq.Header.Set("Origin", "http://localhost:5173")
blockedReq.RemoteAddr = "127.0.0.1:12345"
blockedResp := httptest.NewRecorder()
r.ServeHTTP(blockedResp, blockedReq)
if blockedResp.Code != http.StatusTooManyRequests {
t.Fatalf("expected 429 after limit, got %d", blockedResp.Code)
}
if got := blockedResp.Header().Get("Access-Control-Allow-Origin"); got != "http://localhost:5173" {
t.Fatalf("expected CORS header on rate-limited response, got %q", got)
}
}
func TestRoutes_7_2_2_RateLimitingAppliedToAPIRoutes(t *testing.T) {
resetRateLimiter()
r := buildMountedRouter()
for i := 0; i < 10; i++ {
req := httptest.NewRequest(http.MethodPost, "/api/analyze", nil)
req.RemoteAddr = "127.0.0.1:12345"
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
}
req := httptest.NewRequest(http.MethodPost, "/api/analyze", nil)
req.RemoteAddr = "127.0.0.1:12345"
rr := httptest.NewRecorder()
r.ServeHTTP(rr, req)
if rr.Code != http.StatusTooManyRequests {
t.Fatalf("expected 429 on 11th /api/analyze request, got %d", rr.Code)
}
}