Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

at icy/sntnrt 5.7 kB View raw
1package middleware 2 3import ( 4 "context" 5 "net/http" 6 "net/http/httptest" 7 "testing" 8 9 "github.com/bluesky-social/indigo/atproto/identity" 10 "github.com/bluesky-social/indigo/atproto/syntax" 11 "github.com/go-chi/chi/v5" 12 "tangled.org/core/appview/models" 13) 14 15func runCanonicalize(t *testing.T, method, urlPath, urlUser, urlRepo, handle string, repo *models.Repo) *httptest.ResponseRecorder { 16 t.Helper() 17 req := httptest.NewRequest(method, urlPath, nil) 18 rctx := chi.NewRouteContext() 19 rctx.URLParams.Add("user", urlUser) 20 rctx.URLParams.Add("repo", urlRepo) 21 ctx := context.WithValue(req.Context(), chi.RouteCtxKey, rctx) 22 id := identity.Identity{ 23 DID: syntax.DID("did:plc:boltless"), 24 Handle: syntax.Handle(handle), 25 } 26 ctx = context.WithValue(ctx, "resolvedId", id) 27 ctx = context.WithValue(ctx, "repo", repo) 28 req = req.WithContext(ctx) 29 30 rec := httptest.NewRecorder() 31 called := false 32 next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 33 called = true 34 w.WriteHeader(http.StatusOK) 35 }) 36 mw := Middleware{} 37 mw.CanonicalizeRepoURL()(next).ServeHTTP(rec, req) 38 if rec.Code == http.StatusFound { 39 if called { 40 t.Errorf("middleware both issued 302 and invoked next handler") 41 } 42 } 43 return rec 44} 45 46func TestCanonicalize_CanonicalUrlPassesThrough(t *testing.T) { 47 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "anemone"} 48 rec := runCanonicalize(t, "GET", "/boltless.dev/anemone/issues", "boltless.dev", "anemone", "boltless.dev", repo) 49 if rec.Code != http.StatusOK { 50 t.Errorf("canonical URL got %d, want 200; Location=%q", rec.Code, rec.Header().Get("Location")) 51 } 52} 53 54func TestCanonicalize_EmptyNameUsesRkeyAsSlug(t *testing.T) { 55 repo := &models.Repo{Did: "did:plc:boltless", Name: "", Rkey: "anemone"} 56 rec := runCanonicalize(t, "GET", "/boltless.dev/anemone/pulls", "boltless.dev", "anemone", "boltless.dev", repo) 57 if rec.Code != http.StatusOK { 58 t.Errorf("rkey-as-slug canonical URL got %d, want 200; Location=%q", rec.Code, rec.Header().Get("Location")) 59 } 60} 61 62func TestCanonicalize_EmptyNameOwnerDidRedirectsToHandleRkey(t *testing.T) { 63 repo := &models.Repo{Did: "did:plc:boltless", Name: "", Rkey: "anemone"} 64 rec := runCanonicalize(t, "GET", "/did:plc:boltless/anemone/pulls", "did:plc:boltless", "anemone", "boltless.dev", repo) 65 if rec.Code != http.StatusFound { 66 t.Fatalf("got %d, want 302", rec.Code) 67 } 68 if got, want := rec.Header().Get("Location"), "/boltless.dev/anemone/pulls"; got != want { 69 t.Errorf("Location = %q, want %q", got, want) 70 } 71} 72 73func TestCanonicalize_HandleSlashTIDRedirectsToName(t *testing.T) { 74 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "3kabcxyz"} 75 rec := runCanonicalize(t, "GET", "/boltless.dev/3kabcxyz/issues", "boltless.dev", "3kabcxyz", "boltless.dev", repo) 76 if rec.Code != http.StatusFound { 77 t.Fatalf("got %d, want 302", rec.Code) 78 } 79 if got, want := rec.Header().Get("Location"), "/boltless.dev/anemone/issues"; got != want { 80 t.Errorf("Location = %q, want %q", got, want) 81 } 82} 83 84func TestCanonicalize_OwnerDidRedirectsToHandle(t *testing.T) { 85 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "anemone"} 86 rec := runCanonicalize(t, "GET", "/did:plc:boltless/anemone/pulls/3", "did:plc:boltless", "anemone", "boltless.dev", repo) 87 if rec.Code != http.StatusFound { 88 t.Fatalf("got %d, want 302", rec.Code) 89 } 90 if got, want := rec.Header().Get("Location"), "/boltless.dev/anemone/pulls/3"; got != want { 91 t.Errorf("Location = %q, want %q", got, want) 92 } 93} 94 95func TestCanonicalize_OwnerDidAndTIDRedirectsToCanonical(t *testing.T) { 96 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "3kabcxyz"} 97 rec := runCanonicalize(t, "GET", "/did:plc:boltless/3kabcxyz", "did:plc:boltless", "3kabcxyz", "boltless.dev", repo) 98 if rec.Code != http.StatusFound { 99 t.Fatalf("got %d, want 302", rec.Code) 100 } 101 if got, want := rec.Header().Get("Location"), "/boltless.dev/anemone"; got != want { 102 t.Errorf("Location = %q, want %q", got, want) 103 } 104} 105 106func TestCanonicalize_PreservesQueryString(t *testing.T) { 107 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "anemone"} 108 rec := runCanonicalize(t, "GET", "/did:plc:boltless/anemone/issues?state=closed&page=2", "did:plc:boltless", "anemone", "boltless.dev", repo) 109 if got, want := rec.Header().Get("Location"), "/boltless.dev/anemone/issues?state=closed&page=2"; got != want { 110 t.Errorf("Location = %q, want %q", got, want) 111 } 112} 113 114func TestCanonicalize_PostNotRedirected(t *testing.T) { 115 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "anemone"} 116 rec := runCanonicalize(t, "POST", "/did:plc:boltless/anemone/issues", "did:plc:boltless", "anemone", "boltless.dev", repo) 117 if rec.Code != http.StatusOK { 118 t.Errorf("POST on non-canonical URL got %d, want 200; Location=%q", rec.Code, rec.Header().Get("Location")) 119 } 120} 121 122func TestCanonicalize_InvalidHandlePassesThrough(t *testing.T) { 123 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "anemone"} 124 rec := runCanonicalize(t, "GET", "/did:plc:boltless/anemone", "did:plc:boltless", "anemone", string(syntax.HandleInvalid), repo) 125 if rec.Code != http.StatusOK { 126 t.Errorf("invalid handle got %d, want 200; Location=%q", rec.Code, rec.Header().Get("Location")) 127 } 128} 129 130func TestCanonicalize_DotGitSuffixStripped(t *testing.T) { 131 repo := &models.Repo{Did: "did:plc:boltless", Name: "anemone", Rkey: "anemone"} 132 rec := runCanonicalize(t, "GET", "/boltless.dev/anemone.git/", "boltless.dev", "anemone.git", "boltless.dev", repo) 133 if rec.Code != http.StatusOK { 134 t.Errorf(".git on canonical name got %d, want 200; Location=%q", rec.Code, rec.Header().Get("Location")) 135 } 136}