test(android): prove rotating refresh is serialized

This commit is contained in:
2026-09-08 17:13:07 -03:00
parent ad72f3505c
commit 18238d0c3d
@@ -0,0 +1,62 @@
package com.korexlabs.dhinspeccion.data
import java.util.concurrent.atomic.AtomicInteger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Test
class SessionRefreshGateTest {
@Test
fun simultaneous401sConsumeTheRotatingRefreshTokenOnlyOnce() = runBlocking {
val gate = SessionRefreshGate()
val calls = AtomicInteger(0)
var stored: StoredSession? = StoredSession(
userId = "u-1",
username = "inspector",
displayName = "Inspector",
accessToken = "access-old",
refreshToken = "refresh-old",
)
fun response() = MobileSessionResponse(
user = MobileUser(id = "u-1", username = "inspector"),
accessToken = "access-new",
refreshToken = "refresh-new",
accessExpiresInSeconds = 900,
)
val results = listOf(1, 2).map {
async(Dispatchers.Default) {
gate.refreshIfNeeded(
previousRefreshToken = "refresh-old",
load = { stored },
save = { refreshed ->
StoredSession(
userId = refreshed.user.id,
username = refreshed.user.username,
displayName = refreshed.user.username,
accessToken = refreshed.accessToken,
refreshToken = refreshed.refreshToken,
).also { stored = it }
},
clear = { stored = null },
refresh = {
calls.incrementAndGet()
delay(40)
response()
},
)
}
}.awaitAll()
assertEquals(1, calls.get())
assertEquals(listOf("refresh-new", "refresh-new"), results.map { it.refreshToken })
assertNotNull(stored)
assertEquals("access-new", stored?.accessToken)
}
}