Vibe-guided bskyoauth and custom repo example code in Golang 馃 probably not safe to use in prod
1package bskyoauth
2
3import (
4 "context"
5 "crypto/ecdsa"
6 "crypto/elliptic"
7 "crypto/rand"
8 "testing"
9 "time"
10)
11
12func TestIsAccessTokenExpired(t *testing.T) {
13 tests := []struct {
14 name string
15 expiresAt time.Time
16 buffer time.Duration
17 expectedExpired bool
18 }{
19 {
20 name: "token expired 1 hour ago",
21 expiresAt: time.Now().Add(-1 * time.Hour),
22 buffer: 0,
23 expectedExpired: true,
24 },
25 {
26 name: "token expires in 1 hour no buffer",
27 expiresAt: time.Now().Add(1 * time.Hour),
28 buffer: 0,
29 expectedExpired: false,
30 },
31 {
32 name: "token expires in 10 minutes with 15 minute buffer",
33 expiresAt: time.Now().Add(10 * time.Minute),
34 buffer: 15 * time.Minute,
35 expectedExpired: true,
36 },
37 {
38 name: "token expires in 30 minutes with 5 minute buffer",
39 expiresAt: time.Now().Add(30 * time.Minute),
40 buffer: 5 * time.Minute,
41 expectedExpired: false,
42 },
43 {
44 name: "no expiration time set",
45 expiresAt: time.Time{},
46 buffer: 5 * time.Minute,
47 expectedExpired: false,
48 },
49 }
50
51 for _, tt := range tests {
52 t.Run(tt.name, func(t *testing.T) {
53 session := &Session{
54 AccessTokenExpiresAt: tt.expiresAt,
55 }
56
57 expired := session.IsAccessTokenExpired(tt.buffer)
58 if expired != tt.expectedExpired {
59 t.Errorf("expected expired=%v, got %v", tt.expectedExpired, expired)
60 }
61 })
62 }
63}
64
65func TestIsRefreshTokenExpired(t *testing.T) {
66 tests := []struct {
67 name string
68 expiresAt time.Time
69 expectedExpired bool
70 }{
71 {
72 name: "refresh token expired",
73 expiresAt: time.Now().Add(-1 * time.Hour),
74 expectedExpired: true,
75 },
76 {
77 name: "refresh token valid",
78 expiresAt: time.Now().Add(24 * time.Hour),
79 expectedExpired: false,
80 },
81 {
82 name: "no expiration time set",
83 expiresAt: time.Time{},
84 expectedExpired: false,
85 },
86 }
87
88 for _, tt := range tests {
89 t.Run(tt.name, func(t *testing.T) {
90 session := &Session{
91 RefreshTokenExpiresAt: tt.expiresAt,
92 }
93
94 expired := session.IsRefreshTokenExpired()
95 if expired != tt.expectedExpired {
96 t.Errorf("expected expired=%v, got %v", tt.expectedExpired, expired)
97 }
98 })
99 }
100}
101
102func TestTimeUntilAccessTokenExpiry(t *testing.T) {
103 tests := []struct {
104 name string
105 expiresAt time.Time
106 expectZero bool
107 }{
108 {
109 name: "token expires in 1 hour",
110 expiresAt: time.Now().Add(1 * time.Hour),
111 expectZero: false,
112 },
113 {
114 name: "token already expired",
115 expiresAt: time.Now().Add(-1 * time.Hour),
116 expectZero: true,
117 },
118 {
119 name: "no expiration time set",
120 expiresAt: time.Time{},
121 expectZero: true,
122 },
123 }
124
125 for _, tt := range tests {
126 t.Run(tt.name, func(t *testing.T) {
127 session := &Session{
128 AccessTokenExpiresAt: tt.expiresAt,
129 }
130
131 duration := session.TimeUntilAccessTokenExpiry()
132
133 if tt.expectZero {
134 if duration != 0 {
135 t.Errorf("expected zero duration, got %v", duration)
136 }
137 } else {
138 if duration <= 0 {
139 t.Errorf("expected positive duration, got %v", duration)
140 }
141 // Allow some tolerance for test execution time
142 expected := time.Until(tt.expiresAt)
143 if duration < expected-time.Second || duration > expected+time.Second {
144 t.Errorf("expected duration ~%v, got %v", expected, duration)
145 }
146 }
147 })
148 }
149}
150
151func TestUpdateSession(t *testing.T) {
152 store := NewMemorySessionStore()
153 client := NewClientWithOptions(ClientOptions{
154 BaseURL: "http://localhost:8181",
155 SessionStore: store,
156 })
157
158 // Create initial session
159 dpopKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
160 session := &Session{
161 DID: "did:plc:test123",
162 AccessToken: "old_token",
163 RefreshToken: "refresh_token",
164 DPoPKey: dpopKey,
165 PDS: "https://bsky.social",
166 AccessTokenExpiresAt: time.Now().Add(1 * time.Hour),
167 }
168
169 sessionID := "test-session-id"
170 err := client.SessionStore.Set(sessionID, session)
171 if err != nil {
172 t.Fatalf("failed to set initial session: %v", err)
173 }
174
175 // Update with new tokens
176 newSession := &Session{
177 DID: "did:plc:test123",
178 AccessToken: "new_token",
179 RefreshToken: "new_refresh_token",
180 DPoPKey: dpopKey,
181 PDS: "https://bsky.social",
182 AccessTokenExpiresAt: time.Now().Add(2 * time.Hour),
183 }
184
185 err = client.UpdateSession(sessionID, newSession)
186 if err != nil {
187 t.Fatalf("failed to update session: %v", err)
188 }
189
190 // Verify update
191 retrieved, err := client.GetSession(sessionID)
192 if err != nil {
193 t.Fatalf("failed to get updated session: %v", err)
194 }
195
196 if retrieved.AccessToken != "new_token" {
197 t.Errorf("expected access token 'new_token', got '%s'", retrieved.AccessToken)
198 }
199
200 if retrieved.RefreshToken != "new_refresh_token" {
201 t.Errorf("expected refresh token 'new_refresh_token', got '%s'", retrieved.RefreshToken)
202 }
203}
204
205func TestRefreshToken_NoRefreshToken(t *testing.T) {
206 client := NewClient("http://localhost:8181")
207
208 dpopKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
209 session := &Session{
210 DID: "did:plc:test123",
211 AccessToken: "access_token",
212 RefreshToken: "", // No refresh token
213 DPoPKey: dpopKey,
214 PDS: "https://bsky.social",
215 }
216
217 _, err := client.RefreshToken(context.Background(), session)
218 if err == nil {
219 t.Error("expected error when refresh token is missing")
220 }
221
222 if err.Error() != "no refresh token available" {
223 t.Errorf("expected 'no refresh token available' error, got: %v", err)
224 }
225}
226
227func TestRefreshToken_ExpiredRefreshToken(t *testing.T) {
228 client := NewClient("http://localhost:8181")
229
230 dpopKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
231 session := &Session{
232 DID: "did:plc:test123",
233 AccessToken: "access_token",
234 RefreshToken: "refresh_token",
235 RefreshTokenExpiresAt: time.Now().Add(-1 * time.Hour), // Expired
236 DPoPKey: dpopKey,
237 PDS: "https://bsky.social",
238 }
239
240 _, err := client.RefreshToken(context.Background(), session)
241 if err == nil {
242 t.Error("expected error when refresh token is expired")
243 }
244
245 if err.Error() != "refresh token expired" {
246 t.Errorf("expected 'refresh token expired' error, got: %v", err)
247 }
248}