Vibe-guided bskyoauth and custom repo example code in Golang 馃 probably not safe to use in prod
at main 6.4 kB view raw
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}