Monorepo for Tangled tangled.org
5

Configure Feed

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

at icy/sntnrt 2.9 kB View raw
1package oauth 2 3import ( 4 "context" 5 "io" 6 "log/slog" 7 "net/http" 8 "net/http/httptest" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/bluesky-social/indigo/atproto/syntax" 14 "tangled.org/core/appview/config" 15 "tangled.org/core/consts" 16) 17 18type fakeAcl struct { 19 member bool 20 gotHost string 21 gotDid string 22} 23 24func (f *fakeAcl) InvalidateMembers(host string) {} 25 26func (f *fakeAcl) IsKnotMember(ctx context.Context, host, userDid string) bool { 27 f.gotHost = host 28 f.gotDid = userDid 29 return f.member 30} 31 32func TestAddToDefaultKnot_ShortCircuitsWhenAlreadyMember(t *testing.T) { 33 acl := &fakeAcl{member: true} 34 o := &OAuth{ 35 Acl: acl, 36 Logger: slog.New(slog.NewTextHandler(io.Discard, nil)), 37 Config: &config.Config{ 38 Core: config.CoreConfig{Dev: true}, 39 Knot: config.KnotConfig{Default: consts.DefaultKnot}, 40 }, 41 } 42 43 o.addToDefaultKnot(syntax.DID("did:plc:akshay")) 44 45 if acl.gotDid != "did:plc:akshay" { 46 t.Fatalf("IsKnotMember did = %q, want did:plc:akshay", acl.gotDid) 47 } 48 if acl.gotHost != consts.DefaultKnot { 49 t.Fatalf("IsKnotMember host = %q, want %q", acl.gotHost, consts.DefaultKnot) 50 } 51} 52 53func TestAddMemberViaKnotAdmin_HonorsDeadline(t *testing.T) { 54 release := make(chan struct{}) 55 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 56 <-release 57 })) 58 defer srv.Close() 59 defer close(release) 60 61 o := &OAuth{Config: &config.Config{ 62 Core: config.CoreConfig{Dev: true}, 63 Knot: config.KnotConfig{AdminSecret: "hunter2"}, 64 }} 65 66 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 67 defer cancel() 68 69 done := make(chan error, 1) 70 go func() { 71 done <- o.addMemberViaKnotAdmin(ctx, strings.TrimPrefix(srv.URL, "http://"), syntax.DID("did:plc:whelk")) 72 }() 73 74 select { 75 case err := <-done: 76 if err == nil { 77 t.Fatal("a hung knot must surface an error, got nil") 78 } 79 case <-time.After(5 * time.Second): 80 t.Fatal("addMemberViaKnotAdmin blocked past its deadline; the request has no timeout") 81 } 82} 83 84func TestOnboardActionFor(t *testing.T) { 85 cases := []struct { 86 name string 87 state defaultKnotState 88 want onboardAction 89 }{ 90 {"native default knot with admin secret uses the admin api", defaultKnotState{native: true, adminSecretSet: true}, onboardViaAdminAPI}, 91 {"native default knot without admin secret is blocked", defaultKnotState{native: true, adminSecretSet: false}, onboardBlockedMissingSecret}, 92 {"legacy default knot with admin secret skips the legacy record", defaultKnotState{native: false, adminSecretSet: true}, onboardBlockedSecretSet}, 93 {"legacy default knot without admin secret writes the legacy record", defaultKnotState{native: false, adminSecretSet: false}, onboardViaRecord}, 94 } 95 for _, c := range cases { 96 t.Run(c.name, func(t *testing.T) { 97 if got := onboardActionFor(c.state); got != c.want { 98 t.Fatalf("onboardActionFor(%+v) = %d, want %d", c.state, got, c.want) 99 } 100 }) 101 } 102}