package release import ( "bytes" "errors" "os" "path/filepath" "strings" "testing" "time" "github.com/carlosframework/platform/internal/rootstate" ) // Inject the directory-sync boundary after an actual file sync and rename. // The embedded interface is intentionally unused: addRootHealthy needs Read // and Write only, under the lock already held by recordRootHealthy. type healthyRetryStore struct { rootstate.Store dir string fail int syncs int fault error } func (s *healthyRetryStore) Read(name string) ([]byte, error) { return os.ReadFile(filepath.Join(s.dir, name)) } func (s *healthyRetryStore) Write(name string, b []byte) error { f, err := os.CreateTemp(s.dir, "history-") if err != nil { return err } tmp := f.Name() defer os.Remove(tmp) if _, err = f.Write(b); err != nil { f.Close() return err } if err = f.Sync(); err != nil { f.Close() return err } if err = f.Close(); err != nil { return err } if err = os.Rename(tmp, filepath.Join(s.dir, name)); err != nil { return err } s.syncs++ if s.fail > 0 { s.fail-- return s.fault } d, err := os.Open(s.dir) if err != nil { return err } defer d.Close() return d.Sync() } func TestPlan14HealthyDuplicateRetryDurability(t *testing.T) { fault := errors.New("injected account directory fsync failure") s := &healthyRetryStore{dir: t.TempDir(), fail: 2, fault: fault} original := HealthyBuild{SHA256: strings.Repeat("a", 64), Version: "v1", How: "live", At: time.Date(2026, 10, 12, 0, 0, 0, 0, time.UTC)} if err := addRootHealthy(s, "console", original); !errors.Is(err, fault) { t.Fatalf("first write: %v", err) } before, err := s.Read("console.json") if err != nil { t.Fatal(err) } retry := original retry.At = retry.At.Add(time.Hour) retry.How = "settle" retry.Version = "renamed" if err = addRootHealthy(s, "console", retry); !errors.Is(err, fault) { t.Fatalf("visible duplicate hid failed directory sync: %v", err) } if err = addRootHealthy(s, "console", retry); err != nil { t.Fatal(err) } if s.syncs != 3 { t.Fatalf("directory sync attempts = %d, want 3", s.syncs) } after, err := s.Read("console.json") if err != nil { t.Fatal(err) } if !bytes.Equal(before, after) { t.Fatal("retry replaced the original evidence bytes") } got, err := decodeRootHealthy(after) if err != nil || len(got) != 1 || got[0] != original { t.Fatalf("evidence = %#v: %v", got, err) } }