fix: make card comment refresh failures non-fatal
This commit is contained in:
@@ -19,6 +19,7 @@ class CardDetailRepository(
|
||||
companion object {
|
||||
const val MISSING_SESSION_MESSAGE = "Missing session. Please sign in again."
|
||||
private const val SESSION_EXPIRED_MESSAGE = "Session expired. Please sign in again."
|
||||
private val AUTH_STATUS_CODE_REGEX = Regex("\\b(401|403)\\b")
|
||||
}
|
||||
|
||||
sealed interface Result<out T> {
|
||||
@@ -206,7 +207,11 @@ class CardDetailRepository(
|
||||
is BoardsApiResult.Failure -> return mapFailure(addCommentResult.message)
|
||||
}
|
||||
|
||||
return listActivities(normalizedCardId)
|
||||
return when (val refreshResult = listActivities(normalizedCardId)) {
|
||||
is Result.Success -> refreshResult
|
||||
is Result.Failure.SessionExpired -> refreshResult
|
||||
is Result.Failure.Generic -> Result.Success(emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun session(): Result<SessionSnapshot> {
|
||||
@@ -231,11 +236,18 @@ class CardDetailRepository(
|
||||
|
||||
private fun isAuthFailure(message: String): Boolean {
|
||||
val lower = message.lowercase()
|
||||
return lower.contains("authentication failed") ||
|
||||
lower.contains("server error: 401") ||
|
||||
lower.contains("server error: 403") ||
|
||||
lower.contains(" 401") ||
|
||||
lower.contains(" 403")
|
||||
val hasAuthToken =
|
||||
lower.contains("authentication failed") ||
|
||||
lower.contains("unauthorized") ||
|
||||
lower.contains("forbidden")
|
||||
val hasAuthStatusCode = AUTH_STATUS_CODE_REGEX.containsMatchIn(lower) &&
|
||||
(
|
||||
lower.contains("server error") ||
|
||||
lower.contains("http") ||
|
||||
lower.contains("status") ||
|
||||
lower.contains("code")
|
||||
)
|
||||
return hasAuthToken || hasAuthStatusCode
|
||||
}
|
||||
|
||||
private data class SessionSnapshot(
|
||||
|
||||
@@ -120,6 +120,36 @@ class CardDetailRepositoryTest {
|
||||
assertEquals("hello", apiClient.lastComment)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addComment_refreshGenericFailure_returnsSuccessWithEmptyActivities() = runTest {
|
||||
val apiClient = FakeCardDetailApiClient().apply {
|
||||
addCommentResult = BoardsApiResult.Success(Unit)
|
||||
listActivitiesResult = BoardsApiResult.Failure("Server temporarily unavailable")
|
||||
}
|
||||
val repository = createRepository(apiClient = apiClient)
|
||||
|
||||
val result = repository.addComment(cardId = "card-1", comment = "hello")
|
||||
|
||||
assertTrue(result is CardDetailRepository.Result.Success)
|
||||
val activities = (result as CardDetailRepository.Result.Success<List<CardActivity>>).value
|
||||
assertTrue(activities.isEmpty())
|
||||
assertEquals(1, apiClient.addCommentCalls)
|
||||
assertEquals(1, apiClient.listActivitiesCalls)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addComment_refreshAuthFailure_mapsToSessionExpired() = runTest {
|
||||
val apiClient = FakeCardDetailApiClient().apply {
|
||||
addCommentResult = BoardsApiResult.Success(Unit)
|
||||
listActivitiesResult = BoardsApiResult.Failure("Server error: 403")
|
||||
}
|
||||
val repository = createRepository(apiClient = apiClient)
|
||||
|
||||
val result = repository.addComment(cardId = "card-1", comment = "hello")
|
||||
|
||||
assertTrue(result is CardDetailRepository.Result.Failure.SessionExpired)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addComment_authFailureMapsToSessionExpired() = runTest {
|
||||
val apiClient = FakeCardDetailApiClient().apply {
|
||||
@@ -132,6 +162,31 @@ class CardDetailRepositoryTest {
|
||||
assertTrue(result is CardDetailRepository.Result.Failure.SessionExpired)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun listActivities_nonAuthNumericMessage_remainsGenericFailure() = runTest {
|
||||
val apiClient = FakeCardDetailApiClient().apply {
|
||||
listActivitiesResult = BoardsApiResult.Failure("Server error: 1401")
|
||||
}
|
||||
val repository = createRepository(apiClient = apiClient)
|
||||
|
||||
val result = repository.listActivities("card-1")
|
||||
|
||||
assertTrue(result is CardDetailRepository.Result.Failure.Generic)
|
||||
assertEquals("Server error: 1401", (result as CardDetailRepository.Result.Failure.Generic).message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun listActivities_forbiddenMessage_mapsToSessionExpired() = runTest {
|
||||
val apiClient = FakeCardDetailApiClient().apply {
|
||||
listActivitiesResult = BoardsApiResult.Failure("Forbidden")
|
||||
}
|
||||
val repository = createRepository(apiClient = apiClient)
|
||||
|
||||
val result = repository.listActivities("card-1")
|
||||
|
||||
assertTrue(result is CardDetailRepository.Result.Failure.SessionExpired)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun updateDueDate_dateOnlyInputNormalizesToUtcMidnightPayloadContract() = runTest {
|
||||
val apiClient = FakeCardDetailApiClient()
|
||||
|
||||
Reference in New Issue
Block a user