Ensure that disabling (resp. enabling) notification unregisters (resp. registers) the pusher
This commit is contained in:
@@ -36,7 +36,7 @@ import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.pushproviders.api.RegistrationFailure
|
||||
import io.element.android.libraries.push.api.PusherRegistrationFailure
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.combine
|
||||
@@ -71,7 +71,17 @@ class LoggedInPresenter(
|
||||
when (sessionVerifiedStatus) {
|
||||
SessionVerifiedStatus.Unknown -> Unit
|
||||
SessionVerifiedStatus.Verified -> {
|
||||
ensurePusherIsRegistered(pusherRegistrationState)
|
||||
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
|
||||
pushService.ensurePusherIsRegistered(matrixClient).fold(
|
||||
onSuccess = {
|
||||
Timber.tag(pusherTag.value).d("Pusher registered")
|
||||
pusherRegistrationState.value = AsyncData.Success(Unit)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.tag(pusherTag.value).e(it, "Failed to register pusher")
|
||||
pusherRegistrationState.value = AsyncData.Failure(it)
|
||||
},
|
||||
)
|
||||
}
|
||||
SessionVerifiedStatus.NotVerified -> {
|
||||
pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.AccountNotVerified())
|
||||
@@ -133,59 +143,6 @@ class LoggedInPresenter(
|
||||
currentSlidingSyncVersion == SlidingSyncVersion.Proxy
|
||||
}
|
||||
|
||||
private suspend fun ensurePusherIsRegistered(pusherRegistrationState: MutableState<AsyncData<Unit>>) {
|
||||
Timber.tag(pusherTag.value).d("Ensure pusher is registered")
|
||||
val currentPushProvider = pushService.getCurrentPushProvider(matrixClient.sessionId)
|
||||
val result = if (currentPushProvider == null) {
|
||||
Timber.tag(pusherTag.value).d("Register with the first available push provider with at least one distributor")
|
||||
val pushProvider = pushService.getAvailablePushProviders()
|
||||
.firstOrNull { it.getDistributors().isNotEmpty() }
|
||||
// Else fallback to the first available push provider (the list should never be empty)
|
||||
?: pushService.getAvailablePushProviders().firstOrNull()
|
||||
?: return Unit
|
||||
.also { Timber.tag(pusherTag.value).w("No push providers available") }
|
||||
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoProvidersAvailable()) }
|
||||
val distributor = pushProvider.getDistributors().firstOrNull()
|
||||
?: return Unit
|
||||
.also { Timber.tag(pusherTag.value).w("No distributors available") }
|
||||
.also {
|
||||
// In this case, consider the push provider is chosen.
|
||||
pushService.selectPushProvider(matrixClient.sessionId, pushProvider)
|
||||
}
|
||||
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable()) }
|
||||
pushService.registerWith(matrixClient, pushProvider, distributor)
|
||||
} else {
|
||||
val currentPushDistributor = currentPushProvider.getCurrentDistributor(matrixClient.sessionId)
|
||||
if (currentPushDistributor == null) {
|
||||
Timber.tag(pusherTag.value).d("Register with the first available distributor")
|
||||
val distributor = currentPushProvider.getDistributors().firstOrNull()
|
||||
?: return Unit
|
||||
.also { Timber.tag(pusherTag.value).w("No distributors available") }
|
||||
.also { pusherRegistrationState.value = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable()) }
|
||||
pushService.registerWith(matrixClient, currentPushProvider, distributor)
|
||||
} else {
|
||||
Timber.tag(pusherTag.value).d("Re-register with the current distributor")
|
||||
pushService.registerWith(matrixClient, currentPushProvider, currentPushDistributor)
|
||||
}
|
||||
}
|
||||
result.fold(
|
||||
onSuccess = {
|
||||
Timber.tag(pusherTag.value).d("Pusher registered")
|
||||
pusherRegistrationState.value = AsyncData.Success(Unit)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.tag(pusherTag.value).e(it, "Failed to register pusher")
|
||||
if (it is RegistrationFailure) {
|
||||
pusherRegistrationState.value = AsyncData.Failure(
|
||||
PusherRegistrationFailure.RegistrationFailure(it.clientException, it.isRegisteringAgain)
|
||||
)
|
||||
} else {
|
||||
pusherRegistrationState.value = AsyncData.Failure(it)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun reportCryptoStatusToAnalytics(verificationState: SessionVerifiedStatus, recoveryState: RecoveryState) {
|
||||
// Update first the user property, to store the current status for that posthog user
|
||||
val userVerificationState = verificationState.toAnalyticsUserPropertyValue()
|
||||
|
||||
@@ -10,6 +10,7 @@ package io.element.android.appnav.loggedin
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.push.api.PusherRegistrationFailure
|
||||
|
||||
open class LoggedInStateProvider : PreviewParameterProvider<LoggedInState> {
|
||||
override val values: Sequence<LoggedInState>
|
||||
|
||||
@@ -25,6 +25,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.matrix.api.exception.isNetworkError
|
||||
import io.element.android.libraries.push.api.PusherRegistrationFailure
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -34,6 +34,7 @@ import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.push.api.PusherRegistrationFailure
|
||||
import io.element.android.libraries.push.test.FakePushService
|
||||
import io.element.android.libraries.pushproviders.api.Distributor
|
||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||
@@ -42,7 +43,6 @@ import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.lambda.any
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
@@ -115,7 +115,9 @@ class LoggedInPresenterTest {
|
||||
encryptionService = encryptionService,
|
||||
),
|
||||
syncService = FakeSyncService(initialSyncState = SyncState.Running),
|
||||
pushService = FakePushService(),
|
||||
pushService = FakePushService(
|
||||
ensurePusherIsRegisteredResult = { Result.success(Unit) },
|
||||
),
|
||||
sessionVerificationService = verificationService,
|
||||
analyticsService = analyticsService,
|
||||
encryptionService = encryptionService,
|
||||
@@ -139,10 +141,10 @@ class LoggedInPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - ensure default pusher is not registered if session is not verified`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
val lambda = lambdaRecorder<Result<Unit>> {
|
||||
Result.success(Unit)
|
||||
}
|
||||
val pushService = createFakePushService(registerWithLambda = lambda)
|
||||
val pushService = createFakePushService(ensurePusherIsRegisteredResult = lambda)
|
||||
val verificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.NotVerified
|
||||
)
|
||||
@@ -153,21 +155,18 @@ class LoggedInPresenterTest {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
lambda.assertions().isNeverCalled()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - ensure default pusher is registered with default provider`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val lambda = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
registerWithLambda = lambda,
|
||||
ensurePusherIsRegisteredResult = lambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
@@ -180,27 +179,17 @@ class LoggedInPresenterTest {
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// PushProvider with highest priority (lower index)
|
||||
value(pushService.getAvailablePushProviders()[0]),
|
||||
// First distributor
|
||||
value(pushService.getAvailablePushProviders()[0].getDistributors()[0]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - ensure default pusher is registered with default provider - fail to register`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.failure(AN_EXCEPTION)
|
||||
}
|
||||
val lambda = lambdaRecorder<Result<Unit>> { Result.failure(AN_EXCEPTION) }
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
registerWithLambda = lambda,
|
||||
ensurePusherIsRegisteredResult = lambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
@@ -213,158 +202,36 @@ class LoggedInPresenterTest {
|
||||
assertThat(finalState.pusherRegistrationState.isFailure()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// PushProvider with highest priority (lower index)
|
||||
value(pushService.getAvailablePushProviders()[0]),
|
||||
// First distributor
|
||||
value(pushService.getAvailablePushProviders()[0].getDistributors()[0]),
|
||||
)
|
||||
// Reset the error and do not show again
|
||||
finalState.eventSink(LoggedInEvents.CloseErrorDialog(doNotShowAgain = false))
|
||||
val lastState = awaitItem()
|
||||
assertThat(lastState.pusherRegistrationState.isUninitialized()).isTrue()
|
||||
assertThat(lastState.ignoreRegistrationError).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - ensure current provider is registered with current distributor`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val distributor = Distributor("aDistributorValue1", "aDistributorName1")
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = listOf(
|
||||
Distributor("aDistributorValue0", "aDistributorName0"),
|
||||
distributor,
|
||||
),
|
||||
currentDistributor = { distributor },
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
pushProvider1 = pushProvider,
|
||||
currentPushProvider = { pushProvider },
|
||||
registerWithLambda = lambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
matrixClient = FakeMatrixClient(
|
||||
accountManagementUrlResult = { Result.success(null) },
|
||||
),
|
||||
).test {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// Current push provider
|
||||
value(pushProvider),
|
||||
// Current distributor
|
||||
value(distributor),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - if current push provider does not have current distributor, the first one is used`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = listOf(
|
||||
Distributor("aDistributorValue0", "aDistributorName0"),
|
||||
Distributor("aDistributorValue1", "aDistributorName1"),
|
||||
),
|
||||
currentDistributor = { null },
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
pushProvider0 = pushProvider,
|
||||
currentPushProvider = { pushProvider },
|
||||
registerWithLambda = lambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
matrixClient = FakeMatrixClient(
|
||||
accountManagementUrlResult = { Result.success(null) },
|
||||
),
|
||||
).test {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// PushProvider with highest priority (lower index)
|
||||
value(pushService.getAvailablePushProviders()[0]),
|
||||
// First distributor
|
||||
value(pushService.getAvailablePushProviders()[0].getDistributors()[0]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - if current push provider does not have distributors, nothing happen`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = emptyList(),
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
pushProvider0 = pushProvider,
|
||||
currentPushProvider = { pushProvider },
|
||||
registerWithLambda = lambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
).test {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - case no push provider available provider`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(SessionVerifiedStatus.Verified)
|
||||
fun `present - ensure default pusher is registered with default provider - fail to register - do not show again`() = runTest {
|
||||
val lambda = lambdaRecorder<Result<Unit>> { Result.failure(AN_EXCEPTION) }
|
||||
val setIgnoreRegistrationErrorLambda = lambdaRecorder<SessionId, Boolean, Unit> { _, _ -> }
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
pushProvider0 = null,
|
||||
pushProvider1 = null,
|
||||
registerWithLambda = lambda,
|
||||
ensurePusherIsRegisteredResult = lambda,
|
||||
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
matrixClient = FakeMatrixClient(
|
||||
accountManagementUrlResult = { Result.success(null) },
|
||||
),
|
||||
).test {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java)
|
||||
assertThat(finalState.pusherRegistrationState.isFailure()).isTrue()
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
.isCalledOnce()
|
||||
// Reset the error and do not show again
|
||||
finalState.eventSink(LoggedInEvents.CloseErrorDialog(doNotShowAgain = true))
|
||||
skipItems(1)
|
||||
@@ -382,95 +249,6 @@ class LoggedInPresenterTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - case one push provider but no distributor available`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val selectPushProviderLambda = lambdaRecorder<SessionId, PushProvider, Unit> { _, _ -> }
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider",
|
||||
distributors = emptyList(),
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
pushProvider0 = pushProvider,
|
||||
pushProvider1 = null,
|
||||
registerWithLambda = lambda,
|
||||
selectPushProviderLambda = selectPushProviderLambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
).test {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.errorOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
selectPushProviderLambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// SessionId
|
||||
value(A_SESSION_ID),
|
||||
// PushProvider
|
||||
value(pushProvider),
|
||||
)
|
||||
// Reset the error
|
||||
finalState.eventSink(LoggedInEvents.CloseErrorDialog(doNotShowAgain = false))
|
||||
val lastState = awaitItem()
|
||||
assertThat(lastState.pusherRegistrationState.isUninitialized()).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - case two push providers but first one does not have distributor - second one will be used`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, PushProvider, Distributor, Result<Unit>> { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider0 = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = emptyList(),
|
||||
)
|
||||
val distributor = Distributor("aDistributorValue1", "aDistributorName1")
|
||||
val pushProvider1 = FakePushProvider(
|
||||
index = 1,
|
||||
name = "aFakePushProvider1",
|
||||
distributors = listOf(distributor),
|
||||
)
|
||||
val pushService = createFakePushService(
|
||||
pushProvider0 = pushProvider0,
|
||||
pushProvider1 = pushProvider1,
|
||||
registerWithLambda = lambda,
|
||||
)
|
||||
createLoggedInPresenter(
|
||||
pushService = pushService,
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
matrixClient = FakeMatrixClient(
|
||||
accountManagementUrlResult = { Result.success(null) },
|
||||
),
|
||||
).test {
|
||||
val finalState = awaitFirstItem()
|
||||
assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
|
||||
lambda.assertions().isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// PushProvider with the distributor
|
||||
value(pushProvider1),
|
||||
// First distributor of second push provider
|
||||
value(distributor),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFakePushService(
|
||||
pushProvider0: PushProvider? = FakePushProvider(
|
||||
index = 0,
|
||||
@@ -484,7 +262,7 @@ class LoggedInPresenterTest {
|
||||
distributors = listOf(Distributor("aDistributorValue1", "aDistributorName1")),
|
||||
currentDistributor = { null },
|
||||
),
|
||||
registerWithLambda: (MatrixClient, PushProvider, Distributor) -> Result<Unit> = { _, _, _ ->
|
||||
ensurePusherIsRegisteredResult: () -> Result<Unit> = {
|
||||
Result.success(Unit)
|
||||
},
|
||||
selectPushProviderLambda: (SessionId, PushProvider) -> Unit = { _, _ -> lambdaError() },
|
||||
@@ -493,7 +271,7 @@ class LoggedInPresenterTest {
|
||||
): PushService {
|
||||
return FakePushService(
|
||||
availablePushProviders = listOfNotNull(pushProvider0, pushProvider1),
|
||||
registerWithLambda = registerWithLambda,
|
||||
ensurePusherIsRegisteredResult = ensurePusherIsRegisteredResult,
|
||||
currentPushProvider = currentPushProvider,
|
||||
selectPushProviderLambda = selectPushProviderLambda,
|
||||
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
|
||||
|
||||
@@ -25,6 +25,7 @@ import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingStateNoSuccess
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
@@ -51,6 +52,8 @@ class NotificationSettingsPresenter(
|
||||
private val pushService: PushService,
|
||||
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider,
|
||||
private val fullScreenIntentPermissionsPresenter: Presenter<FullScreenIntentPermissionsState>,
|
||||
@SessionCoroutineScope
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
) : Presenter<NotificationSettingsState> {
|
||||
@Composable
|
||||
override fun present(): NotificationSettingsState {
|
||||
@@ -141,7 +144,7 @@ class NotificationSettingsPresenter(
|
||||
is NotificationSettingsEvents.SetInviteForMeNotificationsEnabled -> {
|
||||
localCoroutineScope.setInviteForMeNotificationsEnabled(event.enabled, changeNotificationSettingAction)
|
||||
}
|
||||
is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled)
|
||||
is NotificationSettingsEvents.SetNotificationsEnabled -> sessionCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled)
|
||||
NotificationSettingsEvents.ClearConfigurationMismatchError -> {
|
||||
matrixSettings.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false)
|
||||
}
|
||||
@@ -262,5 +265,10 @@ class NotificationSettingsPresenter(
|
||||
|
||||
private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch {
|
||||
userPushStore.setNotificationEnabledForDevice(enabled)
|
||||
if (enabled) {
|
||||
pushService.ensurePusherIsRegistered(matrixClient)
|
||||
} else {
|
||||
pushService.getCurrentPushProvider(matrixClient.sessionId)?.unregister(matrixClient)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
package io.element.android.features.preferences.impl.notifications
|
||||
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
||||
@@ -28,6 +25,9 @@ import io.element.android.libraries.pushproviders.test.FakePushProvider
|
||||
import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.test
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
@@ -36,9 +36,7 @@ class NotificationSettingsPresenterTest {
|
||||
@Test
|
||||
fun `present - ensures initial state is correct`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
assertThat(initialState.appSettings.appNotificationsEnabled).isFalse()
|
||||
assertThat(initialState.appSettings.systemNotificationsEnabled).isTrue()
|
||||
@@ -62,9 +60,7 @@ class NotificationSettingsPresenterTest {
|
||||
fun `present - default group notification mode changed`() = runTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
val presenter = createNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
@@ -80,9 +76,7 @@ class NotificationSettingsPresenterTest {
|
||||
fun `present - notification settings mismatched`() = runTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
val presenter = createNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||
isEncrypted = true,
|
||||
isOneToOne = false,
|
||||
@@ -110,9 +104,7 @@ class NotificationSettingsPresenterTest {
|
||||
initialOneToOneDefaultMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
)
|
||||
val presenter = createNotificationSettingsPresenter(notificationSettingsService)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(NotificationSettingsEvents.FixConfigurationMismatch)
|
||||
val fixedState = consumeItemsUntilPredicate(timeout = 2000.milliseconds) {
|
||||
@@ -125,10 +117,19 @@ class NotificationSettingsPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - set notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val unregisterWithResult = lambdaRecorder<MatrixClient, Result<Unit>> { Result.success(Unit) }
|
||||
val ensurePusherIsRegisteredResult = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||
val presenter = createNotificationSettingsPresenter(
|
||||
pushService = FakePushService(
|
||||
currentPushProvider = {
|
||||
FakePushProvider(
|
||||
unregisterWithResult = unregisterWithResult,
|
||||
)
|
||||
},
|
||||
ensurePusherIsRegisteredResult = ensurePusherIsRegisteredResult,
|
||||
)
|
||||
)
|
||||
presenter.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
@@ -138,16 +139,21 @@ class NotificationSettingsPresenterTest {
|
||||
!it.appSettings.appNotificationsEnabled
|
||||
}.last()
|
||||
assertThat(updatedState.appSettings.appNotificationsEnabled).isFalse()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
unregisterWithResult.assertions().isCalledOnce()
|
||||
// Enable notification again
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(true))
|
||||
val updatedState2 = consumeItemsUntilPredicate {
|
||||
it.appSettings.appNotificationsEnabled
|
||||
}.last()
|
||||
assertThat(updatedState2.appSettings.appNotificationsEnabled).isTrue()
|
||||
ensurePusherIsRegisteredResult.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - set call notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.callNotificationsEnabled == false
|
||||
}.last()
|
||||
@@ -166,9 +172,7 @@ class NotificationSettingsPresenterTest {
|
||||
@Test
|
||||
fun `present - set invite for me notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == false
|
||||
}.last()
|
||||
@@ -187,9 +191,7 @@ class NotificationSettingsPresenterTest {
|
||||
@Test
|
||||
fun `present - set atRoom notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == false
|
||||
}.last()
|
||||
@@ -210,9 +212,7 @@ class NotificationSettingsPresenterTest {
|
||||
val notificationSettingsService = FakeNotificationSettingsService()
|
||||
val presenter = createNotificationSettingsPresenter(notificationSettingsService)
|
||||
notificationSettingsService.givenSetAtRoomError(AN_EXCEPTION)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == false
|
||||
}.last()
|
||||
@@ -237,9 +237,7 @@ class NotificationSettingsPresenterTest {
|
||||
val presenter = createNotificationSettingsPresenter(
|
||||
pushService = createFakePushService(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncData.Success(Distributor(value = "aDistributorValue0", name = "aDistributorName0")))
|
||||
assertThat(initialState.availablePushDistributors).containsExactly(
|
||||
@@ -271,9 +269,7 @@ class NotificationSettingsPresenterTest {
|
||||
val presenter = createNotificationSettingsPresenter(
|
||||
pushService = createFakePushService(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncData.Success(Distributor(value = "aDistributorValue0", name = "aDistributorName0")))
|
||||
assertThat(initialState.availablePushDistributors).containsExactly(
|
||||
@@ -298,9 +294,7 @@ class NotificationSettingsPresenterTest {
|
||||
pushService = createFakePushService(),
|
||||
fullScreenIntentPermissionsStateLambda = fullScreenIntentPermissionsStateLambda,
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
presenter.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
assertThat(initialState.fullScreenIntentPermissionsState.permissionGranted).isFalse()
|
||||
|
||||
@@ -324,11 +318,7 @@ class NotificationSettingsPresenterTest {
|
||||
},
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
initialState.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
||||
presenter.test {
|
||||
val withDialog = awaitItem()
|
||||
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
||||
withDialog.eventSink(NotificationSettingsEvents.SetPushProvider(1))
|
||||
@@ -361,7 +351,7 @@ class NotificationSettingsPresenterTest {
|
||||
)
|
||||
}
|
||||
|
||||
private fun createNotificationSettingsPresenter(
|
||||
private fun TestScope.createNotificationSettingsPresenter(
|
||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
pushService: PushService = FakePushService(),
|
||||
fullScreenIntentPermissionsStateLambda: () -> FullScreenIntentPermissionsState = { aFullScreenIntentPermissionsState() },
|
||||
@@ -374,6 +364,7 @@ class NotificationSettingsPresenterTest {
|
||||
pushService = pushService,
|
||||
systemNotificationsEnabledProvider = FakeSystemNotificationsEnabledProvider(),
|
||||
fullScreenIntentPermissionsPresenter = { fullScreenIntentPermissionsStateLambda() },
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,15 @@ interface PushService {
|
||||
distributor: Distributor,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Ensure that the pusher with the current push provider and distributor is registered.
|
||||
* If there is no current config, the default push provider with the default distributor will be used.
|
||||
* Error can be [PusherRegistrationFailure].
|
||||
*/
|
||||
suspend fun ensurePusherIsRegistered(
|
||||
matrixClient: MatrixClient,
|
||||
): Result<Unit>
|
||||
|
||||
/**
|
||||
* Store the given push provider as the current one, but do not register.
|
||||
* To be used when there is no distributor available.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.appnav.loggedin
|
||||
package io.element.android.libraries.push.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.exception.ClientException
|
||||
|
||||
@@ -15,8 +15,10 @@ import dev.zacsweers.metro.binding
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||
import io.element.android.libraries.push.api.GetCurrentPushProvider
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.push.api.PusherRegistrationFailure
|
||||
import io.element.android.libraries.push.api.history.PushHistoryItem
|
||||
import io.element.android.libraries.push.impl.push.MutableBatteryOptimizationStore
|
||||
import io.element.android.libraries.push.impl.store.PushDataStore
|
||||
@@ -24,11 +26,13 @@ import io.element.android.libraries.push.impl.test.TestPush
|
||||
import io.element.android.libraries.push.impl.unregistration.ServiceUnregisteredHandler
|
||||
import io.element.android.libraries.pushproviders.api.Distributor
|
||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||
import io.element.android.libraries.pushproviders.api.RegistrationFailure
|
||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecretStore
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import timber.log.Timber
|
||||
|
||||
@ContributesBinding(AppScope::class, binding = binding<PushService>())
|
||||
@@ -84,6 +88,59 @@ class DefaultPushService(
|
||||
return pushProvider.registerWith(matrixClient, distributor)
|
||||
}
|
||||
|
||||
override suspend fun ensurePusherIsRegistered(matrixClient: MatrixClient): Result<Unit> {
|
||||
val verificationStatus = matrixClient.sessionVerificationService.sessionVerifiedStatus.first()
|
||||
if (verificationStatus != SessionVerifiedStatus.Verified) {
|
||||
return Result.failure<Unit>(PusherRegistrationFailure.AccountNotVerified())
|
||||
.also { Timber.w("Account is not verified") }
|
||||
}
|
||||
Timber.d("Ensure pusher is registered")
|
||||
val currentPushProvider = getCurrentPushProvider(matrixClient.sessionId)
|
||||
val result = if (currentPushProvider == null) {
|
||||
Timber.d("Register with the first available push provider with at least one distributor")
|
||||
val pushProvider = getAvailablePushProviders()
|
||||
.firstOrNull { it.getDistributors().isNotEmpty() }
|
||||
// Else fallback to the first available push provider (the list should never be empty)
|
||||
?: getAvailablePushProviders().firstOrNull()
|
||||
?: return Result.failure<Unit>(PusherRegistrationFailure.NoProvidersAvailable())
|
||||
.also { Timber.w("No push providers available") }
|
||||
val distributor = pushProvider.getDistributors().firstOrNull()
|
||||
?: return Result.failure<Unit>(PusherRegistrationFailure.NoDistributorsAvailable())
|
||||
.also { Timber.w("No distributors available") }
|
||||
.also {
|
||||
// In this case, consider the push provider is chosen.
|
||||
selectPushProvider(matrixClient.sessionId, pushProvider)
|
||||
}
|
||||
registerWith(matrixClient, pushProvider, distributor)
|
||||
} else {
|
||||
val currentPushDistributor = currentPushProvider.getCurrentDistributor(matrixClient.sessionId)
|
||||
if (currentPushDistributor == null) {
|
||||
Timber.d("Register with the first available distributor")
|
||||
val distributor = currentPushProvider.getDistributors().firstOrNull()
|
||||
?: return Result.failure<Unit>(PusherRegistrationFailure.NoDistributorsAvailable())
|
||||
.also { Timber.w("No distributors available") }
|
||||
registerWith(matrixClient, currentPushProvider, distributor)
|
||||
} else {
|
||||
Timber.d("Re-register with the current distributor")
|
||||
registerWith(matrixClient, currentPushProvider, currentPushDistributor)
|
||||
}
|
||||
}
|
||||
return result.fold(
|
||||
onSuccess = {
|
||||
Timber.d("Pusher registered")
|
||||
Result.success(Unit)
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Failed to register pusher")
|
||||
if (it is RegistrationFailure) {
|
||||
Result.failure(PusherRegistrationFailure.RegistrationFailure(it.clientException, it.isRegisteringAgain))
|
||||
} else {
|
||||
Result.failure(it)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun selectPushProvider(
|
||||
sessionId: SessionId,
|
||||
pushProvider: PushProvider,
|
||||
|
||||
@@ -12,12 +12,15 @@ import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||
import io.element.android.libraries.push.api.GetCurrentPushProvider
|
||||
import io.element.android.libraries.push.api.PusherRegistrationFailure
|
||||
import io.element.android.libraries.push.api.history.PushHistoryItem
|
||||
import io.element.android.libraries.push.impl.push.FakeMutableBatteryOptimizationStore
|
||||
import io.element.android.libraries.push.impl.push.MutableBatteryOptimizationStore
|
||||
@@ -40,6 +43,7 @@ import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushSto
|
||||
import io.element.android.libraries.pushstore.test.userpushstore.clientsecret.InMemoryPushClientSecretStore
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
|
||||
import io.element.android.libraries.sessionstorage.test.observer.NoOpSessionObserver
|
||||
import io.element.android.tests.testutils.lambda.any
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import kotlinx.coroutines.flow.first
|
||||
@@ -339,6 +343,281 @@ class DefaultPushServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - error when account is not verified`() = runTest {
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.NotVerified
|
||||
)
|
||||
val pushService = createDefaultPushService()
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.exceptionOrNull()!!).isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - case two push providers but first one does not have distributor - second one will be used`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider0 = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = emptyList(),
|
||||
)
|
||||
val distributor = Distributor("aDistributorValue1", "aDistributorName1")
|
||||
val pushProvider1 = FakePushProvider(
|
||||
index = 1,
|
||||
name = "aFakePushProvider1",
|
||||
distributors = listOf(distributor),
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(
|
||||
pushProvider0,
|
||||
pushProvider1,
|
||||
),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
lambda.assertions().isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// First distributor of second push provider
|
||||
value(distributor),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - case one push provider but no distributor available`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider",
|
||||
distributors = emptyList(),
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(pushProvider),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.exceptionOrNull()).isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions().isNeverCalled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - ensure default pusher is registered with default provider`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(
|
||||
FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider",
|
||||
distributors = listOf(Distributor("aDistributorValue0", "aDistributorName0")),
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// First distributor
|
||||
value(pushService.getAvailablePushProviders()[0].getDistributors()[0]),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - ensure default pusher is registered with default provider - fail to register`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.failure(AN_EXCEPTION)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(
|
||||
FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider",
|
||||
distributors = listOf(Distributor("aDistributorValue0", "aDistributorName0")),
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.isFailure).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// First distributor
|
||||
value(pushService.getAvailablePushProviders()[0].getDistributors()[0]),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - if current push provider does not have distributors, nothing happen`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = emptyList(),
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(pushProvider),
|
||||
getCurrentPushProvider = FakeGetCurrentPushProvider(currentPushProvider = pushProvider.name),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.exceptionOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - ensure current provider is registered with current distributor`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val distributor = Distributor("aDistributorValue1", "aDistributorName1")
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = listOf(
|
||||
Distributor("aDistributorValue0", "aDistributorName0"),
|
||||
distributor,
|
||||
),
|
||||
currentDistributor = { distributor },
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(pushProvider),
|
||||
getCurrentPushProvider = FakeGetCurrentPushProvider(currentPushProvider = pushProvider.name),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// Current distributor
|
||||
value(distributor),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - case no push provider available provider`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(SessionVerifiedStatus.Verified)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = emptySet(),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.exceptionOrNull())
|
||||
.isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java)
|
||||
lambda.assertions()
|
||||
.isNeverCalled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ensurePusher - if current push provider does not have current distributor, the first one is used`() = runTest {
|
||||
val lambda = lambdaRecorder<MatrixClient, Distributor, Result<Unit>> { _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val sessionVerificationService = FakeSessionVerificationService(
|
||||
initialSessionVerifiedStatus = SessionVerifiedStatus.Verified
|
||||
)
|
||||
val pushProvider = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
distributors = listOf(
|
||||
Distributor("aDistributorValue0", "aDistributorName0"),
|
||||
Distributor("aDistributorValue1", "aDistributorName1"),
|
||||
),
|
||||
currentDistributor = { null },
|
||||
registerWithResult = lambda,
|
||||
)
|
||||
val pushService = createDefaultPushService(
|
||||
pushProviders = setOf(pushProvider),
|
||||
getCurrentPushProvider = FakeGetCurrentPushProvider(currentPushProvider = pushProvider.name),
|
||||
)
|
||||
val result = pushService.ensurePusherIsRegistered(
|
||||
FakeMatrixClient(
|
||||
sessionVerificationService = sessionVerificationService,
|
||||
)
|
||||
)
|
||||
assertThat(result.isSuccess).isTrue()
|
||||
lambda.assertions()
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
// MatrixClient
|
||||
any(),
|
||||
// First distributor
|
||||
value(pushService.getAvailablePushProviders()[0].getDistributors()[0]),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createDefaultPushService(
|
||||
testPush: TestPush = FakeTestPush(),
|
||||
userPushStoreFactory: UserPushStoreFactory = FakeUserPushStoreFactory(),
|
||||
|
||||
@@ -32,6 +32,7 @@ class FakePushService(
|
||||
private val resetPushHistoryResult: () -> Unit = { lambdaError() },
|
||||
private val resetBatteryOptimizationStateResult: () -> Unit = { lambdaError() },
|
||||
private val onServiceUnregisteredResult: (UserId) -> Unit = { lambdaError() },
|
||||
private val ensurePusherIsRegisteredResult: () -> Result<Unit> = { lambdaError() },
|
||||
) : PushService {
|
||||
override suspend fun getCurrentPushProvider(sessionId: SessionId): PushProvider? {
|
||||
return registeredPushProvider ?: currentPushProvider(sessionId)
|
||||
@@ -56,6 +57,10 @@ class FakePushService(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ensurePusherIsRegistered(matrixClient: MatrixClient): Result<Unit> {
|
||||
return ensurePusherIsRegisteredResult()
|
||||
}
|
||||
|
||||
override suspend fun selectPushProvider(sessionId: SessionId, pushProvider: PushProvider) {
|
||||
selectPushProviderLambda(sessionId, pushProvider)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user