package handlers import ( "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/go-chi/chi/v5" "git.threesix.ai/jordan/sp4-debug-1770477266/pkg/app" "git.threesix.ai/jordan/sp4-debug-1770477266/pkg/auth" "git.threesix.ai/jordan/sp4-debug-1770477266/pkg/logging" ) func newTestValidateHandler() *Validate { validator := auth.NewJWTValidator(auth.JWTConfig{ Secret: []byte("test-secret"), Issuer: "sp4-debug-1770477266", }) return NewValidate(validator, logging.Nop()) } func generateTestToken(t *testing.T, user *auth.User) string { t.Helper() token, err := auth.GenerateTokenWithIssuer( []byte("test-secret"), user, time.Hour, "sp4-debug-1770477266", "", ) if err != nil { t.Fatalf("failed to generate token: %v", err) } return token } func TestValidate_Check_ValidToken(t *testing.T) { handler := newTestValidateHandler() user := &auth.User{ ID: "user-123", Email: "test@example.com", Roles: []string{"admin"}, Scopes: []string{"read", "write"}, } token := generateTestToken(t, user) r := chi.NewRouter() r.Post("/api/auth-svc/validate", app.Wrap(handler.Check)) req := httptest.NewRequest(http.MethodPost, "/api/auth-svc/validate", nil) req.Header.Set("Authorization", "Bearer "+token) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d: %s", w.Code, w.Body.String()) } var resp map[string]any if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { t.Fatalf("failed to decode response: %v", err) } data, ok := resp["data"].(map[string]any) if !ok { t.Fatal("expected 'data' field in response") } if data["user_id"] != "user-123" { t.Errorf("expected user_id 'user-123', got %v", data["user_id"]) } if data["email"] != "test@example.com" { t.Errorf("expected email 'test@example.com', got %v", data["email"]) } } func TestValidate_Check_MissingToken(t *testing.T) { handler := newTestValidateHandler() r := chi.NewRouter() r.Post("/api/auth-svc/validate", app.Wrap(handler.Check)) req := httptest.NewRequest(http.MethodPost, "/api/auth-svc/validate", nil) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusUnauthorized { t.Errorf("expected status 401, got %d: %s", w.Code, w.Body.String()) } } func TestValidate_Check_InvalidToken(t *testing.T) { handler := newTestValidateHandler() r := chi.NewRouter() r.Post("/api/auth-svc/validate", app.Wrap(handler.Check)) req := httptest.NewRequest(http.MethodPost, "/api/auth-svc/validate", nil) req.Header.Set("Authorization", "Bearer invalid-token") w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusUnauthorized { t.Errorf("expected status 401, got %d: %s", w.Code, w.Body.String()) } } func TestValidate_Check_ExpiredToken(t *testing.T) { handler := newTestValidateHandler() user := &auth.User{ID: "user-123", Email: "test@example.com"} // Generate token that's already expired token, err := auth.GenerateTokenWithIssuer( []byte("test-secret"), user, -time.Hour, // negative duration = expired "sp4-debug-1770477266", "", ) if err != nil { t.Fatalf("failed to generate token: %v", err) } r := chi.NewRouter() r.Post("/api/auth-svc/validate", app.Wrap(handler.Check)) req := httptest.NewRequest(http.MethodPost, "/api/auth-svc/validate", nil) req.Header.Set("Authorization", "Bearer "+token) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusUnauthorized { t.Errorf("expected status 401, got %d: %s", w.Code, w.Body.String()) } } func TestValidate_Check_WrongSecret(t *testing.T) { handler := newTestValidateHandler() user := &auth.User{ID: "user-123"} // Generate token with different secret token, err := auth.GenerateTokenWithIssuer( []byte("wrong-secret"), user, time.Hour, "sp4-debug-1770477266", "", ) if err != nil { t.Fatalf("failed to generate token: %v", err) } r := chi.NewRouter() r.Post("/api/auth-svc/validate", app.Wrap(handler.Check)) req := httptest.NewRequest(http.MethodPost, "/api/auth-svc/validate", nil) req.Header.Set("Authorization", "Bearer "+token) w := httptest.NewRecorder() r.ServeHTTP(w, req) if w.Code != http.StatusUnauthorized { t.Errorf("expected status 401, got %d: %s", w.Code, w.Body.String()) } }