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("记录下发不应改变计划") } }