Media build part 1 (unreleased): real restart (R-1026), media apps on every PRESENT drive via an owned compose override (R-1023), dead-drive check from mountinfo, removal never deletes shared/:ro binds (R-1027), safety list knows userdata (R-1032), no drive question for media apps (R-1031)
gates / gates (push) Successful in 46s
gates / gates (push) Successful in 46s
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
1 parent
331be17e1e
commit
78c894234c
13 files changed
+984
-9
No files matched your search
@@ -0,0 +1,72 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user