feat(server/m7-353): coverart.Fetcher MBCAA HTTP client + rate limiter
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user