a love letter to tangled (android, iOS, and a search API)
1package backfill
2
3import (
4 "context"
5 "encoding/json"
6 "net/http"
7 "net/http/httptest"
8 "net/url"
9 "reflect"
10 "testing"
11)
12
13func TestHTTPLightrailClientListReposByCollectionSinglePage(t *testing.T) {
14 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
15 if r.URL.Path != "/xrpc/"+listReposByCollectionNSID {
16 http.NotFound(w, r)
17 return
18 }
19 _ = json.NewEncoder(w).Encode(map[string]any{
20 "repos": []map[string]string{
21 {"did": "did:plc:a"},
22 {"did": "did:plc:b"},
23 },
24 })
25 }))
26 defer srv.Close()
27
28 client := NewHTTPLightrailClient()
29 dids, err := client.ListReposByCollection(
30 context.Background(), srv.URL, []string{"sh.tangled.repo"}, 100,
31 )
32 if err != nil {
33 t.Fatalf("list repos: %v", err)
34 }
35
36 want := []string{"did:plc:a", "did:plc:b"}
37 if !reflect.DeepEqual(dids, want) {
38 t.Fatalf("dids: got %#v want %#v", dids, want)
39 }
40}
41
42func TestHTTPLightrailClientListReposByCollectionPaginatesAndDedupes(t *testing.T) {
43 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
44 query := r.URL.Query()
45 cursor := query.Get("cursor")
46 switch cursor {
47 case "":
48 _ = json.NewEncoder(w).Encode(map[string]any{
49 "cursor": "page-2",
50 "repos": []map[string]string{
51 {"did": "did:plc:a"},
52 {"did": "did:plc:b"},
53 },
54 })
55 case "page-2":
56 _ = json.NewEncoder(w).Encode(map[string]any{
57 "repos": []map[string]string{
58 {"did": "did:plc:b"},
59 {"did": "did:plc:c"},
60 },
61 })
62 default:
63 t.Fatalf("unexpected cursor %q", cursor)
64 }
65 }))
66 defer srv.Close()
67
68 client := NewHTTPLightrailClient()
69 dids, err := client.ListReposByCollection(
70 context.Background(), srv.URL, []string{"sh.tangled.repo"}, 2,
71 )
72 if err != nil {
73 t.Fatalf("list repos: %v", err)
74 }
75
76 want := []string{"did:plc:a", "did:plc:b", "did:plc:c"}
77 if !reflect.DeepEqual(dids, want) {
78 t.Fatalf("dids: got %#v want %#v", dids, want)
79 }
80}
81
82func TestHTTPLightrailClientListReposByCollectionAddsRepeatedCollections(t *testing.T) {
83 var got url.Values
84 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
85 got = r.URL.Query()
86 _ = json.NewEncoder(w).Encode(map[string]any{"repos": []map[string]string{}})
87 }))
88 defer srv.Close()
89
90 client := NewHTTPLightrailClient()
91 if _, err := client.ListReposByCollection(
92 context.Background(),
93 srv.URL,
94 []string{"sh.tangled.actor.profile", "sh.tangled.repo"},
95 50,
96 ); err != nil {
97 t.Fatalf("list repos: %v", err)
98 }
99
100 if got.Get("limit") != "50" {
101 t.Fatalf("limit: got %q", got.Get("limit"))
102 }
103 if values := got["collection"]; !reflect.DeepEqual(values, []string{
104 "sh.tangled.actor.profile",
105 "sh.tangled.repo",
106 }) {
107 t.Fatalf("collections: got %#v", values)
108 }
109}
110
111func TestHTTPLightrailClientListReposByCollectionErrorsOnNonSuccess(t *testing.T) {
112 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
113 http.Error(w, `{"message":"boom"}`, http.StatusBadGateway)
114 }))
115 defer srv.Close()
116
117 client := NewHTTPLightrailClient()
118 if _, err := client.ListReposByCollection(
119 context.Background(), srv.URL, []string{"sh.tangled.repo"}, 100,
120 ); err == nil {
121 t.Fatal("expected error")
122 }
123}