//go:build integration package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "testing" "time" ) // TestNewSessionAPI 测试新的会话API func TestNewSessionAPI(t *testing.T) { t.Log("🚀 开始测试新的会话API") baseURL := "http://localhost:8020" // 1. 获取认证token token := getAuthToken(t, baseURL) if token == "" { t.Fatal("无法获取认证token") } t.Logf("✅ 获取到认证token: %s...", token[:min(20, len(token))]) // 2. 获取智能体列表 agents := getAgents(t, baseURL, token) if agents == nil { t.Fatal("无法获取智能体列表") } t.Logf("✅ 获取到 %d 个智能体", len(agents)) // 验证智能体 expectedAgents := map[string]string{ "replenish": "补货", "transfer": "调拨", "allocation": "配货", "report": "报表", } for _, agent := range agents { if expectedName, ok := expectedAgents[agent.ID]; !ok { t.Errorf("未知的智能体ID: %s", agent.ID) } else if agent.Name != expectedName { t.Errorf("智能体 %s 名称不匹配,期望: %s, 实际: %s", agent.ID, expectedName, agent.Name) } } // 3. 创建会话 sessionID := createSession(t, baseURL, token, "API集成测试会话", "replenish") if sessionID == "" { t.Fatal("无法创建会话") } t.Logf("✅ 创建会话成功: %s", sessionID) // 4. 查询会话列表 sessions := listSessions(t, baseURL, token, 1, 10, "", "") if sessions == nil { t.Fatal("无法查询会话列表") } t.Logf("✅ 查询到 %d 个会话 (总共 %d)", len(sessions.Sessions), sessions.TotalCount) // 5. 查询单个会话详情 sessionDetail := getSessionDetail(t, baseURL, token, sessionID) if sessionDetail == nil { t.Fatal("无法获取会话详情") } t.Logf("✅ 获取会话详情成功") t.Logf(" 会话ID: %s", sessionDetail.Session.ID) t.Logf(" 标题: %s", sessionDetail.Session.Title) t.Logf(" 智能体: %s", sessionDetail.Session.AgentName) t.Logf(" 状态: %s", sessionDetail.Session.Status) // 6. 更新会话 success := updateSession(t, baseURL, token, sessionID, "更新后的标题", "technical_document") if !success { t.Fatal("无法更新会话") } t.Logf("✅ 更新会话成功") // 7. 验证更新 updatedDetail := getSessionDetail(t, baseURL, token, sessionID) if updatedDetail == nil { t.Fatal("无法获取更新后的会话详情") } if updatedDetail.Session.Title != "更新后的标题" { t.Errorf("标题更新失败,期望: %s, 实际: %s", "更新后的标题", updatedDetail.Session.Title) } if updatedDetail.Session.Status != "technical_document" { t.Errorf("状态更新失败,期望: %s, 实际: %s", "technical_document", updatedDetail.Session.Status) } t.Logf("✅ 验证更新成功") // 8. 测试分页和筛选 t.Log("🔍 测试分页和筛选功能...") // 创建更多测试数据 sessionIDs := []string{} for i := 1; i <= 3; i++ { id := createSession(t, baseURL, token, fmt.Sprintf("分页测试会话 %d", i), "transfer") if id != "" { sessionIDs = append(sessionIDs, id) } } // 测试分页 page1 := listSessions(t, baseURL, token, 1, 2, "", "") if page1 != nil { t.Logf("✅ 第一页获取到 %d 个会话", len(page1.Sessions)) } // 测试标题搜索 searchResult := listSessions(t, baseURL, token, 1, 10, "分页测试", "") if searchResult != nil { t.Logf("✅ 标题搜索获取到 %d 个会话", len(searchResult.Sessions)) } // 测试状态筛选 statusResult := listSessions(t, baseURL, token, 1, 10, "", "requirement_document") if statusResult != nil { t.Logf("✅ 状态筛选获取到 %d 个需求文档状态的会话", len(statusResult.Sessions)) } // 9. 清理测试数据 t.Log("🧹 清理测试数据...") // 删除创建的会话 allSessions := listSessions(t, baseURL, token, 1, 100, "", "") if allSessions != nil { for _, session := range allSessions.Sessions { if session.ID == sessionID || contains(sessionIDs, session.ID) { deleteSession(t, baseURL, token, session.ID) t.Logf(" 删除会话: %s", session.ID) } } } t.Log("🎉 所有测试通过!") } // 辅助函数 func getAuthToken(t *testing.T, baseURL string) string { url := baseURL + "/api/auth/login" loginData := map[string]string{ "user_id": "test-user-001", "password": "password123", } jsonData, _ := json.Marshal(loginData) resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData)) if err != nil { t.Logf("登录失败: %v,使用模拟token", err) return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment" } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("登录返回状态码 %d,使用模拟token", resp.StatusCode) return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment" } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data string `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v,使用模拟token", err) return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment" } if !result.Success { t.Logf("登录失败: %s,使用模拟token", result.Message) return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment" } return result.Data } func getAgents(t *testing.T, baseURL, token string) []Agent { url := baseURL + "/api/agents" req, err := http.NewRequest("GET", url, nil) if err != nil { t.Logf("创建请求失败: %v", err) return nil } req.Header.Set("Authorization", "Bearer "+token) client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { t.Logf("HTTP请求失败: %v", err) return nil } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("HTTP状态码 %d", resp.StatusCode) return nil } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data []Agent `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v", err) return nil } if !result.Success { t.Logf("API调用失败: %s", result.Message) return nil } return result.Data } func createSession(t *testing.T, baseURL, token, title, agentName string) string { url := baseURL + "/api/session/create" sessionData := map[string]string{ "title": title, "agent_name": agentName, } jsonData, _ := json.Marshal(sessionData) req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) if err != nil { t.Logf("创建请求失败: %v", err) return "" } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { t.Logf("HTTP请求失败: %v", err) return "" } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("HTTP状态码 %d", resp.StatusCode) body, _ := io.ReadAll(resp.Body) t.Logf("响应体: %s", string(body)) return "" } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data struct { ID string `json:"id"` } `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v", err) return "" } if !result.Success { t.Logf("创建会话失败: %s", result.Message) return "" } return result.Data.ID } func listSessions(t *testing.T, baseURL, token string, page, pageSize int, title, status string) *SessionListResult { url := fmt.Sprintf("%s/api/sessions?page=%d&pageSize=%d", baseURL, page, pageSize) if title != "" { url += "&title=" + title } if status != "" { url += "&status=" + status } req, err := http.NewRequest("GET", url, nil) if err != nil { t.Logf("创建请求失败: %v", err) return nil } req.Header.Set("Authorization", "Bearer "+token) client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { t.Logf("HTTP请求失败: %v", err) return nil } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("HTTP状态码 %d", resp.StatusCode) return nil } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data *SessionListResult `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v", err) return nil } if !result.Success { t.Logf("API调用失败: %s", result.Message) return nil } return result.Data } func getSessionDetail(t *testing.T, baseURL, token, sessionID string) *SessionWithDetail { url := baseURL + "/api/session/" + sessionID req, err := http.NewRequest("GET", url, nil) if err != nil { t.Logf("创建请求失败: %v", err) return nil } req.Header.Set("Authorization", "Bearer "+token) client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { t.Logf("HTTP请求失败: %v", err) return nil } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("HTTP状态码 %d", resp.StatusCode) return nil } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data *SessionWithDetail `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v", err) return nil } if !result.Success { t.Logf("API调用失败: %s", result.Message) return nil } return result.Data } func updateSession(t *testing.T, baseURL, token, sessionID, title, status string) bool { url := baseURL + "/api/session/" + sessionID updateData := make(map[string]string) if title != "" { updateData["title"] = title } if status != "" { updateData["status"] = status } jsonData, _ := json.Marshal(updateData) req, err := http.NewRequest("PUT", url, bytes.NewBuffer(jsonData)) if err != nil { t.Logf("创建请求失败: %v", err) return false } req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { t.Logf("HTTP请求失败: %v", err) return false } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("HTTP状态码 %d", resp.StatusCode) return false } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data bool `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v", err) return false } if !result.Success { t.Logf("更新会话失败: %s", result.Message) return false } return result.Data } func deleteSession(t *testing.T, baseURL, token, sessionID string) bool { url := baseURL + "/api/session/" + sessionID req, err := http.NewRequest("DELETE", url, nil) if err != nil { t.Logf("创建请求失败: %v", err) return false } req.Header.Set("Authorization", "Bearer "+token) client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { t.Logf("HTTP请求失败: %v", err) return false } defer resp.Body.Close() if resp.StatusCode != 200 { t.Logf("HTTP状态码 %d", resp.StatusCode) return false } body, _ := io.ReadAll(resp.Body) var result struct { Success bool `json:"success"` Data bool `json:"data"` Message string `json:"message"` } if err := json.Unmarshal(body, &result); err != nil { t.Logf("解析响应失败: %v", err) return false } if !result.Success { t.Logf("删除会话失败: %s", result.Message) return false } return result.Data } // 数据结构 type Agent struct { ID string `json:"id"` Name string `json:"name"` } type Session struct { ID string `json:"id"` Title string `json:"title"` AgentName string `json:"agent_name"` Status string `json:"status"` UserID string `json:"user_id"` TenantID string `json:"tenant_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type SessionListResult struct { Sessions []*Session `json:"sessions"` TotalCount int64 `json:"total_count"` Page int `json:"page"` PageSize int `json:"page_size"` TotalPages int `json:"total_pages"` } type SessionWithDetail struct { Session *Session `json:"session"` Detail *SessionDetail `json:"detail"` HistoryCount int `json:"history_count"` } type SessionDetail struct { ID string `json:"id,omitempty"` SessionID string `json:"session_id"` RequirementDoc string `json:"requirement_doc"` TechnicalDoc string `json:"technical_doc"` CodeItems []CodeItem `json:"code_items"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type CodeItem struct { Order int `json:"order"` SelectPart string `json:"select_part"` FromPart string `json:"from_part"` WherePart string `json:"where_part"` GroupByPart string `json:"group_by_part"` OrderByPart string `json:"order_by_part"` TempTableName string `json:"temp_table_name"` Parameters map[string]interface{} `json:"parameters"` ReturnColumns map[string]string `json:"return_columns"` } // 工具函数 func min(a, b int) int { if a < b { return a } return b } func contains(slice []string, item string) bool { for _, s := range slice { if s == item { return true } } return false }