Files
felhom-controller/controller/internal/api/r474_remove_wiring_test.go
T
admin bdcbd50b42
gates / gates (push) Successful in 13s
controller v0.240.0: seven defects from the any-tier proof and the first nightly rotation
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/.
2026-09-13 19:26:50 +02:00

63 lines
1.9 KiB
Go

package api
import (
"go/ast"
"go/parser"
"go/token"
"strings"
"testing"
)
// R-474 — the remove handler really deletes the whole unit, the Tier-2 mirror and the prefs.
func TestR474_RemoveHandlerDeletesUnitMirrorAndPrefs(t *testing.T) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "router.go", nil, 0)
if err != nil {
t.Fatal(err)
}
var sel []string
for _, d := range f.Decls {
fn, ok := d.(*ast.FuncDecl)
if !ok || fn.Name.Name != "removeStack" || fn.Body == nil {
continue
}
ast.Inspect(fn.Body, func(n ast.Node) bool {
if s, ok := n.(*ast.SelectorExpr); ok {
sel = append(sel, s.Sel.Name)
}
return true
})
}
joined := " " + strings.Join(sel, " ") + " "
for _, want := range []string{"RecoveryUnitPath", "Tier2MirrorDirsForApp", "RemoveTier2Mirrors", "DeleteAppBackupPrefs"} {
if !strings.Contains(joined, " "+want+" ") {
t.Errorf("removeStack must call %s", want)
}
}
}
// R-486 — removing an app with its backups KEPT keeps its Tier-2 record. The only call that may
// forget the record is DeleteAppBackupPrefs, which the R-474 branch guards on remove_backups.
//
// COMPANION RED-PROOF (REPORT.md): put `r.sett.SetCrossDriveConfig(name, nil)` back into
// removeStack unconditionally — this fails.
func TestR486_RemovalKeepsTheTier2RecordUnlessBackupsGo(t *testing.T) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "router.go", nil, 0)
if err != nil {
t.Fatal(err)
}
for _, d := range f.Decls {
fn, ok := d.(*ast.FuncDecl)
if !ok || fn.Name.Name != "removeStack" || fn.Body == nil {
continue
}
ast.Inspect(fn.Body, func(n ast.Node) bool {
if s, ok := n.(*ast.SelectorExpr); ok && s.Sel.Name == "SetCrossDriveConfig" {
t.Errorf("removeStack calls SetCrossDriveConfig at line %d — a removal with backups kept would forget the mirror it kept (R-486)", fset.Position(s.Pos()).Line)
}
return true
})
}
}