Add the Config view: edit and save the settings, applied without a restart
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -109,3 +109,82 @@ func TestCoverStyleValidation(t *testing.T) {
|
||||
t.Error("unknown style accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveRoundTripAndPermissions(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "config.json")
|
||||
covers := false
|
||||
cfg := &Config{
|
||||
Radarr: Arr{Service: Service{URL: "http://r:7878", APIKey: "rk"}, DefaultQualityProfile: "HD-1080p"},
|
||||
Sonarr: Arr{Service: Service{URL: "http://s:8989", APIKey: "sk"}},
|
||||
SABnzbd: Service{URL: "http://a:8080", APIKey: "ak"},
|
||||
UI: UI{RefreshSeconds: 5, Covers: &covers, CoverStyle: "sextant", Bell: true},
|
||||
}
|
||||
if err := Save(path, cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
info, err := os.Stat(path)
|
||||
if err != nil || info.Mode().Perm() != 0o600 {
|
||||
t.Fatalf("new file mode = %v, want 0600 (it holds API keys): %v", info.Mode().Perm(), err)
|
||||
}
|
||||
got, err := LoadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Radarr.DefaultQualityProfile != "HD-1080p" || got.UI.RefreshSeconds != 5 || got.UI.Covers == nil || *got.UI.Covers || got.UI.CoverStyle != "sextant" || !got.UI.Bell {
|
||||
t.Errorf("round trip lost values: %+v", got)
|
||||
}
|
||||
// Unset optional settings stay out of the file.
|
||||
if data, _ := os.ReadFile(path); strings.Contains(string(data), "notify_downloads") || strings.Contains(string(data), "default_root_folder") {
|
||||
t.Errorf("unset settings written:\n%s", data)
|
||||
}
|
||||
|
||||
// An existing file keeps its permissions and no temporary file is left behind.
|
||||
if err := os.Chmod(path, 0o640); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := Save(path, cfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if info, _ := os.Stat(path); info.Mode().Perm() != 0o640 {
|
||||
t.Errorf("existing mode changed to %v", info.Mode().Perm())
|
||||
}
|
||||
entries, _ := os.ReadDir(dir)
|
||||
if len(entries) != 1 {
|
||||
t.Errorf("leftover files in the config directory: %v", entries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileIgnoresEnvironmentAndDefaults(t *testing.T) {
|
||||
t.Setenv("ARR_TUI_RADARR_APIKEY", "from-env")
|
||||
path := filepath.Join(t.TempDir(), "config.json")
|
||||
os.WriteFile(path, []byte(`{"radarr":{"url":"http://r/","apikey":"from-file"},"sonarr":{"url":"http://s","apikey":"k"},"sabnzbd":{"url":"http://a","apikey":"k"}}`), 0o600)
|
||||
|
||||
raw, err := LoadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if raw.Radarr.APIKey != "from-file" || raw.Radarr.URL != "http://r/" || raw.UI.RefreshSeconds != 0 {
|
||||
t.Errorf("raw = %+v: environment, trailing slash trimming and defaults must not be applied", raw)
|
||||
}
|
||||
eff, err := raw.Effective(os.Getenv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if eff.Radarr.APIKey != "from-env" || eff.Radarr.URL != "http://r" || eff.UI.RefreshSeconds != 3 {
|
||||
t.Errorf("effective = %+v", eff)
|
||||
}
|
||||
if raw.Radarr.APIKey != "from-file" {
|
||||
t.Error("Effective must not modify the raw config")
|
||||
}
|
||||
if got := Overrides(os.Getenv); len(got) != 1 || got["radarr.apikey"] != "ARR_TUI_RADARR_APIKEY" {
|
||||
t.Errorf("overrides = %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEffectiveValidates(t *testing.T) {
|
||||
raw := &Config{Radarr: Arr{Service: Service{URL: "ftp://x", APIKey: "k"}}}
|
||||
if _, err := raw.Effective(func(string) string { return "" }); err == nil {
|
||||
t.Error("an invalid config must not become effective")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user