package backup import ( "io" "log" "os" "path/filepath" "strings" "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/stacks" ) // R-669 (v0.270.0): the recovery unit captures the PINNED version's .felhom.yml (the applied record), // not the stack dir's — which the sync may already have replaced with a newer, even failing, step's file. // MEASURED 2026-09-24 (A2): the unit held port 8999 (the failing step's probe), a restore wrote it back, // and the next undo judged the correct version with it and held the app. // // COMPANION RED-PROOF (REPORT.md): capture the stack dir's .felhom.yml again → "the unit carries the // failing step's probe". func TestR669_UnitCapturesThePinnedVersionsMeta(t *testing.T) { tmp := t.TempDir() stackDir := filepath.Join(tmp, "stack") drive := filepath.Join(tmp, "drive") mustWrite(t, filepath.Join(stackDir, "docker-compose.yml"), "services:\n app:\n image: example/app:1.2.3\n") mustWrite(t, filepath.Join(stackDir, ".felhom.yml"), "display_name: Example\nhealthcheck:\n checks:\n - type: api\n port: 8999\n") // flowed by the sync mustWrite(t, stacks.AppliedMetaFile(stackDir), "display_name: Example\nhealthcheck:\n checks:\n - type: api\n port: 80\n") // the pinned version's mustWrite(t, filepath.Join(stackDir, "app.yaml"), "deployed: true\nenv: {}\n") m := &Manager{ logger: log.New(io.Discard, "", 0), systemDataPath: filepath.Join(tmp, "system"), stackProvider: &fakeRecoveryProvider{info: RecoveryInfo{StackDir: stackDir, DisplayName: "Example", ImagePins: []string{"example/app:1.2.3"}}, hdd: drive}, version: "vtest", } if err := m.CaptureRecoveryUnit("example"); err != nil { t.Fatalf("capture: %v", err) } b, err := os.ReadFile(filepath.Join(RecoveryUnitComposePath(drive, "example"), ".felhom.yml")) if err != nil { t.Fatal(err) } if strings.Contains(string(b), "8999") || !strings.Contains(string(b), "port: 80") { t.Fatalf("the unit carries the failing step's probe, not the pinned version's:\n%s", b) } // Control: no applied record (an app pinned before v0.263.2) → the stack dir's file, as before. if err := os.RemoveAll(filepath.Dir(stacks.AppliedMetaFile(stackDir))); err != nil { t.Fatal(err) } mustWrite(t, filepath.Join(stackDir, ".felhom.yml"), "display_name: Example changed\n") // force a recapture if err := m.CaptureRecoveryUnit("example"); err != nil { t.Fatal(err) } b, _ = os.ReadFile(filepath.Join(RecoveryUnitComposePath(drive, "example"), ".felhom.yml")) if !strings.Contains(string(b), "Example changed") { t.Fatalf("without an applied record the stack dir's file must be captured: %s", b) } }