package appbackup import ( "os" "path/filepath" "testing" "time" ) // writeDumpFile creates a minimal VALID postgres dump so a real ValidateDump would set Valid=true and // TableCount=1 — distinguishable from the sentinel the cache returns. func writeDumpFile(t *testing.T, dir string) string { t.Helper() path := filepath.Join(dir, "romm-postgres.sql") body := "-- PostgreSQL database dump\n" + "CREATE TABLE public.t (id int);\n" + "-- PostgreSQL database dump complete\n" + // pad past the 100-byte floor "-- padding ------------------------------------------------------------\n" if err := os.WriteFile(path, []byte(body), 0o644); err != nil { t.Fatal(err) } return path } // TestListDumpFiles_CacheHitSkipsValidate asserts M18: when the `cached` lookup returns ok for an // unchanged file, ListDumpFiles reuses that result and does NOT re-run the (expensive) ValidateDump. // Proven via a sentinel TableCount=999 that only the cache could supply (a real validate yields 1). func TestListDumpFiles_CacheHitSkipsValidate(t *testing.T) { dir := t.TempDir() writeDumpFile(t, dir) const sentinel = 999 calls := 0 cached := func(name string, size int64, mod time.Time) (DumpValidation, bool) { calls++ return DumpValidation{Valid: true, TableCount: sentinel}, true // always "hit" } files, err := ListDumpFiles(dir, cached) if err != nil { t.Fatal(err) } if len(files) != 1 { t.Fatalf("expected 1 dump file, got %d", len(files)) } if files[0].Validation.TableCount != sentinel { t.Fatalf("validation TableCount = %d, want %d (sentinel from cache) — ValidateDump was re-run instead of using the cache", files[0].Validation.TableCount, sentinel) } if calls != 1 { t.Fatalf("cached lookup called %d times, want 1", calls) } } // TestListDumpFiles_CacheMissValidates asserts that on a cache MISS (e.g. modtime changed) ListDumpFiles // falls through to a real ValidateDump (sentinel must NOT appear; real TableCount=1). func TestListDumpFiles_CacheMissValidates(t *testing.T) { dir := t.TempDir() writeDumpFile(t, dir) cached := func(name string, size int64, mod time.Time) (DumpValidation, bool) { return DumpValidation{Valid: true, TableCount: 999}, false // always "miss" } files, err := ListDumpFiles(dir, cached) if err != nil { t.Fatal(err) } if len(files) != 1 { t.Fatalf("expected 1 dump file, got %d", len(files)) } if files[0].Validation.TableCount == 999 { t.Fatalf("got the sentinel on a cache MISS — should have run a real ValidateDump") } if !files[0].Validation.Valid || files[0].Validation.TableCount != 1 { t.Fatalf("real validation expected Valid=true TableCount=1, got Valid=%v TableCount=%d", files[0].Validation.Valid, files[0].Validation.TableCount) } } // TestListDumpFiles_NilCachedAlwaysValidates asserts the legacy fast path (cached==nil) still validates. func TestListDumpFiles_NilCachedAlwaysValidates(t *testing.T) { dir := t.TempDir() writeDumpFile(t, dir) files, err := ListDumpFiles(dir, nil) if err != nil { t.Fatal(err) } if len(files) != 1 || !files[0].Validation.Valid || files[0].Validation.TableCount != 1 { t.Fatalf("nil-cached path should validate: got %+v", files[0].Validation) } }