137 lines
4.0 KiB
Go
137 lines
4.0 KiB
Go
package store
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.casaderoll.de/michael/urbm/internal/model"
|
|
)
|
|
|
|
func TestStoreInitializesAndPersists(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := New(dir)
|
|
if err := s.Init(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c, err := s.LoadConfig()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c.SchemaVersion != model.SchemaVersion {
|
|
t.Fatalf("schema version = %d", c.SchemaVersion)
|
|
}
|
|
info, err := os.Stat(s.configPath())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if info.Mode().Perm() != 0600 {
|
|
t.Fatalf("config mode = %o", info.Mode().Perm())
|
|
}
|
|
}
|
|
|
|
func TestCorruptRunHistoryIsQuarantinedBeforeReplacement(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := New(dir)
|
|
if err := os.WriteFile(s.runsPath(), []byte(`{"broken":`), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := s.LoadRuns(); err == nil {
|
|
t.Fatal("corrupt run history loaded without error")
|
|
}
|
|
if _, err := os.Stat(s.runsPath()); !os.IsNotExist(err) {
|
|
t.Fatalf("corrupt runs file was not moved: %v", err)
|
|
}
|
|
matches, err := filepath.Glob(s.runsPath() + ".corrupt-*")
|
|
if err != nil || len(matches) != 1 {
|
|
t.Fatalf("quarantined run files = %#v, %v", matches, err)
|
|
}
|
|
if err := s.SaveRuns([]model.Run{}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(matches[0]); err != nil {
|
|
t.Fatalf("quarantined run file was overwritten: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCorruptBackupMetricsAreQuarantined(t *testing.T) {
|
|
dir := t.TempDir()
|
|
s := New(dir)
|
|
if err := os.WriteFile(s.backupMetricsPath(), []byte("{not-json}\n"), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, _, err := s.LoadBackupMetrics(); err == nil {
|
|
t.Fatal("corrupt backup metrics loaded without error")
|
|
}
|
|
matches, err := filepath.Glob(s.backupMetricsPath() + ".corrupt-*")
|
|
if err != nil || len(matches) != 1 {
|
|
t.Fatalf("quarantined metric files = %#v, %v", matches, err)
|
|
}
|
|
contents, err := os.ReadFile(matches[0])
|
|
if err != nil || string(contents) != "{not-json}\n" {
|
|
t.Fatalf("quarantined metric contents = %q, %v", contents, err)
|
|
}
|
|
}
|
|
|
|
func TestBackupMetricsPersistSeparatelyFromRuns(t *testing.T) {
|
|
s := New(t.TempDir())
|
|
if err := s.Init(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
finished := time.Date(2026, 7, 13, 1, 30, 0, 0, time.UTC)
|
|
metrics := []model.BackupMetric{{SchemaVersion: model.SchemaVersion, RunID: "run-1", JobID: "job-1", FinishedAt: finished, Status: "success", BytesProcessed: 42, FilesProcessed: 7}}
|
|
if err := s.SaveBackupMetrics(metrics); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.SaveRuns(nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
loaded, legacy, err := s.LoadBackupMetrics()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if legacy {
|
|
t.Fatal("compacted metric file was detected as legacy JSON array")
|
|
}
|
|
if len(loaded) != 1 || loaded[0].RunID != "run-1" || loaded[0].BytesProcessed != 42 {
|
|
t.Fatalf("backup metrics = %#v", loaded)
|
|
}
|
|
info, err := os.Stat(s.backupMetricsPath())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if info.Mode().Perm() != 0600 {
|
|
t.Fatalf("backup metrics mode = %o", info.Mode().Perm())
|
|
}
|
|
}
|
|
|
|
func TestBackupMetricsMigrateFromJSONArrayAndAppend(t *testing.T) {
|
|
s := New(t.TempDir())
|
|
finished := time.Date(2026, 7, 13, 1, 30, 0, 0, time.UTC)
|
|
legacyJSON := `[{"schemaVersion":1,"runId":"old","jobId":"job-1","finishedAt":"2026-07-13T01:30:00Z","status":"success","bytesProcessed":42,"filesProcessed":7}]`
|
|
if err := os.WriteFile(s.legacyBackupMetricsPath(), []byte(legacyJSON), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
metrics, legacy, err := s.LoadBackupMetrics()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !legacy || len(metrics) != 1 || metrics[0].RunID != "old" {
|
|
t.Fatalf("legacy metrics = %#v, legacy = %v", metrics, legacy)
|
|
}
|
|
if err := s.SaveBackupMetrics(metrics); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := s.AppendBackupMetric(model.BackupMetric{SchemaVersion: model.SchemaVersion, RunID: "new", JobID: "job-1", FinishedAt: finished.Add(time.Hour), Status: "success"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
metrics, legacy, err = s.LoadBackupMetrics()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if legacy || len(metrics) != 2 || metrics[1].RunID != "new" {
|
|
t.Fatalf("appended metrics = %#v, legacy = %v", metrics, legacy)
|
|
}
|
|
}
|