package providers import ( "context" "io" "net/http" "net/http/httptest" "strings" "sync/atomic" "testing" ) func TestIGDBSearch(t *testing.T) { var tokenHits int32 tokenSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { atomic.AddInt32(&tokenHits, 1) if r.URL.Query().Get("grant_type") != "client_credentials" { t.Errorf("grant_type = %q", r.URL.Query().Get("grant_type")) } w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"access_token":"tok-123","expires_in":5184000}`)) })) defer tokenSrv.Close() var gotBody, gotClientID, gotAuth string apiSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { b, _ := io.ReadAll(r.Body) gotBody = string(b) gotClientID = r.Header.Get("Client-ID") gotAuth = r.Header.Get("Authorization") w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`[ { "id": 1029, "name": "Sonic the Hedgehog", "summary": "A fast blue hedgehog.", "first_release_date": 677635200, "cover": {"url": "//images.igdb.com/igdb/image/upload/t_thumb/co1234.jpg"} } ]`)) })) defer apiSrv.Close() p := NewIGDB("client-id", "client-secret") p.TokenURL = tokenSrv.URL p.BaseURL = apiSrv.URL cands, err := p.Search(context.Background(), Query{Title: "Sonic"}) if err != nil { t.Fatalf("Search: %v", err) } if len(cands) != 1 { t.Fatalf("got %d candidates, want 1", len(cands)) } c := cands[0] if c.Title != "Sonic the Hedgehog" { t.Errorf("Title = %q", c.Title) } if c.ExternalID != "1029" { t.Errorf("ExternalID = %q", c.ExternalID) } if c.Year != 1991 { t.Errorf("Year = %d, want 1991", c.Year) } if c.CoverURL != "https://images.igdb.com/igdb/image/upload/t_cover_big/co1234.jpg" { t.Errorf("CoverURL = %q (want https and t_cover_big)", c.CoverURL) } if !strings.Contains(gotBody, `search "Sonic"`) { t.Errorf("query body = %q", gotBody) } if gotClientID != "client-id" || gotAuth != "Bearer tok-123" { t.Errorf("headers: Client-ID=%q Authorization=%q", gotClientID, gotAuth) } // A second search must reuse the cached token, not re-authenticate. if _, err := p.Search(context.Background(), Query{Title: "Sonic 2"}); err != nil { t.Fatal(err) } if n := atomic.LoadInt32(&tokenHits); n != 1 { t.Errorf("token endpoint hit %d times, want 1 (token should be cached)", n) } } func TestIGDBWithoutCredentialsDoesNothing(t *testing.T) { p := NewIGDB("", "") cands, err := p.Search(context.Background(), Query{Title: "Sonic"}) if err != nil { t.Fatalf("Search: %v", err) } if len(cands) != 0 { t.Errorf("got %d candidates with no credentials, want 0", len(cands)) } }