1453cfc69b
gates / gates (push) Failing after 50s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
57 lines
2.1 KiB
Go
57 lines
2.1 KiB
Go
package appbackup
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// R-10 (T-6E-1): DumpOneTo fsynced the dump FILE and renamed it, but never fsynced the DIRECTORY, so
|
|
// the rename itself was not durable — the asymmetry with atomicPromoteTar (backup.go), which does.
|
|
// The consequence asserted: a successful dump syncs the directory that holds the final file, AFTER
|
|
// the final name exists (the sync must cover the rename, not precede it).
|
|
//
|
|
// No real docker: a `docker` stub in t.TempDir() on PATH (R-650's sanctioned seam) answers the
|
|
// running-check and prints a small SQL dump.
|
|
func TestDumpOneTo_SyncsTheDumpDirectoryAfterRename(t *testing.T) {
|
|
bin := t.TempDir()
|
|
stub := "#!/bin/sh\ncase \"$1\" in\n inspect) echo true ;;\n exec) printf 'CREATE TABLE t (id int);\\nINSERT INTO t VALUES (1);\\n' ;;\nesac\n"
|
|
if err := os.WriteFile(filepath.Join(bin, "docker"), []byte(stub), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Setenv("PATH", bin)
|
|
|
|
dumpDir := filepath.Join(t.TempDir(), "unit")
|
|
final := filepath.Join(dumpDir, "app-postgres.sql")
|
|
|
|
var synced []string
|
|
finalExistedAtSync := false
|
|
orig := syncDumpDir
|
|
syncDumpDir = func(dir string) error {
|
|
synced = append(synced, dir)
|
|
if _, err := os.Stat(final); err == nil {
|
|
finalExistedAtSync = true
|
|
}
|
|
return orig(dir)
|
|
}
|
|
t.Cleanup(func() { syncDumpDir = orig })
|
|
|
|
db := DiscoveredDB{ContainerName: "app-db", ContainerID: "0123456789abcdef", DBType: DBTypePostgres, DBUser: "u", DBName: "d", StackName: "app"}
|
|
res := DumpOneTo(context.Background(), db, final, log.New(io.Discard, "", 0), false)
|
|
if res.Error != nil {
|
|
t.Fatalf("dump failed: %v", res.Error)
|
|
}
|
|
if _, err := os.Stat(final + ".tmp"); !os.IsNotExist(err) {
|
|
t.Errorf("the .tmp scratch file is still present after a successful dump")
|
|
}
|
|
if len(synced) != 1 || synced[0] != dumpDir {
|
|
t.Fatalf("R-10: the dump directory was not fsynced after the rename: synced=%v, want [%s]", synced, dumpDir)
|
|
}
|
|
if !finalExistedAtSync {
|
|
t.Errorf("R-10: the directory was synced BEFORE the final name existed — the rename is not covered")
|
|
}
|
|
}
|