package server import ( "bufio" "bytes" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "chat-agent-system/internal/bizdev" "chat-agent-system/internal/chat" "chat-agent-system/internal/config" "chat-agent-system/internal/stream" ) func newTestServer() *Server { cfg := &config.Config{ Env: "test", AgentBackend: "stub", DataDir: "./data/test", KbDbPort: 5432, } svc := bizdev.NewService(cfg) return NewServer(cfg, svc) } func TestServer_Health(t *testing.T) { srv := newTestServer() req := httptest.NewRequest(http.MethodGet, "/api/v1/health", nil) w := httptest.NewRecorder() srv.Routes().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected status 200, got %d", w.Code) } var resp HealthResponse if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { t.Fatalf("decode response failed: %v", err) } if resp.Status != "ok" || resp.Env != "test" { t.Errorf("unexpected health response: %+v", resp) } } func TestServer_ChatBlocking(t *testing.T) { srv := newTestServer() chatReq := ChatRequest{ SessionID: "test_sess_01", Message: "查一下当前进展", ProjectName: "内窥镜研发项目", CustomerName: "水木东方", } body, _ := json.Marshal(chatReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/chat", bytes.NewReader(body)) w := httptest.NewRecorder() srv.Routes().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String()) } var resp chat.ChatResponse if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { t.Fatalf("decode chat response failed: %v", err) } if resp.ReplyText == "" { t.Errorf("expected non-empty reply text") } } func TestServer_ChatSSEStream(t *testing.T) { srv := newTestServer() chatReq := StreamChatRequest{ SessionID: "test_sess_sse", Message: "查一下当前进展", IncludeDetails: false, ProjectName: "内窥镜研发项目", CustomerName: "水木东方", } body, _ := json.Marshal(chatReq) req := httptest.NewRequest(http.MethodPost, "/api/v1/chat/stream", bytes.NewReader(body)) w := httptest.NewRecorder() srv.Routes().ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected status 200, got %d", w.Code) } contentType := w.Header().Get("Content-Type") if !strings.Contains(contentType, "text/event-stream") { t.Fatalf("expected Content-Type text/event-stream, got %s", contentType) } // 解析 SSE 事件流 scanner := bufio.NewScanner(w.Body) var currentEvent string var eventsReceived []string for scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "event: ") { currentEvent = strings.TrimPrefix(line, "event: ") } else if strings.HasPrefix(line, "data: ") { dataStr := strings.TrimPrefix(line, "data: ") var ev stream.StreamEvent if err := json.Unmarshal([]byte(dataStr), &ev); err == nil { eventsReceived = append(eventsReceived, currentEvent) } } } if len(eventsReceived) == 0 { t.Fatalf("expected to receive SSE events, got 0") } hasPhase := false hasStatus := false hasDone := false for _, et := range eventsReceived { switch et { case "phase": hasPhase = true case "status": hasStatus = true case "done": hasDone = true } } if !hasPhase { t.Errorf("expected phase event in SSE stream") } if !hasStatus { t.Errorf("expected status event in SSE stream") } if !hasDone { t.Errorf("expected done event in SSE stream") } }