controller v0.240.0: seven defects from the any-tier proof and the first nightly rotation
gates / gates (push) Successful in 13s
gates / gates (push) Successful in 13s
R-486 (P1): removing an app with its backups KEPT keeps its Tier-2 record, so the second-drive restore is no longer refused over an intact mirror. R-484: postgis/pgvector/timescaledb images are Postgres (logical dumps). R-485: the backup card sizes the recovery unit and the mirror(s). R-480: a held update's sentence leaves the card once the hold is lifted. R-477: the update's off-site lookup is one snapshots call, no stats. R-478: a copy older than this install's deploy does not count. R-474: "delete backups" deletes the unit, the mirror(s) and the prefs. Tests and red-proofs per row; evidence in felhom.eu documentation/audits/v0240-2026-09-13/ and nightly-2026-09-13-adventurelog/.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package stacks
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/appbackup"
|
||||
)
|
||||
|
||||
// R-485 — the backup card sizes the recovery unit and the mirror, not two dead paths.
|
||||
//
|
||||
// COMPANION RED-PROOF (REPORT.md): put the old `db-dumps` + `secondary/<app>/rsync` paths back —
|
||||
// this fails with has_backups=false over a unit that exists.
|
||||
func TestR485_BackupCardSeesTheUnitAndTheMirror(t *testing.T) {
|
||||
m, _ := newPinManager(t, pinTplOld, pinTplNew, "deployed: true\nenv: {}\n")
|
||||
ns := t.TempDir()
|
||||
unit := appbackup.RecoveryUnitPath(ns, "nextcloud")
|
||||
if err := os.MkdirAll(filepath.Join(unit, "volume-dumps"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(unit, "volume-dumps", "x.tar"), make([]byte, 4096), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mirror := filepath.Join(t.TempDir(), "backups", "secondary", "nextcloud")
|
||||
if err := os.MkdirAll(mirror, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(mirror, "manifest.json"), []byte("{}"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp, err := m.GetStackBackupData("nextcloud", ns, []string{mirror})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !resp.HasBackups {
|
||||
t.Fatal("a recovery unit on disk IS a backup — has_backups must be true")
|
||||
}
|
||||
var seen []string
|
||||
for _, p := range resp.BackupPaths {
|
||||
if p.Exists {
|
||||
seen = append(seen, p.Path)
|
||||
}
|
||||
}
|
||||
if len(seen) != 2 || seen[0] != unit || seen[1] != mirror {
|
||||
t.Errorf("want the unit and the mirror, got %v", seen)
|
||||
}
|
||||
if resp.BackupPaths[0].SizeBytes < 4096 {
|
||||
t.Errorf("the unit's size must include its volume dumps, got %d", resp.BackupPaths[0].SizeBytes)
|
||||
}
|
||||
// No unit, no mirror: nothing to delete, honestly.
|
||||
if resp, _ := m.GetStackBackupData("nextcloud", t.TempDir(), nil); resp.HasBackups {
|
||||
t.Error("nothing on disk must be has_backups=false")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user