package stacks import ( "path/filepath" "testing" ) // R-1027 — „delete my data too" must never delete a read-only bind or the shared media library. MEASURED 2026-10-14 // on Tester 1: removing a throwaway Plex (a READER, `:ro`) with „delete data" deleted drive A's whole // `userdata/media`. The test asserts the EFFECT on a real tree: the library's files are still there, the app's own // folder is gone. // // COMPANION RED-PROOF (2026-10-15): make keepOnRemoval return "" → this test fails (the library and the :ro folder are // deleted). Restored. func TestRemoveStack_R1027_NeverDeletesSharedOrReadOnly(t *testing.T) { drive := t.TempDir() compose := "services:\n" + " app:\n" + " image: nginx:1.27\n" + " volumes:\n" + " - ${HDD_PATH}/appdata/app:/data\n" + " - " + drive + "/userdata/media:" + drive + "/userdata/media\n" + // a literal, rw, shared library (the drill shape) " - " + drive + "/userdata/documents/scans:/scans:ro\n" + // someone else's folder, read only " - app_cfg:/config\n" + "volumes:\n" + " app_cfg:\n" m, _, _ := newR442Manager(t, "app", compose, driveAppYAML(drive), drive) own := filepath.Join(drive, "appdata", "app", "state.db") film := filepath.Join(drive, "userdata", "media", "movies", "Nosferatu (1922)", "Nosferatu.mkv") scan := filepath.Join(drive, "userdata", "documents", "scans", "letter.pdf") plantFile(t, own) plantFile(t, film) plantFile(t, scan) resp, err := m.RemoveStack("app", true, nil) if err != nil { t.Fatalf("remove: %v", err) } if exists(own) { t.Errorf("the app's OWN folder must be deleted with delete-my-data: %s still exists", own) } if !exists(film) { t.Fatalf("the shared media library was DELETED by an app's removal (R-1027): %s is gone; resp=%+v", film, resp) } if !exists(scan) { t.Fatalf("a read-only bind was DELETED by an app's removal (R-1027): %s is gone", scan) } } // R-1032 — the safety list knows the userdata layout: the userdata root, the media library and its folders, the // download folders. COMPANION RED-PROOF: remove the R-1032 block from ProtectedHDDPaths → this test fails. Restored. func TestProtectedHDDPaths_R1032_UserdataLayout(t *testing.T) { p := ProtectedHDDPaths("/mnt/felhom-drives/hdd_1") for _, want := range []string{ "/mnt/felhom-drives/hdd_1/userdata", "/mnt/felhom-drives/hdd_1/userdata/media", "/mnt/felhom-drives/hdd_1/userdata/media/tv", "/mnt/felhom-drives/hdd_1/userdata/media/movies", "/mnt/felhom-drives/hdd_1/userdata/media/torrents", "/mnt/felhom-drives/hdd_1/userdata/media/transmission", "/mnt/felhom-drives/hdd_1/userdata/documents", "/mnt/felhom-drives/hdd_1/userdata/downloads", "/mnt/felhom-drives/hdd_1/media", // the old layout stays protected too } { if !p[want] { t.Errorf("ProtectedHDDPaths does not protect %s", want) } } if p["/mnt/felhom-drives/hdd_1/userdata/media/movies/Some Film"] { t.Error("a single film folder is not a top-level folder — the list must stay a list of roots") } }