343a005db1
- migrations_test.go 之前硬编码 44:新增 000045 后该包测试失败(全量套件里才暴露) - 现在断言 migration 44 = production_kb_bindings、45 = backup_schedule - 新增 TestBackupScheduleRoundTripIntegration:默认值 → 保存(upsert 单行) → 读回(含 updated_by/at) → 记录下发结果(不改计划);实测在 governance 库隔离 schema 上 PASS(0.95s)
91 lines
2.7 KiB
Go
91 lines
2.7 KiB
Go
package postgres
|
||
|
||
import (
|
||
"context"
|
||
"os"
|
||
"testing"
|
||
"time"
|
||
|
||
"github.com/jackc/pgx/v5/pgxpool"
|
||
|
||
"knowledge-governance/internal/governance"
|
||
)
|
||
|
||
// 备份定时计划的真实库往返:默认值 → 保存 → 读回 → 记录下发结果。
|
||
// 页面靠这几步判定"库里设置"与"主机上生效计划"是否一致(待下发/已一致)。
|
||
func TestBackupScheduleRoundTripIntegration(t *testing.T) {
|
||
databaseURL := isolatedIntegrationDatabaseURL(t, os.Getenv("TEST_DATABASE_URL"))
|
||
if databaseURL == "" {
|
||
t.Skip("TEST_DATABASE_URL is not set")
|
||
}
|
||
ctx := context.Background()
|
||
pool, err := pgxpool.New(ctx, databaseURL)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer pool.Close()
|
||
if err := ApplyMigrations(ctx, pool); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
store := NewStore(pool)
|
||
|
||
initial, err := store.LoadBackupSchedule(ctx)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if initial.Enabled || initial.ScheduleTime != governance.BackupScheduleDefaultTime ||
|
||
initial.RetentionDays != 7 || initial.RetentionMonths != 3 {
|
||
t.Fatalf("迁移后的默认计划不对: %#v", initial)
|
||
}
|
||
|
||
now := time.Date(2026, 10, 9, 12, 0, 0, 0, time.UTC)
|
||
next := governance.BackupSchedule{
|
||
Enabled: true, ScheduleTime: "04:15", RetentionDays: 14, RetentionMonths: 6,
|
||
}
|
||
if err := store.SaveBackupSchedule(ctx, next, "admin", now); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
saved, err := store.LoadBackupSchedule(ctx)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if !saved.Enabled || saved.ScheduleTime != "04:15" || saved.RetentionDays != 14 || saved.RetentionMonths != 6 {
|
||
t.Fatalf("保存后读回不对: %#v", saved)
|
||
}
|
||
if saved.UpdatedBy != "admin" || !saved.UpdatedAt.Equal(now) {
|
||
t.Fatalf("应记录操作人与时间: %#v", saved)
|
||
}
|
||
if !next.SameHostPlan(saved) {
|
||
t.Fatal("保存的计划应与主机下发字段一致(SameHostPlan)")
|
||
}
|
||
|
||
// 重复保存走 upsert,不应产生第二行。
|
||
if err := store.SaveBackupSchedule(ctx, next, "admin2", now.Add(time.Minute)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
var rows int
|
||
if err := pool.QueryRow(ctx, `SELECT count(*) FROM backup_schedule`).Scan(&rows); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if rows != 1 {
|
||
t.Fatalf("单行表出现 %d 行", rows)
|
||
}
|
||
|
||
appliedAt := now.Add(2 * time.Minute)
|
||
if err := store.MarkBackupScheduleApplied(ctx, "每天 04:15 · 保留 14 天 · 每月归档 6 份", appliedAt); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
afterApply, err := store.LoadBackupSchedule(ctx)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if afterApply.LastAppliedAt == nil || !afterApply.LastAppliedAt.Equal(appliedAt) ||
|
||
afterApply.LastAppliedSummary == "" {
|
||
t.Fatalf("下发结果未落库: %#v", afterApply)
|
||
}
|
||
// 记录下发不得改动计划本身。
|
||
if !afterApply.SameHostPlan(saved) {
|
||
t.Fatal("记录下发不应改变计划")
|
||
}
|
||
}
|