Sin descripción
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

integration_api_test.go 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. //go:build integration
  2. package main
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "testing"
  10. "time"
  11. )
  12. // TestNewSessionAPI 测试新的会话API
  13. func TestNewSessionAPI(t *testing.T) {
  14. t.Log("🚀 开始测试新的会话API")
  15. baseURL := "http://localhost:8020"
  16. // 1. 获取认证token
  17. token := getAuthToken(t, baseURL)
  18. if token == "" {
  19. t.Fatal("无法获取认证token")
  20. }
  21. t.Logf("✅ 获取到认证token: %s...", token[:min(20, len(token))])
  22. // 2. 获取智能体列表
  23. agents := getAgents(t, baseURL, token)
  24. if agents == nil {
  25. t.Fatal("无法获取智能体列表")
  26. }
  27. t.Logf("✅ 获取到 %d 个智能体", len(agents))
  28. // 验证智能体
  29. expectedAgents := map[string]string{
  30. "replenish": "补货",
  31. "transfer": "调拨",
  32. "allocation": "配货",
  33. "report": "报表",
  34. }
  35. for _, agent := range agents {
  36. if expectedName, ok := expectedAgents[agent.ID]; !ok {
  37. t.Errorf("未知的智能体ID: %s", agent.ID)
  38. } else if agent.Name != expectedName {
  39. t.Errorf("智能体 %s 名称不匹配,期望: %s, 实际: %s", agent.ID, expectedName, agent.Name)
  40. }
  41. }
  42. // 3. 创建会话
  43. sessionID := createSession(t, baseURL, token, "API集成测试会话", "replenish")
  44. if sessionID == "" {
  45. t.Fatal("无法创建会话")
  46. }
  47. t.Logf("✅ 创建会话成功: %s", sessionID)
  48. // 4. 查询会话列表
  49. sessions := listSessions(t, baseURL, token, 1, 10, "", "")
  50. if sessions == nil {
  51. t.Fatal("无法查询会话列表")
  52. }
  53. t.Logf("✅ 查询到 %d 个会话 (总共 %d)", len(sessions.Sessions), sessions.TotalCount)
  54. // 5. 查询单个会话详情
  55. sessionDetail := getSessionDetail(t, baseURL, token, sessionID)
  56. if sessionDetail == nil {
  57. t.Fatal("无法获取会话详情")
  58. }
  59. t.Logf("✅ 获取会话详情成功")
  60. t.Logf(" 会话ID: %s", sessionDetail.Session.ID)
  61. t.Logf(" 标题: %s", sessionDetail.Session.Title)
  62. t.Logf(" 智能体: %s", sessionDetail.Session.AgentName)
  63. t.Logf(" 状态: %s", sessionDetail.Session.Status)
  64. // 6. 更新会话
  65. success := updateSession(t, baseURL, token, sessionID, "更新后的标题", "technical_document")
  66. if !success {
  67. t.Fatal("无法更新会话")
  68. }
  69. t.Logf("✅ 更新会话成功")
  70. // 7. 验证更新
  71. updatedDetail := getSessionDetail(t, baseURL, token, sessionID)
  72. if updatedDetail == nil {
  73. t.Fatal("无法获取更新后的会话详情")
  74. }
  75. if updatedDetail.Session.Title != "更新后的标题" {
  76. t.Errorf("标题更新失败,期望: %s, 实际: %s", "更新后的标题", updatedDetail.Session.Title)
  77. }
  78. if updatedDetail.Session.Status != "technical_document" {
  79. t.Errorf("状态更新失败,期望: %s, 实际: %s", "technical_document", updatedDetail.Session.Status)
  80. }
  81. t.Logf("✅ 验证更新成功")
  82. // 8. 测试分页和筛选
  83. t.Log("🔍 测试分页和筛选功能...")
  84. // 创建更多测试数据
  85. sessionIDs := []string{}
  86. for i := 1; i <= 3; i++ {
  87. id := createSession(t, baseURL, token, fmt.Sprintf("分页测试会话 %d", i), "transfer")
  88. if id != "" {
  89. sessionIDs = append(sessionIDs, id)
  90. }
  91. }
  92. // 测试分页
  93. page1 := listSessions(t, baseURL, token, 1, 2, "", "")
  94. if page1 != nil {
  95. t.Logf("✅ 第一页获取到 %d 个会话", len(page1.Sessions))
  96. }
  97. // 测试标题搜索
  98. searchResult := listSessions(t, baseURL, token, 1, 10, "分页测试", "")
  99. if searchResult != nil {
  100. t.Logf("✅ 标题搜索获取到 %d 个会话", len(searchResult.Sessions))
  101. }
  102. // 测试状态筛选
  103. statusResult := listSessions(t, baseURL, token, 1, 10, "", "requirement_document")
  104. if statusResult != nil {
  105. t.Logf("✅ 状态筛选获取到 %d 个需求文档状态的会话", len(statusResult.Sessions))
  106. }
  107. // 9. 清理测试数据
  108. t.Log("🧹 清理测试数据...")
  109. // 删除创建的会话
  110. allSessions := listSessions(t, baseURL, token, 1, 100, "", "")
  111. if allSessions != nil {
  112. for _, session := range allSessions.Sessions {
  113. if session.ID == sessionID || contains(sessionIDs, session.ID) {
  114. deleteSession(t, baseURL, token, session.ID)
  115. t.Logf(" 删除会话: %s", session.ID)
  116. }
  117. }
  118. }
  119. t.Log("🎉 所有测试通过!")
  120. }
  121. // 辅助函数
  122. func getAuthToken(t *testing.T, baseURL string) string {
  123. url := baseURL + "/api/auth/login"
  124. loginData := map[string]string{
  125. "user_id": "test-user-001",
  126. "password": "password123",
  127. }
  128. jsonData, _ := json.Marshal(loginData)
  129. resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
  130. if err != nil {
  131. t.Logf("登录失败: %v,使用模拟token", err)
  132. return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment"
  133. }
  134. defer resp.Body.Close()
  135. if resp.StatusCode != 200 {
  136. t.Logf("登录返回状态码 %d,使用模拟token", resp.StatusCode)
  137. return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment"
  138. }
  139. body, _ := io.ReadAll(resp.Body)
  140. var result struct {
  141. Success bool `json:"success"`
  142. Data string `json:"data"`
  143. Message string `json:"message"`
  144. }
  145. if err := json.Unmarshal(body, &result); err != nil {
  146. t.Logf("解析响应失败: %v,使用模拟token", err)
  147. return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment"
  148. }
  149. if !result.Success {
  150. t.Logf("登录失败: %s,使用模拟token", result.Message)
  151. return "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidGVzdCIsInVzZXJuYW1lIjoidGVzdCIsImV4cCI6MTc3MTE0MTQyNywiaWF0IjoxNzE4NDIxNDI3fQ.SimulatedTokenForDevelopment"
  152. }
  153. return result.Data
  154. }
  155. func getAgents(t *testing.T, baseURL, token string) []Agent {
  156. url := baseURL + "/api/agents"
  157. req, err := http.NewRequest("GET", url, nil)
  158. if err != nil {
  159. t.Logf("创建请求失败: %v", err)
  160. return nil
  161. }
  162. req.Header.Set("Authorization", "Bearer "+token)
  163. client := &http.Client{Timeout: 10 * time.Second}
  164. resp, err := client.Do(req)
  165. if err != nil {
  166. t.Logf("HTTP请求失败: %v", err)
  167. return nil
  168. }
  169. defer resp.Body.Close()
  170. if resp.StatusCode != 200 {
  171. t.Logf("HTTP状态码 %d", resp.StatusCode)
  172. return nil
  173. }
  174. body, _ := io.ReadAll(resp.Body)
  175. var result struct {
  176. Success bool `json:"success"`
  177. Data []Agent `json:"data"`
  178. Message string `json:"message"`
  179. }
  180. if err := json.Unmarshal(body, &result); err != nil {
  181. t.Logf("解析响应失败: %v", err)
  182. return nil
  183. }
  184. if !result.Success {
  185. t.Logf("API调用失败: %s", result.Message)
  186. return nil
  187. }
  188. return result.Data
  189. }
  190. func createSession(t *testing.T, baseURL, token, title, agentName string) string {
  191. url := baseURL + "/api/session/create"
  192. sessionData := map[string]string{
  193. "title": title,
  194. "agent_name": agentName,
  195. }
  196. jsonData, _ := json.Marshal(sessionData)
  197. req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
  198. if err != nil {
  199. t.Logf("创建请求失败: %v", err)
  200. return ""
  201. }
  202. req.Header.Set("Authorization", "Bearer "+token)
  203. req.Header.Set("Content-Type", "application/json")
  204. client := &http.Client{Timeout: 10 * time.Second}
  205. resp, err := client.Do(req)
  206. if err != nil {
  207. t.Logf("HTTP请求失败: %v", err)
  208. return ""
  209. }
  210. defer resp.Body.Close()
  211. if resp.StatusCode != 200 {
  212. t.Logf("HTTP状态码 %d", resp.StatusCode)
  213. body, _ := io.ReadAll(resp.Body)
  214. t.Logf("响应体: %s", string(body))
  215. return ""
  216. }
  217. body, _ := io.ReadAll(resp.Body)
  218. var result struct {
  219. Success bool `json:"success"`
  220. Data struct {
  221. ID string `json:"id"`
  222. } `json:"data"`
  223. Message string `json:"message"`
  224. }
  225. if err := json.Unmarshal(body, &result); err != nil {
  226. t.Logf("解析响应失败: %v", err)
  227. return ""
  228. }
  229. if !result.Success {
  230. t.Logf("创建会话失败: %s", result.Message)
  231. return ""
  232. }
  233. return result.Data.ID
  234. }
  235. func listSessions(t *testing.T, baseURL, token string, page, pageSize int, title, status string) *SessionListResult {
  236. url := fmt.Sprintf("%s/api/sessions?page=%d&pageSize=%d", baseURL, page, pageSize)
  237. if title != "" {
  238. url += "&title=" + title
  239. }
  240. if status != "" {
  241. url += "&status=" + status
  242. }
  243. req, err := http.NewRequest("GET", url, nil)
  244. if err != nil {
  245. t.Logf("创建请求失败: %v", err)
  246. return nil
  247. }
  248. req.Header.Set("Authorization", "Bearer "+token)
  249. client := &http.Client{Timeout: 10 * time.Second}
  250. resp, err := client.Do(req)
  251. if err != nil {
  252. t.Logf("HTTP请求失败: %v", err)
  253. return nil
  254. }
  255. defer resp.Body.Close()
  256. if resp.StatusCode != 200 {
  257. t.Logf("HTTP状态码 %d", resp.StatusCode)
  258. return nil
  259. }
  260. body, _ := io.ReadAll(resp.Body)
  261. var result struct {
  262. Success bool `json:"success"`
  263. Data *SessionListResult `json:"data"`
  264. Message string `json:"message"`
  265. }
  266. if err := json.Unmarshal(body, &result); err != nil {
  267. t.Logf("解析响应失败: %v", err)
  268. return nil
  269. }
  270. if !result.Success {
  271. t.Logf("API调用失败: %s", result.Message)
  272. return nil
  273. }
  274. return result.Data
  275. }
  276. func getSessionDetail(t *testing.T, baseURL, token, sessionID string) *SessionWithDetail {
  277. url := baseURL + "/api/session/" + sessionID
  278. req, err := http.NewRequest("GET", url, nil)
  279. if err != nil {
  280. t.Logf("创建请求失败: %v", err)
  281. return nil
  282. }
  283. req.Header.Set("Authorization", "Bearer "+token)
  284. client := &http.Client{Timeout: 10 * time.Second}
  285. resp, err := client.Do(req)
  286. if err != nil {
  287. t.Logf("HTTP请求失败: %v", err)
  288. return nil
  289. }
  290. defer resp.Body.Close()
  291. if resp.StatusCode != 200 {
  292. t.Logf("HTTP状态码 %d", resp.StatusCode)
  293. return nil
  294. }
  295. body, _ := io.ReadAll(resp.Body)
  296. var result struct {
  297. Success bool `json:"success"`
  298. Data *SessionWithDetail `json:"data"`
  299. Message string `json:"message"`
  300. }
  301. if err := json.Unmarshal(body, &result); err != nil {
  302. t.Logf("解析响应失败: %v", err)
  303. return nil
  304. }
  305. if !result.Success {
  306. t.Logf("API调用失败: %s", result.Message)
  307. return nil
  308. }
  309. return result.Data
  310. }
  311. func updateSession(t *testing.T, baseURL, token, sessionID, title, status string) bool {
  312. url := baseURL + "/api/session/" + sessionID
  313. updateData := make(map[string]string)
  314. if title != "" {
  315. updateData["title"] = title
  316. }
  317. if status != "" {
  318. updateData["status"] = status
  319. }
  320. jsonData, _ := json.Marshal(updateData)
  321. req, err := http.NewRequest("PUT", url, bytes.NewBuffer(jsonData))
  322. if err != nil {
  323. t.Logf("创建请求失败: %v", err)
  324. return false
  325. }
  326. req.Header.Set("Authorization", "Bearer "+token)
  327. req.Header.Set("Content-Type", "application/json")
  328. client := &http.Client{Timeout: 10 * time.Second}
  329. resp, err := client.Do(req)
  330. if err != nil {
  331. t.Logf("HTTP请求失败: %v", err)
  332. return false
  333. }
  334. defer resp.Body.Close()
  335. if resp.StatusCode != 200 {
  336. t.Logf("HTTP状态码 %d", resp.StatusCode)
  337. return false
  338. }
  339. body, _ := io.ReadAll(resp.Body)
  340. var result struct {
  341. Success bool `json:"success"`
  342. Data bool `json:"data"`
  343. Message string `json:"message"`
  344. }
  345. if err := json.Unmarshal(body, &result); err != nil {
  346. t.Logf("解析响应失败: %v", err)
  347. return false
  348. }
  349. if !result.Success {
  350. t.Logf("更新会话失败: %s", result.Message)
  351. return false
  352. }
  353. return result.Data
  354. }
  355. func deleteSession(t *testing.T, baseURL, token, sessionID string) bool {
  356. url := baseURL + "/api/session/" + sessionID
  357. req, err := http.NewRequest("DELETE", url, nil)
  358. if err != nil {
  359. t.Logf("创建请求失败: %v", err)
  360. return false
  361. }
  362. req.Header.Set("Authorization", "Bearer "+token)
  363. client := &http.Client{Timeout: 10 * time.Second}
  364. resp, err := client.Do(req)
  365. if err != nil {
  366. t.Logf("HTTP请求失败: %v", err)
  367. return false
  368. }
  369. defer resp.Body.Close()
  370. if resp.StatusCode != 200 {
  371. t.Logf("HTTP状态码 %d", resp.StatusCode)
  372. return false
  373. }
  374. body, _ := io.ReadAll(resp.Body)
  375. var result struct {
  376. Success bool `json:"success"`
  377. Data bool `json:"data"`
  378. Message string `json:"message"`
  379. }
  380. if err := json.Unmarshal(body, &result); err != nil {
  381. t.Logf("解析响应失败: %v", err)
  382. return false
  383. }
  384. if !result.Success {
  385. t.Logf("删除会话失败: %s", result.Message)
  386. return false
  387. }
  388. return result.Data
  389. }
  390. // 数据结构
  391. type Agent struct {
  392. ID string `json:"id"`
  393. Name string `json:"name"`
  394. }
  395. type Session struct {
  396. ID string `json:"id"`
  397. Title string `json:"title"`
  398. AgentName string `json:"agent_name"`
  399. Status string `json:"status"`
  400. UserID string `json:"user_id"`
  401. TenantID string `json:"tenant_id"`
  402. CreatedAt time.Time `json:"created_at"`
  403. UpdatedAt time.Time `json:"updated_at"`
  404. }
  405. type SessionListResult struct {
  406. Sessions []*Session `json:"sessions"`
  407. TotalCount int64 `json:"total_count"`
  408. Page int `json:"page"`
  409. PageSize int `json:"page_size"`
  410. TotalPages int `json:"total_pages"`
  411. }
  412. type SessionWithDetail struct {
  413. Session *Session `json:"session"`
  414. Detail *SessionDetail `json:"detail"`
  415. HistoryCount int `json:"history_count"`
  416. }
  417. type SessionDetail struct {
  418. ID string `json:"id,omitempty"`
  419. SessionID string `json:"session_id"`
  420. RequirementDoc string `json:"requirement_doc"`
  421. TechnicalDoc string `json:"technical_doc"`
  422. CodeItems []CodeItem `json:"code_items"`
  423. CreatedAt time.Time `json:"created_at"`
  424. UpdatedAt time.Time `json:"updated_at"`
  425. }
  426. type CodeItem struct {
  427. Order int `json:"order"`
  428. SelectPart string `json:"select_part"`
  429. FromPart string `json:"from_part"`
  430. WherePart string `json:"where_part"`
  431. GroupByPart string `json:"group_by_part"`
  432. OrderByPart string `json:"order_by_part"`
  433. TempTableName string `json:"temp_table_name"`
  434. Parameters map[string]interface{} `json:"parameters"`
  435. ReturnColumns map[string]string `json:"return_columns"`
  436. }
  437. // 工具函数
  438. func min(a, b int) int {
  439. if a < b {
  440. return a
  441. }
  442. return b
  443. }
  444. func contains(slice []string, item string) bool {
  445. for _, s := range slice {
  446. if s == item {
  447. return true
  448. }
  449. }
  450. return false
  451. }