From ec8555d44bd262539aa642ddc5eed5878283dd67 Mon Sep 17 00:00:00 2001 From: hhs <386998068@qq.com> Date: Sun, 14 Jun 2026 17:36:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=BC=96=E5=86=99=20Session=20Manager?= =?UTF-8?q?=20=E6=96=B0=E6=96=B9=E6=B3=95=E6=B5=8B=E8=AF=95=EF=BC=88ListBy?= =?UTF-8?q?User=20=E5=88=86=E9=A1=B5=E3=80=81UpdateTitle=E3=80=81=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=A0=87=E9=A2=98=E7=94=9F=E6=88=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/session/memory_test.go | 195 ++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/backend/internal/session/memory_test.go b/backend/internal/session/memory_test.go index eb37b73..ba670f0 100644 --- a/backend/internal/session/memory_test.go +++ b/backend/internal/session/memory_test.go @@ -284,3 +284,198 @@ func TestActiveCount(t *testing.T) { t.Errorf("ActiveCount = %d, want 2", m.ActiveCount()) } } + +func TestCreateWithUserID(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + id, err := m.Create(ctx, "user-123", models.DefaultConfig()) + if err != nil { + t.Fatalf("Create: %v", err) + } + + sess, err := m.Get(ctx, id) + if err != nil { + t.Fatalf("Get: %v", err) + } + if sess.UserID != "user-123" { + t.Errorf("UserID = %q, want %q", sess.UserID, "user-123") + } + if sess.Title != models.DefaultSessionTitle { + t.Errorf("Title = %q, want %q", sess.Title, models.DefaultSessionTitle) + } + if sess.UpdatedAt.IsZero() { + t.Error("UpdatedAt should not be zero") + } +} + +func TestUpdateTitle(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + id, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + + if err := m.UpdateTitle(ctx, id, "自定义标题"); err != nil { + t.Fatalf("UpdateTitle: %v", err) + } + + sess, _ := m.Get(ctx, id) + if sess.Title != "自定义标题" { + t.Errorf("Title = %q, want %q", sess.Title, "自定义标题") + } +} + +func TestUpdateTitleNotFound(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + err := m.UpdateTitle(ctx, "nonexistent", "标题") + if err != ErrSessionNotFound { + t.Errorf("UpdateTitle nonexistent: err = %v, want ErrSessionNotFound", err) + } +} + +func TestAutoTitleOnFirstMessage(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + id, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + + // 首条 user 消息应自动更新标题 + m.AppendMessage(ctx, id, models.Message{Role: "user", Content: "你好世界"}) + + sess, _ := m.Get(ctx, id) + if sess.Title != "你好世界" { + t.Errorf("Title = %q, want %q", sess.Title, "你好世界") + } +} + +func TestAutoTitleLongMessage(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + id, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + + // 超过 20 字符的消息应截断 + longMsg := "这是一条很长很长很长很长很长很长很长很长的消息" + m.AppendMessage(ctx, id, models.Message{Role: "user", Content: longMsg}) + + sess, _ := m.Get(ctx, id) + expected := string([]rune(longMsg)[:20]) + "…" + if sess.Title != expected { + t.Errorf("Title = %q, want %q", sess.Title, expected) + } +} + +func TestAutoTitleNotOverwritten(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + id, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + + // 首条消息设置标题 + m.AppendMessage(ctx, id, models.Message{Role: "user", Content: "第一条消息"}) + // 第二条消息不应覆盖已有的标题 + m.AppendMessage(ctx, id, models.Message{Role: "user", Content: "第二条消息"}) + + sess, _ := m.Get(ctx, id) + if sess.Title != "第一条消息" { + t.Errorf("Title = %q, want %q", sess.Title, "第一条消息") + } +} + +func TestListByUser(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + // 创建两个用户的不同会话 + id1, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + m.AppendMessage(ctx, id1, models.Message{Role: "user", Content: "会话1"}) + id2, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + m.AppendMessage(ctx, id2, models.Message{Role: "user", Content: "会话2"}) + m.Create(ctx, "user-2", models.DefaultConfig()) // 其他用户的会话 + + list, total, err := m.ListByUser(ctx, "user-1", 1, 10) + if err != nil { + t.Fatalf("ListByUser: %v", err) + } + if total != 2 { + t.Errorf("total = %d, want 2", total) + } + if len(list) != 2 { + t.Fatalf("len = %d, want 2", len(list)) + } + // 按 UpdatedAt 降序,id2 应在前 + if list[0].ID != id2 { + t.Errorf("list[0].ID = %q, want %q", list[0].ID, id2) + } + if list[0].Title != "会话2" { + t.Errorf("list[0].Title = %q, want %q", list[0].Title, "会话2") + } + if list[0].LastMessage != "会话2" { + t.Errorf("list[0].LastMessage = %q, want %q", list[0].LastMessage, "会话2") + } +} + +func TestListByUserPagination(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + // 创建 5 个会话 + for i := 0; i < 5; i++ { + id, _ := m.Create(ctx, "user-1", models.DefaultConfig()) + m.AppendMessage(ctx, id, models.Message{Role: "user", Content: "msg"}) + } + + // 第 1 页,每页 2 条 + list, total, _ := m.ListByUser(ctx, "user-1", 1, 2) + if total != 5 { + t.Errorf("total = %d, want 5", total) + } + if len(list) != 2 { + t.Errorf("page 1 len = %d, want 2", len(list)) + } + + // 第 2 页 + list, _, _ = m.ListByUser(ctx, "user-1", 2, 2) + if len(list) != 2 { + t.Errorf("page 2 len = %d, want 2", len(list)) + } + + // 第 3 页(最后一页) + list, _, _ = m.ListByUser(ctx, "user-1", 3, 2) + if len(list) != 1 { + t.Errorf("page 3 len = %d, want 1", len(list)) + } + + // 超出范围的页 + list, _, _ = m.ListByUser(ctx, "user-1", 10, 2) + if len(list) != 0 { + t.Errorf("out of range page len = %d, want 0", len(list)) + } +} + +func TestListByUserEmpty(t *testing.T) { + m := NewMemoryManager(30*time.Minute, 20) + defer m.Stop() + ctx := context.Background() + + list, total, err := m.ListByUser(ctx, "no-such-user", 1, 10) + if err != nil { + t.Fatalf("ListByUser: %v", err) + } + if total != 0 { + t.Errorf("total = %d, want 0", total) + } + if len(list) != 0 { + t.Errorf("len = %d, want 0", len(list)) + } +}