package web import ( "testing" "gitea.dooplex.hu/admin/felhom-controller/internal/agentapi" ) // R-542 — a drive that backs a REGISTERED storage path must not be offered for formatting (nor again // for attaching). The mount table is the shape measured on demo-hp 2026-10-06 (guest /proc/mounts). const r542Mounts = `/dev/mapper/pve-root /mnt/felhom-drives ext4 rw,relatime 0 0 /dev/nvme0n1 /mnt/felhom-drives/hdd_1 ext4 rw,relatime 0 0 /dev/sdb1 /mnt/felhom-drives/adatlemez ext4 rw,relatime 0 0 /dev/mapper/pve-vm--9201--disk--1 /mnt/sys_drive ext4 rw,relatime 0 0 ` // COMPANION RED-PROOF (observed): make dropRegisteredDrives `return resp` at its top (the pre-R-542 // pass-through) → this fails with "a registered, in-use drive is offered for FORMATTING". Restored. func TestR542_RegisteredDriveNotOfferedForFormat(t *testing.T) { agentSaid := agentapi.CandidatesResult{ Initialize: []agentapi.DiskCandidate{ {Device: "/dev/sdb", MountSource: "/dev/sdb1", FSType: "ext4", DataBearing: true}, // registered (partition source) {Device: "/dev/nvme0n1", FSType: "ext4", DataBearing: true}, // registered (whole-disk source) {Device: "/dev/sdc"}, // a fresh, blank drive }, Attach: []agentapi.DiskCandidate{ {Device: "/dev/sdb", MountSource: "/dev/sdb1", FSType: "ext4"}, {Device: "/dev/sdd", MountSource: "/dev/sdd1", FSType: "ext4"}, // a fresh USB with a filesystem }, } registered := map[string]bool{"/mnt/felhom-drives/hdd_1": true, "/mnt/felhom-drives/adatlemez": true, "/mnt/sys_drive": true} got := dropRegisteredDrives(agentSaid, r542Mounts, registered) if len(got.Initialize) != 1 || got.Initialize[0].Device != "/dev/sdc" { t.Fatalf("a registered, in-use drive is offered for FORMATTING: initialize=%+v (want only /dev/sdc)", got.Initialize) } if len(got.Attach) != 1 || got.Attach[0].Device != "/dev/sdd" { t.Fatalf("a registered drive is offered again under attach: %+v (want only /dev/sdd)", got.Attach) } } // An UNregistered drive mounted under the managed path keeps today's behaviour (the agent's rule: // re-initialising Felhom's own, unregistered drive stays allowed — e.g. after a rebuild). func TestR542_UnregisteredDriveStillOffered(t *testing.T) { agentSaid := agentapi.CandidatesResult{Initialize: []agentapi.DiskCandidate{{Device: "/dev/sdb", MountSource: "/dev/sdb1"}}} got := dropRegisteredDrives(agentSaid, r542Mounts, map[string]bool{"/mnt/sys_drive": true}) if len(got.Initialize) != 1 { t.Fatalf("an unregistered drive must stay offered; got %+v", got.Initialize) } } // FAIL-SAFE: an unreadable mount table cannot prove a drive is free → initialize is EMPTY, attach unchanged. // // COMPANION RED-PROOF (observed): drop the empty-mounts branch → this fails with "unreadable mount // table must empty initialize". Restored. func TestR542_UnreadableMountTableEmptiesInitialize(t *testing.T) { agentSaid := agentapi.CandidatesResult{ Initialize: []agentapi.DiskCandidate{{Device: "/dev/sdb"}}, Attach: []agentapi.DiskCandidate{{Device: "/dev/sdd", MountSource: "/dev/sdd1"}}, } got := dropRegisteredDrives(agentSaid, "", map[string]bool{"/mnt/felhom-drives/adatlemez": true}) if len(got.Initialize) != 0 || got.Initialize == nil { t.Fatalf("unreadable mount table must empty initialize (non-nil, so JSON is []); got %+v", got.Initialize) } if len(got.Attach) != 1 { t.Fatalf("attach is non-destructive and must pass through; got %+v", got.Attach) } } // Partition matching must not over-match: /dev/sdb1 in use does not hide /dev/sdba or /dev/sdc. func TestR542_PartitionMatchIsExact(t *testing.T) { inUse := map[string]bool{"/dev/sdb1": true, "/dev/nvme0n1p2": true} for dev, want := range map[string]bool{"/dev/sdb": true, "/dev/sdba": false, "/dev/sdc": false, "/dev/nvme0n1": true, "/dev/nvme0n12": false} { if got := candidateBacksInUse(agentapi.DiskCandidate{Device: dev}, inUse); got != want { t.Errorf("candidateBacksInUse(%s) = %v, want %v", dev, got, want) } } }