From 22f03a5fe80a62828b915da63d5a1c6cec39ec41 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Fri, 8 May 2026 23:07:47 -0400 Subject: [PATCH] test(server/admin): cover new test endpoint response shape - Updates the happy-path test stub to handle the three list endpoints Lidarr exposes (qualityprofile / metadataprofile / rootfolder) and asserts profiles + folders make it through to the response. - Adds a partial-failure case where one list endpoint 5xxs; verifies ok=true, the failing list is omitted, and list_errors carries its bucket code. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/api/admin_lidarr_test.go | 79 ++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/internal/api/admin_lidarr_test.go b/internal/api/admin_lidarr_test.go index d0e882b5..f5b1618e 100644 --- a/internal/api/admin_lidarr_test.go +++ b/internal/api/admin_lidarr_test.go @@ -216,9 +216,20 @@ func TestHandleTestLidarrConnection_HappyPath(t *testing.T) { resetLidarrState(t, h) admin := seedAdminUser(t, h) - stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - _, _ = w.Write([]byte(`{"version":"2.0.5"}`)) + switch r.URL.Path { + case "/api/v1/system/status": + _, _ = w.Write([]byte(`{"version":"2.0.5"}`)) + case "/api/v1/qualityprofile": + _, _ = w.Write([]byte(`[{"id":1,"name":"FLAC"},{"id":2,"name":"MP3-320"}]`)) + case "/api/v1/metadataprofile": + _, _ = w.Write([]byte(`[{"id":1,"name":"Standard"}]`)) + case "/api/v1/rootfolder": + _, _ = w.Write([]byte(`[{"path":"/music","accessible":true,"freeSpace":12345}]`)) + default: + http.NotFound(w, r) + } })) t.Cleanup(stub.Close) @@ -243,6 +254,70 @@ func TestHandleTestLidarrConnection_HappyPath(t *testing.T) { if resp["version"] != "2.0.5" { t.Errorf("version = %v, want 2.0.5", resp["version"]) } + qp, ok := resp["quality_profiles"].([]any) + if !ok || len(qp) != 2 { + t.Errorf("quality_profiles = %v, want 2 entries", resp["quality_profiles"]) + } + mp, ok := resp["metadata_profiles"].([]any) + if !ok || len(mp) != 1 { + t.Errorf("metadata_profiles = %v, want 1 entry", resp["metadata_profiles"]) + } + rf, ok := resp["root_folders"].([]any) + if !ok || len(rf) != 1 { + t.Errorf("root_folders = %v, want 1 entry", resp["root_folders"]) + } + if _, present := resp["list_errors"]; present { + t.Errorf("list_errors should be omitted when all lists succeed; got %v", resp["list_errors"]) + } +} + +// TestHandleTestLidarrConnection_PartialListFailure verifies that POST /test +// against a Lidarr that responds OK to the ping + two of three lists still +// reports ok=true with the failing list omitted and named in list_errors. +func TestHandleTestLidarrConnection_PartialListFailure(t *testing.T) { + h, _ := testHandlers(t) + resetLidarrState(t, h) + admin := seedAdminUser(t, h) + + stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + switch r.URL.Path { + case "/api/v1/system/status": + _, _ = w.Write([]byte(`{"version":"2.0.5"}`)) + case "/api/v1/qualityprofile": + _, _ = w.Write([]byte(`[{"id":1,"name":"FLAC"}]`)) + case "/api/v1/metadataprofile": + http.Error(w, "boom", http.StatusInternalServerError) + case "/api/v1/rootfolder": + _, _ = w.Write([]byte(`[{"path":"/music","accessible":true,"freeSpace":12345}]`)) + default: + http.NotFound(w, r) + } + })) + t.Cleanup(stub.Close) + + body := []byte(`{"base_url":"` + stub.URL + `","api_key":"k"}`) + w := doAdminReq(t, h, http.MethodPost, "/api/admin/lidarr/test", body, admin) + if w.Code != http.StatusOK { + t.Fatalf("status = %d, want 200; body = %s", w.Code, w.Body.String()) + } + var resp map[string]any + if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { + t.Fatalf("decode: %v; body = %s", err, w.Body.String()) + } + if resp["ok"] != true { + t.Errorf("ok = %v, want true", resp["ok"]) + } + if _, present := resp["metadata_profiles"]; present { + t.Errorf("metadata_profiles should be omitted on failure; got %v", resp["metadata_profiles"]) + } + listErrs, ok := resp["list_errors"].(map[string]any) + if !ok { + t.Fatalf("list_errors missing or wrong shape: %v", resp["list_errors"]) + } + if _, present := listErrs["metadata_profiles"]; !present { + t.Errorf("list_errors.metadata_profiles should be present, got %v", listErrs) + } } // TestHandleTestLidarrConnection_Unreachable verifies that POST /test against