Ensure that disabling (resp. enabling) notification unregisters (resp. registers) the pusher
This commit is contained in:
parent
c7d4689473
commit
d3339872ff
11 changed files with 441 additions and 355 deletions
|
|
@ -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(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue