All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Add auth-svc /validate endpoint for token checking Add chat-svc with auth client and Redis task queue Add worker-svc chat handler for task processing Co-Authored-By: Claude Code <claude@anthropic.com>
169 lines
4.2 KiB
Go
169 lines
4.2 KiB
Go
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())
|
|
}
|
|
}
|