package host import ( "os" "path/filepath" "testing" "github.com/carlosframework/platform/internal/release" "github.com/carlosframework/platform/internal/rootstate" ) func TestPlan14IdenticalVersionKeepsRollbackEvidence(t *testing.T) { if !plan14RootFixture(t) { return } e, rt, u, c, _ := plan14AdoptionFixture(t) if err := os.MkdirAll("/var/lib", 0755); err != nil { t.Fatal(err) } if err := rootstate.EnsurePublicDir(release.RootHealthyDir); err != nil { t.Fatal(err) } evidence := release.ReadHealthy(e.bake, rt.Account, rt.App)[0] if err := release.RecordHealthy(release.RootHealthyDir, rt.Account, rt.App, evidence); err != nil { t.Fatal(err) } original, err := os.ReadFile(filepath.Join(release.RootHealthyDir, "healthy", rt.Account, rt.App+".json")) if err != nil { t.Fatal(err) } raw, err := os.ReadFile(u.exe) if err != nil { t.Fatal(err) } v2 := release.VersionPath(u.opt, rt.Account, "v2", rt.App) if err := os.MkdirAll(filepath.Dir(v2), 0755); err != nil { t.Fatal(err) } if err := os.WriteFile(v2, raw, 0755); err != nil { t.Fatal(err) } if err := release.PointLive(u.opt, rt.Host, rt.Account, "v2", rt.App); err != nil { t.Fatal(err) } u.exe = v2 makeProofAncestorsPublic(t, u.exe) makeProofAncestorsPublic(t, u.props.FragmentPath) s := productionProofBindingSource(e.store, u, u.opt) s.unitDirs = []string{filepath.Dir(u.props.FragmentPath)} c.resolve, c.host, c.rollback, c.prepareRollback, c.targetFile = s.resolve, s.forHost, s.rollback, s.prepareRollback, rootstate.OpenTrustedFile c.attempts = productionRootRestartChecks(u, u.opt).attempts e.root.obs.resolve = s.resolve e.bake = release.RootHealthyDir if err := e.root.obs.recordSettled(e.bake)(rt); err != nil { t.Fatal(err) } b, err := s.resolve(t.Context(), rt) if err != nil { t.Fatal(err) } if b.Version != "v2" || !b.Historical || b.History == nil || *b.History != evidence { t.Fatalf("binding: %+v", b) } captured := false u.afterRestart = func() { state, err := c.attempts() if err != nil { t.Fatal(err) } defer state.Close() _, b, err := loadRollback(state, rt.Host, c.now()) if err != nil { t.Fatal(err) } if b.Version != "v2" || b.History.Version != "v1" { t.Fatal("evidence rewritten", b) } if _, err := s.prepareRollback(t.Context(), b); err != nil { t.Fatal("v2 rollback not authorized", err) } captured = true } if err := checkedUnitRestart(u, u.opt, func(string) string { return "5s" }, e.root.obs.recordSettled(e.bake), c)(rt); err != nil { t.Fatal(err) } if !captured || len(u.effects) != 1 { t.Fatal("restart not captured", u.effects) } after, err := os.ReadFile(filepath.Join(release.RootHealthyDir, "healthy", rt.Account, rt.App+".json")) if err != nil { t.Fatal(err) } if string(after) != string(original) { t.Fatal("B4 evidence changed") } }