1
+ import app.cash.turbine.test
1
2
import io.github.jan.supabase.SupabaseClientBuilder
2
3
import io.github.jan.supabase.auth.Auth
3
4
import io.github.jan.supabase.auth.MemorySessionManager
4
5
import io.github.jan.supabase.auth.auth
6
+ import io.github.jan.supabase.auth.event.AuthEvent
5
7
import io.github.jan.supabase.auth.minimalSettings
6
8
import io.github.jan.supabase.auth.providers.Github
9
+ import io.github.jan.supabase.auth.status.RefreshFailureCause
10
+ import io.github.jan.supabase.auth.status.SessionSource
7
11
import io.github.jan.supabase.auth.status.SessionStatus
8
12
import io.github.jan.supabase.auth.user.Identity
9
13
import io.github.jan.supabase.auth.user.UserInfo
10
14
import io.github.jan.supabase.auth.user.UserSession
15
+ import io.github.jan.supabase.logging.LogLevel
11
16
import io.github.jan.supabase.testing.createMockedSupabaseClient
12
17
import io.github.jan.supabase.testing.pathAfterVersion
13
18
import io.github.jan.supabase.testing.respondJson
19
+ import io.ktor.client.engine.mock.respondError
20
+ import io.ktor.http.HttpStatusCode
14
21
import io.ktor.http.Url
22
+ import kotlinx.coroutines.launch
15
23
import kotlinx.coroutines.test.runTest
16
24
import kotlinx.serialization.json.buildJsonObject
17
25
import kotlin.test.Test
18
26
import kotlin.test.assertEquals
19
27
import kotlin.test.assertFailsWith
20
28
import kotlin.test.assertIs
21
29
import kotlin.test.assertNull
30
+ import kotlin.time.Duration.Companion.seconds
22
31
23
32
class AuthTest {
24
33
@@ -105,6 +114,7 @@ class AuthTest {
105
114
val session = userSession(expiresIn = 0 )
106
115
client.auth.importSession(session)
107
116
assertIs<SessionStatus .Authenticated >(client.auth.sessionStatus.value)
117
+ assertIs<SessionSource .Refresh >((client.auth.sessionStatus.value as SessionStatus .Authenticated ).source)
108
118
assertEquals(newSession.expiresIn, client.auth.currentSessionOrNull()?.expiresIn)
109
119
}
110
120
}
@@ -131,10 +141,96 @@ class AuthTest {
131
141
assertIs<SessionStatus .Authenticated >(client.auth.sessionStatus.value)
132
142
assertEquals(session.expiresIn, client.auth.currentSessionOrNull()?.expiresIn) // The session shouldn't be refreshed automatically as alwaysAutoRefresh is false
133
143
client.auth.startAutoRefreshForCurrentSession()
144
+ assertIs<SessionSource .Refresh >((client.auth.sessionStatus.value as SessionStatus .Authenticated ).source)
134
145
assertEquals(newSession.expiresIn, client.auth.currentSessionOrNull()?.expiresIn)
135
146
}
136
147
}
137
148
149
+ @Test
150
+ fun testAutoRefreshFailureNetworkValidSession () {
151
+ runTest {
152
+ val newSession = userSession()
153
+ val client = createMockedSupabaseClient(configuration = {
154
+ install(Auth ) {
155
+ minimalSettings(
156
+ alwaysAutoRefresh = true
157
+ )
158
+ }
159
+ defaultLogLevel = LogLevel .DEBUG
160
+ }) {
161
+ throw IllegalStateException (" Some random error" ) // everything except RestException are handled as network errors
162
+ }
163
+ client.auth.awaitInitialization()
164
+ assertIs<SessionStatus .NotAuthenticated >(client.auth.sessionStatus.value)
165
+ val session = userSession(expiresIn = 1 )
166
+ client.auth.importSession(session)
167
+ assertIs<SessionStatus .Authenticated >(client.auth.sessionStatus.value) // since the session is still valid, the status should be authenticated
168
+ client.auth.events.test(timeout = 2 .seconds) { // event should be emitted regardless of the session status
169
+ val event = awaitItem()
170
+ assertIs<AuthEvent .RefreshFailure >(event)
171
+ assertIs<RefreshFailureCause .NetworkError >(event.cause)
172
+ }
173
+ }
174
+ }
175
+
176
+ @Test
177
+ fun testAutoRefreshFailureServerErrorValidSession () {
178
+ runTest {
179
+ val newSession = userSession()
180
+ val client = createMockedSupabaseClient(configuration = {
181
+ install(Auth ) {
182
+ minimalSettings(
183
+ alwaysAutoRefresh = true
184
+ )
185
+ }
186
+ defaultLogLevel = LogLevel .DEBUG
187
+ }) {
188
+ respondError(HttpStatusCode .InternalServerError , " {}" )
189
+ }
190
+ assertIs<SessionStatus .NotAuthenticated >(client.auth.sessionStatus.value)
191
+ val session = userSession(expiresIn = 1 )
192
+ client.auth.importSession(session)
193
+ assertIs<SessionStatus .Authenticated >(client.auth.sessionStatus.value) // since the session is still valid, the status should be authenticated
194
+ client.auth.events.test(timeout = 2 .seconds) { // event should be emitted regardless of the session status
195
+ val event = awaitItem()
196
+ assertIs<AuthEvent .RefreshFailure >(event)
197
+ assertIs<RefreshFailureCause .InternalServerError >(event.cause)
198
+ }
199
+ }
200
+ }
201
+
202
+ @Test
203
+ fun testAutoRefreshFailureInvalidSession () {
204
+ runTest {
205
+ var first = true
206
+ val newSession = userSession()
207
+ val client = createMockedSupabaseClient(configuration = {
208
+ install(Auth ) {
209
+ minimalSettings(
210
+ alwaysAutoRefresh = false
211
+ )
212
+ }
213
+ defaultLogLevel = LogLevel .DEBUG
214
+ }) {
215
+ if (first) {
216
+ first = false
217
+ respondError(HttpStatusCode .InternalServerError , " {}" )
218
+ } else respondJson(newSession)
219
+ }
220
+ client.auth.awaitInitialization()
221
+ assertIs<SessionStatus .NotAuthenticated >(client.auth.sessionStatus.value)
222
+ val session = userSession(expiresIn = 0 )
223
+ launch {
224
+ client.auth.events.test(timeout = 1 .seconds) { // event should be emitted regardless of the session status
225
+ val event = awaitItem()
226
+ assertIs<SessionStatus .RefreshFailure >(client.auth.sessionStatus.value) // session expired and should be in refresh failure state
227
+ assertIs<AuthEvent .RefreshFailure >(event)
228
+ }
229
+ }
230
+ client.auth.importSession(session, autoRefresh = true )
231
+ }
232
+ }
233
+
138
234
@Test
139
235
fun testGetOAuthUrl () {
140
236
runTest {
0 commit comments