package coverart import ( "context" "errors" "net/http" "net/http/httptest" "strings" "testing" "time" ) func TestFetcher_Success(t *testing.T) { 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", http.StatusBadRequest) return } w.Header().Set("Content-Type", "image/jpeg") _, _ = w.Write([]byte("FAKE_JPEG")) })) defer srv.Close() f := NewFetcher(FetcherConfig{ BaseURL: srv.URL, UserAgent: "Minstrel/test (https://example.com)", MinPeriod: 0, HTTPClient: srv.Client(), }) body, err := f.Fetch(context.Background(), "abc-123") if err != nil { t.Fatalf("Fetch: %v", err) } if string(body) != "FAKE_JPEG" { t.Errorf("body = %q, want FAKE_JPEG", string(body)) } } func TestFetcher_NotFound(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "not found", http.StatusNotFound) })) defer srv.Close() f := NewFetcher(FetcherConfig{BaseURL: srv.URL, UserAgent: "test", MinPeriod: 0, HTTPClient: srv.Client()}) _, err := f.Fetch(context.Background(), "missing") if !errors.Is(err, ErrNotFound) { t.Errorf("err = %v, want ErrNotFound", err) } } func TestFetcher_5xxIsTransient(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.Error(w, "boom", http.StatusInternalServerError) })) defer srv.Close() f := NewFetcher(FetcherConfig{BaseURL: srv.URL, UserAgent: "test", MinPeriod: 0, HTTPClient: srv.Client()}) _, err := f.Fetch(context.Background(), "any") if !errors.Is(err, ErrTransient) { t.Errorf("err = %v, want ErrTransient", err) } } func TestFetcher_SendsUserAgent(t *testing.T) { var seen string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { seen = r.Header.Get("User-Agent") _, _ = w.Write([]byte("ok")) })) defer srv.Close() f := NewFetcher(FetcherConfig{ BaseURL: srv.URL, UserAgent: "Minstrel/0.1 (https://example.org)", MinPeriod: 0, HTTPClient: srv.Client(), }) _, _ = f.Fetch(context.Background(), "ua-test") if seen != "Minstrel/0.1 (https://example.org)" { t.Errorf("UA = %q", seen) } } func TestFetcher_RateLimitSpacesCalls(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("ok")) })) defer srv.Close() f := NewFetcher(FetcherConfig{ BaseURL: srv.URL, UserAgent: "test", MinPeriod: 150 * time.Millisecond, HTTPClient: srv.Client(), }) start := time.Now() _, _ = f.Fetch(context.Background(), "a") _, _ = f.Fetch(context.Background(), "b") elapsed := time.Since(start) if elapsed < 150*time.Millisecond { t.Errorf("two calls in %v — rate limiter not enforcing", elapsed) } } func TestFetcher_EmptyMBID(t *testing.T) { f := NewFetcher(FetcherConfig{UserAgent: "test", MinPeriod: 0}) _, err := f.Fetch(context.Background(), "") if err == nil { t.Error("expected error for empty mbid") } }