- Priority 1: Test NewSendEmailTask + NewSendPushTask (5 tests) - Priority 2: Test customHTTPErrorHandler — all 15+ branches (21 tests) - Priority 3: Extract Enqueuer interface + payload builders in worker pkg (5 tests) - Priority 4: Extract ClassifyFile/ComputeRelPath in migrate-encrypt (6 tests) - Priority 5: Define Handler interfaces, refactor to accept them, mock-based tests (14 tests) - Fix .gitignore: /worker instead of worker to stop ignoring internal/worker/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
201 lines
4.8 KiB
Go
201 lines
4.8 KiB
Go
package router
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/treytartt/honeydue-api/internal/monitoring"
|
|
)
|
|
|
|
// --- CorsOrigins ---
|
|
|
|
func TestCorsOrigins_Debug(t *testing.T) {
|
|
origins := CorsOrigins(true, nil)
|
|
if len(origins) != 8 {
|
|
t.Errorf("len = %d, want 8", len(origins))
|
|
}
|
|
found := false
|
|
for _, o := range origins {
|
|
if o == "http://localhost:3000" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected localhost:3000 in debug origins")
|
|
}
|
|
}
|
|
|
|
func TestCorsOrigins_ProductionConfigured(t *testing.T) {
|
|
custom := []string{"https://example.com"}
|
|
origins := CorsOrigins(false, custom)
|
|
if len(origins) != 1 || origins[0] != "https://example.com" {
|
|
t.Errorf("got %v, want [https://example.com]", origins)
|
|
}
|
|
}
|
|
|
|
func TestCorsOrigins_ProductionDefault(t *testing.T) {
|
|
origins := CorsOrigins(false, nil)
|
|
if len(origins) != 3 {
|
|
t.Errorf("len = %d, want 3", len(origins))
|
|
}
|
|
found := false
|
|
for _, o := range origins {
|
|
if o == "https://myhoneydue.com" {
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("expected myhoneydue.com in default origins")
|
|
}
|
|
}
|
|
|
|
// --- ShouldSkipTimeout ---
|
|
|
|
func TestShouldSkipTimeout_AdminHost_True(t *testing.T) {
|
|
if !ShouldSkipTimeout("/some/path", "admin.example.com", "admin.example.com") {
|
|
t.Error("expected true for admin host")
|
|
}
|
|
}
|
|
|
|
func TestShouldSkipTimeout_NextPath_True(t *testing.T) {
|
|
if !ShouldSkipTimeout("/_next/static/chunk.js", "app.example.com", "admin.example.com") {
|
|
t.Error("expected true for _next path")
|
|
}
|
|
}
|
|
|
|
func TestShouldSkipTimeout_WsPath_True(t *testing.T) {
|
|
if !ShouldSkipTimeout("/api/events/ws", "app.example.com", "admin.example.com") {
|
|
t.Error("expected true for /ws path")
|
|
}
|
|
}
|
|
|
|
func TestShouldSkipTimeout_NormalPath_False(t *testing.T) {
|
|
if ShouldSkipTimeout("/api/tasks/", "app.example.com", "admin.example.com") {
|
|
t.Error("expected false for normal path")
|
|
}
|
|
}
|
|
|
|
func TestShouldSkipTimeout_EmptyAdminHost_False(t *testing.T) {
|
|
if ShouldSkipTimeout("/api/tasks/", "admin.example.com", "") {
|
|
t.Error("expected false when admin host is empty")
|
|
}
|
|
}
|
|
|
|
// --- ShouldSkipBodyLimit ---
|
|
|
|
func TestShouldSkipBodyLimit_Webhook_True(t *testing.T) {
|
|
if !ShouldSkipBodyLimit("/api/subscription/webhook/apple/") {
|
|
t.Error("expected true for webhook path")
|
|
}
|
|
}
|
|
|
|
func TestShouldSkipBodyLimit_Normal_False(t *testing.T) {
|
|
if ShouldSkipBodyLimit("/api/tasks/") {
|
|
t.Error("expected false for normal path")
|
|
}
|
|
}
|
|
|
|
// --- ShouldSkipGzip ---
|
|
|
|
func TestShouldSkipGzip_Media_True(t *testing.T) {
|
|
if !ShouldSkipGzip("/api/media/document/123") {
|
|
t.Error("expected true for media path")
|
|
}
|
|
}
|
|
|
|
func TestShouldSkipGzip_Api_False(t *testing.T) {
|
|
if ShouldSkipGzip("/api/tasks/") {
|
|
t.Error("expected false for non-media path")
|
|
}
|
|
}
|
|
|
|
// --- ParseEndpoint ---
|
|
|
|
func TestParseEndpoint_MethodAndPath(t *testing.T) {
|
|
method, path := ParseEndpoint("GET /api/tasks/")
|
|
if method != "GET" || path != "/api/tasks/" {
|
|
t.Errorf("got (%q, %q), want (GET, /api/tasks/)", method, path)
|
|
}
|
|
}
|
|
|
|
func TestParseEndpoint_NoSpace(t *testing.T) {
|
|
method, path := ParseEndpoint("GET")
|
|
if method != "GET" || path != "" {
|
|
t.Errorf("got (%q, %q), want (GET, \"\")", method, path)
|
|
}
|
|
}
|
|
|
|
// --- AllowedProxyHosts ---
|
|
|
|
func TestAllowedProxyHosts_WithAdmin(t *testing.T) {
|
|
hosts := AllowedProxyHosts("admin.example.com")
|
|
if len(hosts) != 5 {
|
|
t.Errorf("len = %d, want 5", len(hosts))
|
|
}
|
|
if hosts[0] != "admin.example.com" {
|
|
t.Errorf("first host = %q, want admin.example.com", hosts[0])
|
|
}
|
|
}
|
|
|
|
func TestAllowedProxyHosts_WithoutAdmin(t *testing.T) {
|
|
hosts := AllowedProxyHosts("")
|
|
if len(hosts) != 4 {
|
|
t.Errorf("len = %d, want 4", len(hosts))
|
|
}
|
|
}
|
|
|
|
// --- DetermineAdminRoute ---
|
|
|
|
func TestDetermineAdminRoute_Admin_Redirect(t *testing.T) {
|
|
got := DetermineAdminRoute("/admin/dashboard")
|
|
if got != "redirect" {
|
|
t.Errorf("got %q, want redirect", got)
|
|
}
|
|
}
|
|
|
|
func TestDetermineAdminRoute_Api_Passthrough(t *testing.T) {
|
|
got := DetermineAdminRoute("/api/tasks/")
|
|
if got != "passthrough" {
|
|
t.Errorf("got %q, want passthrough", got)
|
|
}
|
|
}
|
|
|
|
func TestDetermineAdminRoute_Other_Proxy(t *testing.T) {
|
|
got := DetermineAdminRoute("/dashboard")
|
|
if got != "proxy" {
|
|
t.Errorf("got %q, want proxy", got)
|
|
}
|
|
}
|
|
|
|
// --- FormatPrometheusMetrics ---
|
|
|
|
func TestFormatPrometheusMetrics_Output(t *testing.T) {
|
|
stats := monitoring.HTTPStats{
|
|
RequestsTotal: 100,
|
|
RequestsPerMinute: 10.5,
|
|
ErrorRate: 0.05,
|
|
ByStatusCode: map[int]int64{200: 90, 500: 10},
|
|
ByEndpoint: map[string]monitoring.EndpointStats{
|
|
"GET /api/tasks/": {Count: 50, AvgLatencyMs: 12.5, P95LatencyMs: 45.0},
|
|
},
|
|
}
|
|
|
|
output := FormatPrometheusMetrics(stats)
|
|
|
|
// Check key sections exist
|
|
checks := []string{
|
|
"http_requests_total",
|
|
"http_endpoint_requests_total",
|
|
"http_request_duration_ms",
|
|
"http_error_rate",
|
|
"http_requests_per_minute",
|
|
`method="GET"`,
|
|
`path="/api/tasks/"`,
|
|
}
|
|
for _, check := range checks {
|
|
if !strings.Contains(output, check) {
|
|
t.Errorf("output missing %q", check)
|
|
}
|
|
}
|
|
}
|