Skip to content

Commit

Permalink
feat(ConfigUseCase): log AppCheck failures (#466)
Browse files Browse the repository at this point in the history
* feat(ConfigUseCase): log AppCheck failures

* test(ConfigUseCase): Add test that sentry is called

* fix: wire up sentry repo

* fix(ConfigUseCase): use sentry repo for captureException

* Update shared/src/commonMain/kotlin/com/mbta/tid/mbta_app/endToEnd/EndToEndRepositories.kt

Co-authored-by: Melody Horn <[email protected]>

* style(RepositoryDI): alphabetize

* fix(E2ERepos): add sentry imports

* fix(ContentViewModelTests): Mock sentry repo

---------

Co-authored-by: Melody Horn <[email protected]>
  • Loading branch information
KaylaBrady and boringcactus authored Oct 28, 2024
1 parent 67e5841 commit bd5167f
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 9 deletions.
3 changes: 2 additions & 1 deletion iosApp/iosAppTests/Views/ContentViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ final class ContentViewModelTests: XCTestCase {
let expectedResult = ApiResultOk<ConfigResponse>(data: .init(mapboxPublicToken: "FAKE_TOKEN"))
let contentVM = ContentViewModel(configUseCase: ConfigUseCase(
appCheckRepo: MockAppCheckRepository(),
configRepo: MockConfigRepository(response: expectedResult)
configRepo: MockConfigRepository(response: expectedResult),
sentryRepo: MockSentryRepository()
))
await contentVM.loadConfig()
XCTAssertEqual(contentVM.configResponse, expectedResult)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.mbta.tid.mbta_app.repositories.IPredictionsRepository
import com.mbta.tid.mbta_app.repositories.IRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.ISchedulesRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.ISentryRepository
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.IStopRepository
import com.mbta.tid.mbta_app.repositories.ITripPredictionsRepository
Expand Down Expand Up @@ -50,6 +51,7 @@ fun repositoriesModule(repositories: IRepositories): Module {
single<IRailRouteShapeRepository> { repositories.railRouteShapes }
single<ISchedulesRepository> { repositories.schedules }
single<ISearchResultRepository> { repositories.searchResults }
single<ISentryRepository> { repositories.sentry }
single<ISettingsRepository> { repositories.settings }
single<IStopRepository> { repositories.stop }
single<ITripRepository> { repositories.trip }
Expand All @@ -64,7 +66,7 @@ fun repositoriesModule(repositories: IRepositories): Module {
repositories.vehicle?.let { vehicleRepo -> factory<IVehicleRepository> { vehicleRepo } }
repositories.vehicles?.let { vehiclesRepo -> factory<IVehiclesRepository> { vehiclesRepo } }
single<IVisitHistoryRepository> { repositories.visitHistory }
single { ConfigUseCase(get(), get()) }
single { ConfigUseCase(get(), get(), get()) }
single { GetSettingUsecase(get()) }
single { TogglePinnedRouteUsecase(get()) }
single { VisitHistoryUsecase(get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.mbta.tid.mbta_app.repositories.IPredictionsRepository
import com.mbta.tid.mbta_app.repositories.IRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.ISchedulesRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.ISentryRepository
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.IStopRepository
import com.mbta.tid.mbta_app.repositories.ITripPredictionsRepository
Expand All @@ -32,6 +33,7 @@ import com.mbta.tid.mbta_app.repositories.MockAppCheckRepository
import com.mbta.tid.mbta_app.repositories.MockConfigRepository
import com.mbta.tid.mbta_app.repositories.MockErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.MockPredictionsRepository
import com.mbta.tid.mbta_app.repositories.MockSentryRepository
import com.mbta.tid.mbta_app.repositories.MockSettingsRepository
import com.mbta.tid.mbta_app.repositories.MockTripPredictionsRepository
import com.mbta.tid.mbta_app.repositories.MockVehicleRepository
Expand All @@ -41,6 +43,7 @@ import com.mbta.tid.mbta_app.repositories.PinnedRoutesRepository
import com.mbta.tid.mbta_app.repositories.RailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.SchedulesRepository
import com.mbta.tid.mbta_app.repositories.SearchResultRepository
import com.mbta.tid.mbta_app.repositories.SentryRepository
import com.mbta.tid.mbta_app.repositories.SettingsRepository
import com.mbta.tid.mbta_app.repositories.StopRepository
import com.mbta.tid.mbta_app.repositories.TripRepository
Expand All @@ -60,6 +63,7 @@ interface IRepositories {
val railRouteShapes: IRailRouteShapeRepository
val schedules: ISchedulesRepository
val searchResults: ISearchResultRepository
val sentry: ISentryRepository
val settings: ISettingsRepository
val stop: IStopRepository
val trip: ITripRepository
Expand All @@ -81,6 +85,7 @@ class RepositoryDI : IRepositories, KoinComponent {
override val railRouteShapes: IRailRouteShapeRepository by inject()
override val schedules: ISchedulesRepository by inject()
override val searchResults: ISearchResultRepository by inject()
override val sentry: ISentryRepository by inject()
override val settings: ISettingsRepository by inject()
override val stop: IStopRepository by inject()
override val trip: ITripRepository by inject()
Expand All @@ -105,6 +110,7 @@ class RealRepositories : IRepositories {
override val railRouteShapes = RailRouteShapeRepository()
override val schedules = SchedulesRepository()
override val searchResults = SearchResultRepository()
override val sentry = SentryRepository()
override val settings = SettingsRepository()
override val stop = StopRepository()
override val trip = TripRepository()
Expand All @@ -126,6 +132,7 @@ class MockRepositories(
override val railRouteShapes: IRailRouteShapeRepository,
override val schedules: ISchedulesRepository,
override val searchResults: ISearchResultRepository,
override val sentry: ISentryRepository,
override val settings: ISettingsRepository,
override val stop: IStopRepository,
override val trip: ITripRepository,
Expand Down Expand Up @@ -155,6 +162,7 @@ class MockRepositories(
railRouteShapes = IdleRailRouteShapeRepository(),
schedules = schedules,
searchResults = IdleSearchResultRepository(),
sentry = MockSentryRepository(),
settings = MockSettingsRepository(),
stop = stop,
trip = trip,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.mbta.tid.mbta_app.repositories.IPredictionsRepository
import com.mbta.tid.mbta_app.repositories.IRailRouteShapeRepository
import com.mbta.tid.mbta_app.repositories.ISchedulesRepository
import com.mbta.tid.mbta_app.repositories.ISearchResultRepository
import com.mbta.tid.mbta_app.repositories.ISentryRepository
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.IStopRepository
import com.mbta.tid.mbta_app.repositories.ITripPredictionsRepository
Expand All @@ -42,6 +43,7 @@ import com.mbta.tid.mbta_app.repositories.MockAppCheckRepository
import com.mbta.tid.mbta_app.repositories.MockConfigRepository
import com.mbta.tid.mbta_app.repositories.MockErrorBannerStateRepository
import com.mbta.tid.mbta_app.repositories.MockSearchResultRepository
import com.mbta.tid.mbta_app.repositories.MockSentryRepository
import com.mbta.tid.mbta_app.repositories.MockSettingsRepository
import com.mbta.tid.mbta_app.repositories.MockVehiclesRepository
import com.mbta.tid.mbta_app.repositories.MockVisitHistoryRepository
Expand Down Expand Up @@ -171,6 +173,7 @@ fun endToEndModule(): Module {
}
}
single<ISearchResultRepository> { MockSearchResultRepository() }
single<ISentryRepository> { MockSentryRepository() }
single<ISettingsRepository> { MockSettingsRepository() }
single<IStopRepository> {
object : IStopRepository {
Expand Down Expand Up @@ -229,7 +232,7 @@ fun endToEndModule(): Module {
}
single<IVehiclesRepository> { MockVehiclesRepository() }
single<IVisitHistoryRepository> { MockVisitHistoryRepository() }
single { ConfigUseCase(get(), get()) }
single { ConfigUseCase(get(), get(), get()) }
single { GetSettingUsecase(get()) }
single { TogglePinnedRouteUsecase(get()) }
single { VisitHistoryUsecase(get()) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.mbta.tid.mbta_app.repositories

import io.sentry.kotlin.multiplatform.Sentry

interface ISentryRepository {

fun captureMessage(msg: String)

fun captureException(throwable: Throwable)
}

class SentryRepository : ISentryRepository {
override fun captureMessage(msg: String) {
Sentry.captureMessage(msg)
}

override fun captureException(throwable: Throwable) {
Sentry.captureException(throwable)
}
}

class MockSentryRepository : ISentryRepository {
override fun captureMessage(msg: String) {
TODO("Not yet implemented")
}

override fun captureException(throwable: Throwable) {
TODO("Not yet implemented")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,30 @@ import com.mbta.tid.mbta_app.model.response.ApiResult
import com.mbta.tid.mbta_app.model.response.ConfigResponse
import com.mbta.tid.mbta_app.repositories.IAppCheckRepository
import com.mbta.tid.mbta_app.repositories.IConfigRepository
import com.mbta.tid.mbta_app.repositories.ISentryRepository
import org.koin.core.component.KoinComponent

class ConfigUseCase(
private val appCheckRepo: IAppCheckRepository,
private val configRepo: IConfigRepository
private val configRepo: IConfigRepository,
private val sentryRepo: ISentryRepository
) : KoinComponent {

suspend fun getConfig(): ApiResult<ConfigResponse> =
try {
when (val tokenResult = appCheckRepo.getToken()) {
is ApiResult.Error ->
is ApiResult.Error -> {
sentryRepo.captureMessage(
"AppCheck token error ${tokenResult.code} ${tokenResult.message}"
)
ApiResult.Error(message = "app check token failure ${tokenResult.message}")
}
is ApiResult.Ok -> {
configRepo.getConfig(tokenResult.data.token)
}
}
} catch (e: Exception) {
sentryRepo.captureException(e)
ApiResult.Error(message = e.message ?: e.toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ package com.mbta.tid.mbta_app.usecases

import com.mbta.tid.mbta_app.model.response.ApiResult
import com.mbta.tid.mbta_app.model.response.ConfigResponse
import com.mbta.tid.mbta_app.repositories.IAppCheckRepository
import com.mbta.tid.mbta_app.repositories.ISentryRepository
import com.mbta.tid.mbta_app.repositories.MockAppCheckRepository
import com.mbta.tid.mbta_app.repositories.MockConfigRepository
import com.mbta.tid.mbta_app.repositories.MockSentryRepository
import dev.mokkery.MockMode
import dev.mokkery.answering.throws
import dev.mokkery.everySuspend
import dev.mokkery.mock
import dev.mokkery.verify
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.runBlocking
Expand All @@ -15,10 +23,10 @@ class ConfigUsecaseTests {
val appCheckRepo = MockAppCheckRepository()
val configRepo =
MockConfigRepository(ApiResult.Ok(ConfigResponse(mapboxPublicToken = "fake_token")))
val mockSentryRepo = MockSentryRepository()

runBlocking {
val response =
ConfigUseCase(appCheckRepo = appCheckRepo, configRepo = configRepo).getConfig()
val response = ConfigUseCase(appCheckRepo, configRepo, mockSentryRepo).getConfig()

assertEquals(response, ApiResult.Ok(ConfigResponse("fake_token")))
}
Expand All @@ -29,12 +37,33 @@ class ConfigUsecaseTests {
val appCheckRepo = MockAppCheckRepository(ApiResult.Error(message = "oops"))
val configRepo =
MockConfigRepository(ApiResult.Ok(ConfigResponse(mapboxPublicToken = "fake_token")))
val mockSentryRepo = mock<ISentryRepository>(MockMode.autofill)

runBlocking {
val response =
ConfigUseCase(appCheckRepo = appCheckRepo, configRepo = configRepo).getConfig()
val response = ConfigUseCase(appCheckRepo, configRepo, mockSentryRepo).getConfig()

assertEquals(ApiResult.Error(message = "app check token failure oops"), response)

verify { mockSentryRepo.captureMessage("AppCheck token error null oops") }
}
}

@Test
fun testGetConfigAppCheckException() {
val appCheckRepo = mock<IAppCheckRepository>(MockMode.autofill)
val expectedException = IllegalArgumentException("oops")

everySuspend { appCheckRepo.getToken() } throws expectedException
val configRepo =
MockConfigRepository(ApiResult.Ok(ConfigResponse(mapboxPublicToken = "fake_token")))
val mockSentryRepo = mock<ISentryRepository>(MockMode.autofill)

runBlocking {
val response = ConfigUseCase(appCheckRepo, configRepo, mockSentryRepo).getConfig()

assertEquals(ApiResult.Error(message = "oops"), response)

verify { mockSentryRepo.captureException(expectedException) }
}
}
}

0 comments on commit bd5167f

Please sign in to comment.