package coverart import ( "context" "errors" "net/http" "net/http/httptest" "strings" "testing" "time" ) // newMBCAAProviderForTest registers a fresh mbcaaProvider pointing at // a test server. func newMBCAAProviderForTest(t *testing.T, mockURL string) *mbcaaProvider { t.Helper() resetRegistryForTests() t.Cleanup(resetRegistryForTests) p := newMBCAAProvider(FetcherConfig{ BaseURL: mockURL, UserAgent: "Minstrel/test (https://example.com)", MinPeriod: 0, HTTPClient: &http.Client{Timeout: 5 * time.Second}, }) Register(p) p.enabled.Store(true) return p } func TestMBCAAProvider_ID(t *testing.T) { resetRegistryForTests() defer resetRegistryForTests() p := newMBCAAProvider(FetcherConfig{}) if p.ID() != "mbcaa" { t.Errorf("ID = %q, want mbcaa", p.ID()) } if p.DisplayName() != "Cover Art Archive" { t.Errorf("DisplayName = %q, want Cover Art Archive", p.DisplayName()) } if p.RequiresAPIKey() { t.Error("RequiresAPIKey = true, want false") } if !p.DefaultEnabled() { t.Error("DefaultEnabled = false, want true") } } func TestMBCAAProvider_FetchAlbumCover_Success(t *testing.T) { imageBody := []byte("FAKE_JPEG") srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !strings.Contains(r.URL.Path, "/release/abc-123/front-500") { http.Error(w, "wrong path: "+r.URL.Path, http.StatusBadRequest) return } w.Header().Set("Content-Type", "image/jpeg") _, _ = w.Write(imageBody) })) defer srv.Close() p := newMBCAAProviderForTest(t, srv.URL) body, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "abc-123"}) if err != nil { t.Fatalf("FetchAlbumCover err = %v, want nil", err) } if string(body) != string(imageBody) { t.Errorf("body = %q, want %q", body, imageBody) } } func TestMBCAAProvider_FetchAlbumCover_NotFound(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "not found", http.StatusNotFound) })) defer srv.Close() p := newMBCAAProviderForTest(t, srv.URL) _, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "missing"}) if !errors.Is(err, ErrNotFound) { t.Errorf("err = %v, want ErrNotFound", err) } } func TestMBCAAProvider_FetchAlbumCover_DisabledReturnsNotFound(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { t.Error("server should not be hit when provider is disabled") })) defer srv.Close() p := newMBCAAProviderForTest(t, srv.URL) p.enabled.Store(false) _, err := p.FetchAlbumCover(context.Background(), AlbumRef{MBID: "any"}) if !errors.Is(err, ErrNotFound) { t.Errorf("err = %v, want ErrNotFound (disabled)", err) } } func TestMBCAAProvider_Configure_TogglesEnabled(t *testing.T) { resetRegistryForTests() defer resetRegistryForTests() p := newMBCAAProvider(FetcherConfig{}) if err := p.Configure(ProviderSettings{Enabled: true}); err != nil { t.Fatalf("Configure: %v", err) } if !p.enabled.Load() { t.Error("after Configure(Enabled: true), enabled = false") } if err := p.Configure(ProviderSettings{Enabled: false}); err != nil { t.Fatalf("Configure: %v", err) } if p.enabled.Load() { t.Error("after Configure(Enabled: false), enabled = true") } } func TestMBCAAProvider_TestConnection_TreatsNotFoundAsSuccess(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "not found", http.StatusNotFound) })) defer srv.Close() p := newMBCAAProviderForTest(t, srv.URL) if err := p.TestConnection(context.Background()); err != nil { t.Errorf("TestConnection err = %v, want nil (404 should be treated as connection ok)", err) } } func TestMBCAAProvider_TestConnection_PropagatesTransient(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { http.Error(w, "boom", http.StatusInternalServerError) })) defer srv.Close() p := newMBCAAProviderForTest(t, srv.URL) if err := p.TestConnection(context.Background()); err == nil { t.Error("TestConnection err = nil, want non-nil for 500") } } func TestNewMBCAAProviderFromConfig_ReplacesRegisteredConfig(t *testing.T) { resetRegistryForTests() defer resetRegistryForTests() // Pre-register with default config (mimics init() behaviour). Register(newMBCAAProvider(FetcherConfig{})) cfg := FetcherConfig{ UserAgent: "Minstrel/test-replaced (x)", MinPeriod: 100 * time.Millisecond, } NewMBCAAProviderFromConfig(cfg) p, err := ProviderByID("mbcaa") if err != nil { t.Fatalf("ProviderByID: %v", err) } mp := p.(*mbcaaProvider) // Verify the cfg was replaced on the registered instance. mp.mu.Lock() gotUA := mp.cfg.UserAgent mp.mu.Unlock() if gotUA != "Minstrel/test-replaced (x)" { t.Errorf("cfg.UserAgent = %q, want %q", gotUA, "Minstrel/test-replaced (x)") } }