package server_test import ( "bytes" "encoding/json" "net/http" "testing" "chat-agent-system/internal/auth" ) func adminToken(t *testing.T, baseURL string) string { t.Helper() body, _ := json.Marshal(map[string]string{"username": "admin", "password": "admin123"}) resp, err := http.Post(baseURL+"/api/v1/auth/login", "application/json", bytes.NewReader(body)) if err != nil { t.Fatalf("admin login: %v", err) } defer resp.Body.Close() var session auth.SessionInfo if err := json.NewDecoder(resp.Body).Decode(&session); err != nil { t.Fatalf("decode admin session: %v", err) } return session.Token } func TestAuthHandlers_DisabledUserTokenReturns401(t *testing.T) { ts, authSvc := setupTestServer(t) loginBody, _ := json.Marshal(map[string]string{"username": "zhanggong", "password": "123456"}) resp, err := http.Post(ts.URL+"/api/v1/auth/login", "application/json", bytes.NewReader(loginBody)) if err != nil { t.Fatalf("user login: %v", err) } if resp.StatusCode != http.StatusOK { t.Fatalf("expected engineer login 200, got %d", resp.StatusCode) } var userSession auth.SessionInfo _ = json.NewDecoder(resp.Body).Decode(&userSession) adminTok := adminToken(t, ts.URL) disableBody, _ := json.Marshal(map[string]string{"status": string(auth.StatusDisabled)}) req, _ := http.NewRequest(http.MethodPut, ts.URL+"/api/v1/admin/users/2/status", bytes.NewReader(disableBody)) req.Header.Set("Authorization", "Bearer "+adminTok) req.Header.Set("Content-Type", "application/json") client := &http.Client{} disableResp, err := client.Do(req) if err != nil { t.Fatalf("disable user: %v", err) } disableResp.Body.Close() if disableResp.StatusCode != http.StatusOK { t.Fatalf("expected disable 200, got %d", disableResp.StatusCode) } meReq, _ := http.NewRequest(http.MethodGet, ts.URL+"/api/v1/auth/me", nil) meReq.Header.Set("Authorization", "Bearer "+userSession.Token) meResp, err := client.Do(meReq) if err != nil { t.Fatalf("me after disable: %v", err) } defer meResp.Body.Close() if meResp.StatusCode != http.StatusUnauthorized { t.Fatalf("expected 401 after disable, got %d", meResp.StatusCode) } u, err := authSvc.GetUserByID(t.Context(), 2) if err != nil || u.Status != auth.StatusDisabled { t.Fatalf("user should remain disabled in store") } } func TestAuthHandlers_AdminListRoles(t *testing.T) { ts, _ := setupTestServer(t) req, _ := http.NewRequest(http.MethodGet, ts.URL+"/api/v1/admin/roles", nil) req.Header.Set("Authorization", "Bearer "+adminToken(t, ts.URL)) resp, err := (&http.Client{}).Do(req) if err != nil { t.Fatalf("list roles: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("expected 200, got %d", resp.StatusCode) } var body map[string]any if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { t.Fatalf("decode: %v", err) } roles, ok := body["roles"].([]any) if !ok || len(roles) == 0 { t.Fatalf("expected roles array, got %v", body["roles"]) } } func TestAuthHandlers_ListSessions(t *testing.T) { ts, _ := setupTestServer(t) tok := adminToken(t, ts.URL) req, _ := http.NewRequest(http.MethodGet, ts.URL+"/api/v1/auth/sessions", nil) req.Header.Set("Authorization", "Bearer "+tok) resp, err := (&http.Client{}).Do(req) if err != nil { t.Fatalf("list sessions: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("expected 200, got %d", resp.StatusCode) } var body map[string]any _ = json.NewDecoder(resp.Body).Decode(&body) sessions, ok := body["sessions"].([]any) if !ok { t.Fatalf("expected sessions array") } if len(sessions) == 0 { t.Fatal("expected at least one active session") } } func TestAuthHandlers_LoginReturnsCapabilitiesFallback(t *testing.T) { ts, _ := setupTestServer(t) req, _ := http.NewRequest(http.MethodGet, ts.URL+"/api/v1/auth/me", nil) req.Header.Set("Authorization", "Bearer "+adminToken(t, ts.URL)) resp, err := (&http.Client{}).Do(req) if err != nil { t.Fatalf("me: %v", err) } defer resp.Body.Close() var body map[string]any if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { t.Fatalf("decode: %v", err) } caps, ok := body["capabilities"].([]any) if !ok || len(caps) == 0 { t.Fatalf("expected non-empty capabilities fallback for admin, got %v", body["capabilities"]) } }