package exchange import ( "context" "errors" "fmt" "net/http" "net/http/httptest" "strings" "testing" "git.fabledsword.com/bvandeusen/minstrel/internal/indexer" ) func TestTorrent_SendsTheKeyOnlyWhenSet(t *testing.T) { auth := make(chan string, 2) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { auth <- r.Header.Get("Authorization") _, _ = w.Write([]byte(`{"infohash": "` + strings.Repeat("a", 40) + `", "files_count": 12}`)) })) defer srv.Close() for _, key := range []string{"", "k"} { c := &Client{Config: Config{BaseURL: srv.URL, APIKey: key}} d, err := c.Torrent(context.Background(), strings.Repeat("A", 40)) if err != nil || d.FilesCount != 12 { t.Fatalf("key %q: detail %+v err %v", key, d, err) } } if without, with := <-auth, <-auth; without != "" || with != "Bearer k" { t.Errorf("Authorization = %q then %q, want none without a key and a bearer with one", without, with) } } func TestTorrent_TellsAnUncrawledTorrentFromAnotherService(t *testing.T) { for name, tc := range map[string]struct { status int body string want error }{ "Exchange has not crawled it": {http.StatusNotFound, `{"error": "unknown torrent"}`, ErrUnknown}, "not FabledExchange": {http.StatusNotFound, `404`, ErrUnreachable}, "a refused key": {http.StatusUnauthorized, `{"error": "bad key"}`, ErrAuth}, } { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(tc.status) _, _ = w.Write([]byte(tc.body)) })) _, err := (&Client{Config: Config{BaseURL: srv.URL}}).Torrent(context.Background(), strings.Repeat("0", 40)) srv.Close() if !errors.Is(err, tc.want) { t.Errorf("%s: err = %v, want %v", name, err, tc.want) } } } func TestSearch_PagesAndKeepsMeasuredSwarmsOnly(t *testing.T) { queries := make(chan string, 4) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { queries <- r.URL.RawQuery offset := r.URL.Query().Get("offset") var rows []string if offset == "0" { for i := 0; i < SearchLimit; i++ { rows = append(rows, fmt.Sprintf(`{"infohash": "%040x", "name": "r%d", "content_type": "music", "seeders": 5, "swarm_known": %t}`, i, i, i == 0)) } } else { // A repeat of page one's first hash, which must not be listed twice. rows = append(rows, fmt.Sprintf(`{"infohash": "%040x", "name": "again"}`, 0)) } _, _ = fmt.Fprintf(w, `{"total": %d, "results": [%s]}`, SearchLimit+1, strings.Join(rows, ",")) })) defer srv.Close() c := &Client{Code: "exchange", Config: Config{BaseURL: srv.URL}} results, err := c.Search(context.Background(), indexer.Query{Text: "x", Categories: indexer.MusicCategories}) if err != nil { t.Fatalf("search: %v", err) } close(queries) var asked []string for q := range queries { asked = append(asked, q) } if len(asked) != 2 || !strings.Contains(asked[0], "type=music") { t.Errorf("queries = %v, want two pages asking for music", asked) } if len(results) != SearchLimit { t.Errorf("results = %d, want %d (the repeat dropped)", len(results), SearchLimit) } if r := results[0]; !r.SwarmKnown || r.Seeders != 5 || r.Category != 3000 || r.Source != "exchange" || !strings.HasPrefix(r.Magnet, "magnet:") { t.Errorf("first = %+v", r) } if r := results[1]; r.SwarmKnown || r.Seeders != 0 { t.Errorf("an unmeasured swarm reported seeders: %+v", r) } } func TestSearch_ARefusedKeyReadsAsAuth(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusForbidden) })) defer srv.Close() _, err := (&Client{Config: Config{BaseURL: srv.URL}}).Search(context.Background(), indexer.Query{Text: "x"}) if !errors.Is(err, indexer.ErrAuth) { t.Fatalf("err = %v, want indexer.ErrAuth", err) } }