package appbackup import "testing" // TestDeriveStackName_KnownCrossRef asserts M19: deriveStackName cross-references the deployed-stack set // so a stack whose slug ends in a DB-role token (e.g. `my-cache`) is NOT misattributed by pure // suffix-stripping. The `my-cache` case fails on the pre-fix code (which stripped it to `my`). func TestDeriveStackName_KnownCrossRef(t *testing.T) { known := map[string]bool{"romm": true, "my-cache": true, "paperless-ngx": true} cases := []struct { container string want string note string }{ {"romm-postgres", "romm", "role suffix of a real stack → strip"}, {"my-cache", "my-cache", "container name IS a real stack → do NOT strip to 'my'"}, // pre-fix: "my" {"my-cache-postgres", "my-cache", "strip role, result is a known stack"}, // pre-fix: "my-cache" (ok) — but via prefix here {"paperless-ngx-postgres", "paperless-ngx", "multi-hyphen stack, role suffix"}, {"romm_postgres", "romm", "underscore-separated compose name → longest known prefix"}, {"romm-1", "romm", "compose numeric suffix → longest known prefix"}, } for _, c := range cases { if got := deriveStackName(c.container, known); got != c.want { t.Errorf("deriveStackName(%q, known) = %q, want %q (%s)", c.container, got, c.want, c.note) } } } // TestDeriveStackName_LegacyFallback asserts the nil/empty-known fast path preserves the old behaviour // (pure suffix-strip), so callers without a stack list (e.g. appexport) don't regress. func TestDeriveStackName_LegacyFallback(t *testing.T) { cases := []struct { container string want string }{ {"romm-postgres", "romm"}, {"paperless-ngx-postgres", "paperless-ngx"}, {"my-cache", "my"}, // legacy strips the role-token suffix {"unknown-db", "unknown"}, // legacy strip {"standalone", "standalone"}, } for _, c := range cases { if got := deriveStackName(c.container, nil); got != c.want { t.Errorf("deriveStackName(%q, nil) = %q, want %q (legacy)", c.container, got, c.want) } // empty (non-nil) map must behave identically to nil if got := deriveStackName(c.container, map[string]bool{}); got != c.want { t.Errorf("deriveStackName(%q, {}) = %q, want %q (legacy)", c.container, got, c.want) } } } // TestDeriveStackName_UnknownContainerFallsBack asserts that when the container matches no known stack at // all, the result falls back to the suffix-strip candidate (no spurious prefix match). func TestDeriveStackName_UnknownContainerFallsBack(t *testing.T) { known := map[string]bool{"romm": true} if got := deriveStackName("grafana-db", known); got != "grafana" { t.Fatalf("deriveStackName(grafana-db, {romm}) = %q, want grafana (fallback strip)", got) } // must NOT match "romm" as a prefix of an unrelated name if got := deriveStackName("rommother-db", known); got != "rommother" { t.Fatalf("deriveStackName(rommother-db) = %q, want rommother (no false prefix match)", got) } }