Files
Cyrene_v2/internal/db/migrate_turn_id_test.go
T
AskaEth d64b26d499
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(chat): chat_messages.turn_id 列 + DTO(写入接线留待下一步)
迁移 0018:ALTER TABLE chat_messages ADD COLUMN turn_id TEXT NOT NULL DEFAULT ''
(与 persona_id / client_msg_id / document 同族:不用 NULL,空串 = 不属于任何已知回合 ⇒ 旧行零迁移、键省略)。
存储层全链路带 turn_id(列清单唯一一份 ⇒ List/ListAfter/Recent/Search/FindByClientMsgID 自动同源);
新增 history/turn_id.go:ensureTurnIDColumn(既有库幂等前滚)+ SetMessagesTurnID
(第二段补写:单事务参数化、先到先得 WHERE turn_id = ''、幂等、未知 id 忽略)。
DTO:historyMessage.TurnID(json turnId,omitempty)⇒ REST 列表 / admin 渠道日志 / WS 握手回放 /
message_persisted / channel_persisted / message_edited 一次全覆盖。
写入面:persistUserMessages 读 ctx 回合标识;persistAssistantReply 增可选尾参(既有调用点零改动);
withTurnID / turnIDFrom / assignTurnID / turnIDOfLeg。
⚠️ 编排器把 turnId 交给落库的 4 处(新起一路 / 续跑路 / 被 steer 吃进 / 助手回复)尚未接线
(那些文件当时被另一路占用);当前生产行为 turn_id 仍为 ''。清单已在切片报告里精确到文件:行。
13 新用例 + 5 条变异(INSERT 不带列 / DTO 不回填 / 去掉 omitempty / 去掉先到先得 / 不回滚前滚)。
为守 session_persist.go ≤500 行,turnId 一节拆到新文件 session_turn_id.go。
2026-10-05 09:46:10 +08:00

72 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package db
import (
"context"
"testing"
)
// turnIDMigrationID 是回合标识列的迁移 id(design/15 §2.5.9)。
const turnIDMigrationID = "0018_chat_message_turn_id"
// TestMigrateTurnIDColumnReversible 验证 0018(chat_messages.turn_id,回合标识列)
// 可上下翻滚:up 建列、重复 up 是空操作、down 删列、再 up 恢复。它用自己的内存库,
// 绝不碰 data/cyrene.db。
func TestMigrateTurnIDColumnReversible(t *testing.T) {
t.Parallel()
ctx := context.Background()
conn := openMemory(t)
if err := MigrateUp(ctx, conn, testLogger()); err != nil {
t.Fatalf("MigrateUp: %v", err)
}
if !columnExists(t, ctx, conn, "chat_messages", "turn_id") {
t.Fatal("chat_messages.turn_id should exist after MigrateUp")
}
// 重复 up:已记录的迁移被跳过,列仍在且不报错(幂等)。
if err := MigrateUp(ctx, conn, testLogger()); err != nil {
t.Fatalf("MigrateUp second call: %v", err)
}
if !columnExists(t, ctx, conn, "chat_messages", "turn_id") {
t.Fatal("chat_messages.turn_id should still exist after idempotent re-run")
}
// 恰好回滚到 0018(含它之后新加的迁移),因此日后再加迁移也不会让本测试失效。
ids := upMigrationIDs(t)
idx := -1
for i, id := range ids {
if id == turnIDMigrationID {
idx = i
}
}
if idx < 0 {
t.Fatalf("%s not found in %v", turnIDMigrationID, ids)
}
if err := MigrateDown(ctx, conn, len(ids)-idx, testLogger()); err != nil {
t.Fatalf("MigrateDown(%d): %v", len(ids)-idx, err)
}
if columnExists(t, ctx, conn, "chat_messages", "turn_id") {
t.Fatal("chat_messages.turn_id should be dropped by the 0018 down")
}
// 重新 up 恢复端到端可用:默认空串意味着「这一行不属于任何已知回合」。
if err := MigrateUp(ctx, conn, testLogger()); err != nil {
t.Fatalf("re-MigrateUp: %v", err)
}
if !columnExists(t, ctx, conn, "chat_messages", "turn_id") {
t.Fatal("chat_messages.turn_id should exist again after re-MigrateUp")
}
if _, err := conn.ExecContext(ctx,
`INSERT INTO chat_messages (id, session_id, role, content, created_at) VALUES (?, ?, ?, ?, ?)`,
"m1", "web", "user", "hi", 1000); err != nil {
t.Fatalf("insert without turn id: %v", err)
}
var turnID string
if err := conn.QueryRowContext(ctx, `SELECT turn_id FROM chat_messages WHERE id = ?`, "m1").Scan(&turnID); err != nil {
t.Fatalf("select turn_id: %v", err)
}
if turnID != "" {
t.Fatalf("turn_id = %q, want the empty default", turnID)
}
}