Files
Agent-System/internal/server/chat_history_api_test.go
T
weichen 3145550a59 feat(security): complete P0 release blocking remediation
Unify auth middleware and remove X-User-ID trust, add project_members
authorization, sandbox workspaces via resolver, and admin-only reconcile
by run_id. Introduce goose migrations with startup schema gate, fail closed
when DB unavailable outside explicit ALLOW_IN_MEMORY, bundle web/dist in
app Dockerfile, and remove frontend pseudo-login fallback.
2026-09-13 02:50:22 +00:00

141 lines
5.1 KiB
Go

package server_test
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"
"chat-agent-system/internal/bizdev"
"chat-agent-system/internal/config"
"chat-agent-system/internal/ctxmgr"
"chat-agent-system/internal/docgov"
"chat-agent-system/internal/server"
)
func TestServer_ChatHistoryAndCaseRecommendationAPIs(t *testing.T) {
cfg := &config.Config{
HTTPHost: "127.0.0.1",
HTTPPort: 8888,
DataDir: t.TempDir(),
}
svc := bizdev.MustNewService(t, cfg)
srv := server.NewServer(cfg, svc)
handler := srv.Routes()
ctx := context.Background()
sessID := "sess_api_history_001"
userID := int64(108)
// 1. 模拟写入对话消息
_ = svc.ContextManager().RecordUserMessage(ctx, sessID, userID, "user", "我们准备立项一款便携无线掌上超声,预算大约150万", "SUPPLEMENT_INFO", "EXPECTATION_HIT", nil)
_ = svc.ContextManager().RecordUserMessage(ctx, sessID, 0, "assistant", "已为您建立超声设备立项基准,预估研发周期6个月", "ADVANCE_STAGE", "EXPECTATION_HIT", nil)
// 2. 测试 GET /api/v1/chat/sessions
reqSessions := httptest.NewRequest("GET", "/api/v1/chat/sessions?user_id=108", nil)
rrSessions := httptest.NewRecorder()
handler.ServeHTTP(rrSessions, reqSessions)
if rrSessions.Code != http.StatusOK {
t.Fatalf("GET /api/v1/chat/sessions expected 200, got %d: %s", rrSessions.Code, rrSessions.Body.String())
}
var sessionList []ctxmgr.ChatSessionSummary
if err := json.Unmarshal(rrSessions.Body.Bytes(), &sessionList); err != nil {
t.Fatalf("unmarshal sessions failed: %v", err)
}
if len(sessionList) != 1 || sessionList[0].SessionID != sessID {
t.Fatalf("unexpected sessions result: %+v", sessionList)
}
t.Logf("✓ 成功查询到历史会话列表: 包含会话=%s, 消息数=%d", sessionList[0].SessionID, sessionList[0].MessageCount)
// 2b. 测试 POST /api/v1/chat/sessions
upsertBody, _ := json.Marshal(map[string]any{
"session_id": "sess_p42_u108",
"title": "便携超声立项",
"user_id": userID,
"project_id": 42,
})
reqUpsert := httptest.NewRequest("POST", "/api/v1/chat/sessions", bytes.NewReader(upsertBody))
reqUpsert.Header.Set("Content-Type", "application/json")
rrUpsert := httptest.NewRecorder()
handler.ServeHTTP(rrUpsert, reqUpsert)
if rrUpsert.Code != http.StatusOK {
t.Fatalf("POST /api/v1/chat/sessions expected 200, got %d: %s", rrUpsert.Code, rrUpsert.Body.String())
}
var upserted ctxmgr.ChatSessionSummary
if err := json.Unmarshal(rrUpsert.Body.Bytes(), &upserted); err != nil {
t.Fatalf("unmarshal upserted session failed: %v", err)
}
if upserted.SessionID != "sess_p42_u108" || upserted.Title != "便携超声立项" {
t.Fatalf("unexpected upserted session: %+v", upserted)
}
// 3. 测试 GET /api/v1/chat/messages
reqMsgs := httptest.NewRequest("GET", "/api/v1/chat/messages?session_id="+sessID, nil)
rrMsgs := httptest.NewRecorder()
handler.ServeHTTP(rrMsgs, reqMsgs)
if rrMsgs.Code != http.StatusOK {
t.Fatalf("GET /api/v1/chat/messages expected 200, got %d: %s", rrMsgs.Code, rrMsgs.Body.String())
}
var msgList []ctxmgr.ChatMessageRecord
if err := json.Unmarshal(rrMsgs.Body.Bytes(), &msgList); err != nil {
t.Fatalf("unmarshal messages failed: %v", err)
}
if len(msgList) != 2 {
t.Fatalf("expected 2 messages, got %d", len(msgList))
}
t.Logf("✓ 成功分页获取会话消息历史: 轮次数=%d, 首条内容=%s", len(msgList), msgList[0].Content)
// 4. 预置一个受控文档终态并索引为标杆案例
now := time.Now()
doc := &docgov.DocumentRecord{
DocID: "doc_benchmark_api_01",
ProjectID: 501,
TaskKey: "feasibility_reg",
Title: "无线掌上超声探头可行性评估报告",
Stage: "V0.5_feasibility",
CurrentState: docgov.StateApproved,
IsLocked: true,
ApprovedAt: &now,
AuthorName: "王总工",
}
docBody := `# 无线掌上超声探头可行性评估报告
## 概述与器械分类
主要用于临床床旁急诊腹部与浅表超声扫查,属于二类或三类医疗器械。
## 关键性能与型检预估
符合 GB 9706.1-2020 和 YY 0644 标准要求,探头无线射频满足 SRRC 与无线电合规要求。`
_, err := svc.ContextManager().IndexApprovedDocument(ctx, doc, docBody)
if err != nil {
t.Fatalf("IndexApprovedDocument failed: %v", err)
}
// 5. 测试 GET /api/v1/context/cases/recommend
reqCase := httptest.NewRequest("GET", "/api/v1/context/cases/recommend?query=便携式无线掌上超声诊断系统&limit=3&min_score=0.10", nil)
rrCase := httptest.NewRecorder()
handler.ServeHTTP(rrCase, reqCase)
if rrCase.Code != http.StatusOK {
t.Fatalf("GET /api/v1/context/cases/recommend expected 200, got %d: %s", rrCase.Code, rrCase.Body.String())
}
var cases []ctxmgr.CaseRecommendationItem
if err := json.Unmarshal(rrCase.Body.Bytes(), &cases); err != nil {
t.Fatalf("unmarshal cases failed: %v", err)
}
if len(cases) == 0 {
t.Fatalf("expected recommended cases, got 0")
}
t.Logf("✓ 成功通过 API 检索到标杆案例推荐: 案例=%s, 匹配章节=%s, 得分=%.2f, 提要=%s",
cases[0].ArtifactTitle, cases[0].SectionTitle, cases[0].SimilarityScore, cases[0].SummarySnippet)
}