controller v0.268.0: the undo finds volumes by definition; a held app names only a whole copy; one press = one tested step (R-658, R-659, R-660, R-651; 09 §6.4 part 5)
gates / gates (push) Successful in 27s
gates / gates (push) Successful in 27s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package stacks
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// R-651 (v0.268.0) — a removed app left `applied-compose.yml` and `applied-meta/` in its stack dir.
|
||||
// The CONSEQUENCE asserted: after remove + reinstall, the probe the undo would judge the old version
|
||||
// by (savePreUpdateMeta) is the REINSTALL's .felhom.yml — not the removed install's record. (A
|
||||
// reinstall whose pin step fails writes no record of its own, which is when the stale one was read.)
|
||||
//
|
||||
// COMPANION RED-PROOF (REPORT.md): delete the R-651 block in RemoveStack. This test then fails at
|
||||
// "the undo would probe with the REMOVED install's .felhom.yml".
|
||||
func TestR651_RemoveDeletesTheAppliedRecord(t *testing.T) {
|
||||
drive := t.TempDir()
|
||||
m, dir, _ := newR442Manager(t, "app", ssdCompose, driveAppYAML(drive), drive)
|
||||
mustWrite(t, AppliedComposePath(dir), ssdCompose)
|
||||
if err := storeAppliedMeta(dir, []byte("# the REMOVED install's probe\n")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := m.RemoveStack("app", false, nil); err != nil {
|
||||
t.Fatalf("RemoveStack: %v", err)
|
||||
}
|
||||
for _, p := range []string{AppliedComposePath(dir), filepath.Join(dir, appliedMetaDir)} {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
t.Errorf("%s survived the remove (R-651)", p)
|
||||
}
|
||||
}
|
||||
// The catalog mirror stays: it is the template, not the install.
|
||||
if _, err := os.Stat(filepath.Join(dir, "docker-compose.yml")); err != nil {
|
||||
t.Fatalf("the catalog mirror's compose file must stay: %v", err)
|
||||
}
|
||||
// Reinstall (its pin step wrote no record) → the undo's probe source.
|
||||
mustWrite(t, filepath.Join(dir, ".felhom.yml"), "# the REINSTALL's probe\n")
|
||||
md, _ := savePreUpdateMeta(dir)
|
||||
b, _ := os.ReadFile(filepath.Join(md, ".felhom.yml"))
|
||||
if !strings.Contains(string(b), "REINSTALL") {
|
||||
t.Fatalf("the undo would probe with the REMOVED install's .felhom.yml: %q", b)
|
||||
}
|
||||
}
|
||||
|
||||
// R-658 — the removal's report counts a declared volume that carries no label (a restored app).
|
||||
// Measured at the 2026-09-23 night's teardown: `volumes_removed: []` over volumes that did go.
|
||||
//
|
||||
// COMPANION RED-PROOF (REPORT.md): make appVolumeSet return projectVolumes alone — the report reads
|
||||
// `[]` again and this test fails.
|
||||
func TestR658_RemoveReportsUnlabelledVolumes(t *testing.T) {
|
||||
drive := t.TempDir()
|
||||
m, _, _ := newR442Manager(t, "app", ssdCompose, driveAppYAML(drive), drive)
|
||||
downDone := false
|
||||
m.execFn = func(name string, args ...string) (string, error) {
|
||||
a := strings.Join(args, " ")
|
||||
switch {
|
||||
case strings.Contains(a, "label=com.docker.compose.project="):
|
||||
return "", nil // restored: no label
|
||||
case a == "volume ls -q":
|
||||
if downDone {
|
||||
return "other_vol\n", nil
|
||||
}
|
||||
return "app_app_cfg\nother_vol\n", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
// the stub compose (newR442Manager) is the `down`; flip the listing after the first before-read.
|
||||
calls := 0
|
||||
inner := m.execFn
|
||||
m.execFn = func(name string, args ...string) (string, error) {
|
||||
if strings.Join(args, " ") == "volume ls -q" {
|
||||
calls++
|
||||
downDone = calls > 1
|
||||
}
|
||||
return inner(name, args...)
|
||||
}
|
||||
resp, err := m.RemoveStack("app", false, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("RemoveStack: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(resp.VolumesRemoved, []string{"app_app_cfg"}) {
|
||||
t.Fatalf("volumes_removed = %v, want [app_app_cfg] — an unlabelled volume the remove did delete", resp.VolumesRemoved)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user