Merge pull request #3388 from element-hq/feature/bma/pushEndpoint
Unified push endpoint: do not fallback to default endpoint in case of failure and add troubleshoot test.
This commit is contained in:
commit
249e6e2925
22 changed files with 589 additions and 129 deletions
|
|
@ -37,7 +37,7 @@ class NotificationTroubleshootCheckPermissionTest @Inject constructor(
|
||||||
private val permissionStateProvider: PermissionStateProvider,
|
private val permissionStateProvider: PermissionStateProvider,
|
||||||
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
||||||
private val permissionActions: PermissionActions,
|
private val permissionActions: PermissionActions,
|
||||||
private val stringProvider: StringProvider,
|
stringProvider: StringProvider,
|
||||||
) : NotificationTroubleshootTest {
|
) : NotificationTroubleshootTest {
|
||||||
override val order: Int = 0
|
override val order: Int = 0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,4 +101,32 @@ class NotificationTroubleshootCheckPermissionTestTest {
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test NotificationTroubleshootCheckPermissionTest error and reset`() = runTest {
|
||||||
|
val permissionStateProvider = FakePermissionStateProvider(
|
||||||
|
permissionGranted = false
|
||||||
|
)
|
||||||
|
val actions = FakePermissionActions(
|
||||||
|
openSettingsAction = {
|
||||||
|
permissionStateProvider.setPermissionGranted()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
val sut = NotificationTroubleshootCheckPermissionTest(
|
||||||
|
permissionStateProvider = permissionStateProvider,
|
||||||
|
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU),
|
||||||
|
permissionActions = actions,
|
||||||
|
stringProvider = FakeStringProvider(),
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(true))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
import io.element.android.libraries.pushproviders.api.Distributor
|
import io.element.android.libraries.pushproviders.api.Distributor
|
||||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||||
import io.element.android.libraries.pushproviders.test.FakePushProvider
|
import io.element.android.libraries.pushproviders.test.FakePushProvider
|
||||||
|
import io.element.android.libraries.pushproviders.test.aCurrentUserPushConfig
|
||||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||||
import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStore
|
import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStore
|
||||||
import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
|
import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
|
||||||
|
|
@ -57,10 +58,7 @@ class DefaultPushServiceTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test push ok`() = runTest {
|
fun `test push ok`() = runTest {
|
||||||
val aConfig = CurrentUserPushConfig(
|
val aConfig = aCurrentUserPushConfig()
|
||||||
url = "aUrl",
|
|
||||||
pushKey = "aPushKey",
|
|
||||||
)
|
|
||||||
val testPushResult = lambdaRecorder<CurrentUserPushConfig, Unit> { }
|
val testPushResult = lambdaRecorder<CurrentUserPushConfig, Unit> { }
|
||||||
val aPushProvider = FakePushProvider(
|
val aPushProvider = FakePushProvider(
|
||||||
currentUserPushConfig = aConfig
|
currentUserPushConfig = aConfig
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.push.impl.test
|
||||||
|
|
||||||
import io.element.android.appconfig.PushConfig
|
import io.element.android.appconfig.PushConfig
|
||||||
import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest
|
import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest
|
||||||
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
import io.element.android.libraries.pushproviders.test.aCurrentUserPushConfig
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -33,10 +33,7 @@ class DefaultTestPushTest {
|
||||||
executeResult = executeResult,
|
executeResult = executeResult,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val aConfig = CurrentUserPushConfig(
|
val aConfig = aCurrentUserPushConfig()
|
||||||
url = "aUrl",
|
|
||||||
pushKey = "aPushKey",
|
|
||||||
)
|
|
||||||
defaultTestPush.execute(aConfig)
|
defaultTestPush.execute(aConfig)
|
||||||
executeResult.assertions()
|
executeResult.assertions()
|
||||||
.isCalledOnce()
|
.isCalledOnce()
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ class CurrentPushProviderTestTest {
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
val lastItem = awaitItem()
|
val lastItem = awaitItem()
|
||||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ class NotificationTestTest {
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.WaitingForUser)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.WaitingForUser)
|
||||||
assertThat(awaitItem().status).isInstanceOf(NotificationTroubleshootTestState.Status.Failure::class.java)
|
assertThat(awaitItem().status).isInstanceOf(NotificationTroubleshootTestState.Status.Failure::class.java)
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@ class PushLoopbackTestTest {
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
val lastItem = awaitItem()
|
val lastItem = awaitItem()
|
||||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ class PushProvidersTestTest {
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
val lastItem = awaitItem()
|
val lastItem = awaitItem()
|
||||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ class FirebaseAvailabilityTestTest {
|
||||||
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
val lastItem = awaitItem()
|
val lastItem = awaitItem()
|
||||||
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,31 @@ class FirebaseTokenTestTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test FirebaseTokenTest error and reset`() = runTest {
|
||||||
|
val firebaseStore = InMemoryFirebaseStore(null)
|
||||||
|
val sut = FirebaseTokenTest(
|
||||||
|
firebaseStore = firebaseStore,
|
||||||
|
firebaseTroubleshooter = FakeFirebaseTroubleshooter(
|
||||||
|
troubleShootResult = {
|
||||||
|
firebaseStore.storeFcmToken(FAKE_TOKEN)
|
||||||
|
Result.success(Unit)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
stringProvider = FakeStringProvider(),
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(true))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test FirebaseTokenTest isRelevant`() {
|
fun `test FirebaseTokenTest isRelevant`() {
|
||||||
val sut = FirebaseTokenTest(
|
val sut = FirebaseTokenTest(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.pushproviders.test
|
||||||
|
|
||||||
|
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
|
|
||||||
|
fun aCurrentUserPushConfig(
|
||||||
|
url: String = "aUrl",
|
||||||
|
pushKey: String = "aPushKey",
|
||||||
|
) = CurrentUserPushConfig(
|
||||||
|
url = url,
|
||||||
|
pushKey = pushKey,
|
||||||
|
)
|
||||||
|
|
@ -60,6 +60,7 @@ dependencies {
|
||||||
testImplementation(libs.test.turbine)
|
testImplementation(libs.test.turbine)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
testImplementation(projects.libraries.push.test)
|
testImplementation(projects.libraries.push.test)
|
||||||
|
testImplementation(projects.libraries.pushproviders.test)
|
||||||
testImplementation(projects.libraries.pushstore.test)
|
testImplementation(projects.libraries.pushstore.test)
|
||||||
testImplementation(projects.tests.testutils)
|
testImplementation(projects.tests.testutils)
|
||||||
testImplementation(projects.services.toolbox.test)
|
testImplementation(projects.services.toolbox.test)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.pushproviders.unifiedpush
|
||||||
|
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
|
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
|
||||||
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
|
import io.element.android.services.appnavstate.api.currentSessionId
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
interface UnifiedPushCurrentUserPushConfigProvider {
|
||||||
|
suspend fun provide(): CurrentUserPushConfig?
|
||||||
|
}
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultUnifiedPushCurrentUserPushConfigProvider @Inject constructor(
|
||||||
|
private val pushClientSecret: PushClientSecret,
|
||||||
|
private val unifiedPushStore: UnifiedPushStore,
|
||||||
|
private val appNavigationStateService: AppNavigationStateService,
|
||||||
|
) : UnifiedPushCurrentUserPushConfigProvider {
|
||||||
|
override suspend fun provide(): CurrentUserPushConfig? {
|
||||||
|
val currentSession = appNavigationStateService.appNavigationState.value.navigationState.currentSessionId() ?: return null
|
||||||
|
val clientSecret = pushClientSecret.getSecretForUser(currentSession)
|
||||||
|
val url = unifiedPushStore.getPushGateway(clientSecret) ?: return null
|
||||||
|
val pushKey = unifiedPushStore.getEndpoint(clientSecret) ?: return null
|
||||||
|
return CurrentUserPushConfig(
|
||||||
|
url = url,
|
||||||
|
pushKey = pushKey,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ package io.element.android.libraries.pushproviders.unifiedpush
|
||||||
|
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
|
import io.element.android.libraries.core.data.tryOrNull
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -33,30 +34,37 @@ class DefaultUnifiedPushGatewayResolver @Inject constructor(
|
||||||
private val unifiedPushApiFactory: UnifiedPushApiFactory,
|
private val unifiedPushApiFactory: UnifiedPushApiFactory,
|
||||||
private val coroutineDispatchers: CoroutineDispatchers,
|
private val coroutineDispatchers: CoroutineDispatchers,
|
||||||
) : UnifiedPushGatewayResolver {
|
) : UnifiedPushGatewayResolver {
|
||||||
|
private val logger = Timber.tag("DefaultUnifiedPushGatewayResolver")
|
||||||
|
|
||||||
override suspend fun getGateway(endpoint: String): String {
|
override suspend fun getGateway(endpoint: String): String {
|
||||||
val gateway = UnifiedPushConfig.DEFAULT_PUSH_GATEWAY_HTTP_URL
|
val url = tryOrNull(
|
||||||
try {
|
onError = { logger.d(it, "Cannot parse endpoint as an URL") }
|
||||||
val url = URL(endpoint)
|
) {
|
||||||
|
URL(endpoint)
|
||||||
|
}
|
||||||
|
return if (url == null) {
|
||||||
|
logger.d("Using default gateway")
|
||||||
|
UnifiedPushConfig.DEFAULT_PUSH_GATEWAY_HTTP_URL
|
||||||
|
} else {
|
||||||
val port = if (url.port != -1) ":${url.port}" else ""
|
val port = if (url.port != -1) ":${url.port}" else ""
|
||||||
val customBase = "${url.protocol}://${url.host}$port"
|
val customBase = "${url.protocol}://${url.host}$port"
|
||||||
val customUrl = "$customBase/_matrix/push/v1/notify"
|
val customUrl = "$customBase/_matrix/push/v1/notify"
|
||||||
Timber.i("Testing $customUrl")
|
logger.i("Testing $customUrl")
|
||||||
return withContext(coroutineDispatchers.io) {
|
return withContext(coroutineDispatchers.io) {
|
||||||
val api = unifiedPushApiFactory.create(customBase)
|
val api = unifiedPushApiFactory.create(customBase)
|
||||||
try {
|
try {
|
||||||
val discoveryResponse = api.discover()
|
val discoveryResponse = api.discover()
|
||||||
if (discoveryResponse.unifiedpush.gateway == "matrix") {
|
if (discoveryResponse.unifiedpush.gateway == "matrix") {
|
||||||
Timber.d("Using custom gateway")
|
logger.d("The endpoint seems to be a valid UnifiedPush gateway")
|
||||||
return@withContext customUrl
|
} else {
|
||||||
|
logger.e("The endpoint does not seem to be a valid UnifiedPush gateway")
|
||||||
}
|
}
|
||||||
} catch (throwable: Throwable) {
|
} catch (throwable: Throwable) {
|
||||||
Timber.tag("UnifiedPushHelper").e(throwable)
|
logger.e(throwable, "Error checking for UnifiedPush endpoint")
|
||||||
}
|
}
|
||||||
return@withContext gateway
|
// Always return the custom url.
|
||||||
|
customUrl
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.d(e, "Cannot try custom gateway")
|
|
||||||
}
|
}
|
||||||
return gateway
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,6 @@ import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
import io.element.android.libraries.pushproviders.api.Distributor
|
import io.element.android.libraries.pushproviders.api.Distributor
|
||||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||||
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
|
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
|
||||||
import io.element.android.services.appnavstate.api.currentSessionId
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ContributesMultibinding(AppScope::class)
|
@ContributesMultibinding(AppScope::class)
|
||||||
|
|
@ -34,7 +32,7 @@ class UnifiedPushProvider @Inject constructor(
|
||||||
private val unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
|
private val unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase,
|
||||||
private val pushClientSecret: PushClientSecret,
|
private val pushClientSecret: PushClientSecret,
|
||||||
private val unifiedPushStore: UnifiedPushStore,
|
private val unifiedPushStore: UnifiedPushStore,
|
||||||
private val appNavigationStateService: AppNavigationStateService,
|
private val unifiedPushCurrentUserPushConfigProvider: UnifiedPushCurrentUserPushConfigProvider,
|
||||||
) : PushProvider {
|
) : PushProvider {
|
||||||
override val index = UnifiedPushConfig.INDEX
|
override val index = UnifiedPushConfig.INDEX
|
||||||
override val name = UnifiedPushConfig.NAME
|
override val name = UnifiedPushConfig.NAME
|
||||||
|
|
@ -62,13 +60,6 @@ class UnifiedPushProvider @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? {
|
override suspend fun getCurrentUserPushConfig(): CurrentUserPushConfig? {
|
||||||
val currentSession = appNavigationStateService.appNavigationState.value.navigationState.currentSessionId() ?: return null
|
return unifiedPushCurrentUserPushConfigProvider.provide()
|
||||||
val clientSecret = pushClientSecret.getSecretForUser(currentSession)
|
|
||||||
val url = unifiedPushStore.getPushGateway(clientSecret) ?: return null
|
|
||||||
val pushKey = unifiedPushStore.getEndpoint(clientSecret) ?: return null
|
|
||||||
return CurrentUserPushConfig(
|
|
||||||
url = url,
|
|
||||||
pushKey = pushKey,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.pushproviders.unifiedpush.troubleshoot
|
||||||
|
|
||||||
|
import com.squareup.anvil.annotations.ContributesMultibinding
|
||||||
|
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushApiFactory
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushCurrentUserPushConfigProvider
|
||||||
|
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTest
|
||||||
|
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestDelegate
|
||||||
|
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState
|
||||||
|
import io.element.android.libraries.troubleshoot.api.test.TestFilterData
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesMultibinding(AppScope::class)
|
||||||
|
class UnifiedPushMatrixGatewayTest @Inject constructor(
|
||||||
|
private val unifiedPushApiFactory: UnifiedPushApiFactory,
|
||||||
|
private val coroutineDispatchers: CoroutineDispatchers,
|
||||||
|
private val unifiedPushCurrentUserPushConfigProvider: UnifiedPushCurrentUserPushConfigProvider,
|
||||||
|
) : NotificationTroubleshootTest {
|
||||||
|
override val order = 450
|
||||||
|
private val delegate = NotificationTroubleshootTestDelegate(
|
||||||
|
defaultName = "Test push gateway",
|
||||||
|
defaultDescription = "Ensure that the push gateway is valid.",
|
||||||
|
visibleWhenIdle = false,
|
||||||
|
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
|
||||||
|
)
|
||||||
|
override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state
|
||||||
|
|
||||||
|
override fun isRelevant(data: TestFilterData): Boolean {
|
||||||
|
return data.currentPushProviderName == UnifiedPushConfig.NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun run(coroutineScope: CoroutineScope) {
|
||||||
|
delegate.start()
|
||||||
|
val config = unifiedPushCurrentUserPushConfigProvider.provide()
|
||||||
|
if (config == null) {
|
||||||
|
delegate.updateState(
|
||||||
|
description = "No current push provider",
|
||||||
|
status = NotificationTroubleshootTestState.Status.Failure(false)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val gatewayBaseUrl = config.url.removeSuffix("/_matrix/push/v1/notify")
|
||||||
|
// Checking if the gateway is a Matrix gateway
|
||||||
|
coroutineScope.launch(coroutineDispatchers.io) {
|
||||||
|
val api = unifiedPushApiFactory.create(gatewayBaseUrl)
|
||||||
|
try {
|
||||||
|
val discoveryResponse = api.discover()
|
||||||
|
if (discoveryResponse.unifiedpush.gateway == "matrix") {
|
||||||
|
delegate.updateState(
|
||||||
|
description = "${config.url} is a Matrix gateway.",
|
||||||
|
status = NotificationTroubleshootTestState.Status.Success
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
delegate.updateState(
|
||||||
|
description = "${config.url} is not a Matrix gateway.",
|
||||||
|
status = NotificationTroubleshootTestState.Status.Failure(false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (throwable: Throwable) {
|
||||||
|
delegate.updateState(
|
||||||
|
description = "Fail to check the gateway ${config.url}: ${throwable.localizedMessage}",
|
||||||
|
status = NotificationTroubleshootTestState.Status.Failure(false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun reset() = delegate.reset()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.pushproviders.unifiedpush
|
||||||
|
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.test.A_SECRET
|
||||||
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
|
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
|
||||||
|
import io.element.android.libraries.pushstore.test.userpushstore.clientsecret.FakePushClientSecret
|
||||||
|
import io.element.android.services.appnavstate.api.AppNavigationState
|
||||||
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
|
import io.element.android.services.appnavstate.api.NavigationState
|
||||||
|
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class DefaultUnifiedPushCurrentUserPushConfigProviderTest {
|
||||||
|
@Test
|
||||||
|
fun `getCurrentUserPushConfig no session`() = runTest {
|
||||||
|
val sut = createDefaultUnifiedPushCurrentUserPushConfigProvider()
|
||||||
|
val result = sut.provide()
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getCurrentUserPushConfig no push gateway`() = runTest {
|
||||||
|
val sut = createDefaultUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
appNavigationStateService = FakeAppNavigationStateService(
|
||||||
|
appNavigationState = MutableStateFlow(
|
||||||
|
AppNavigationState(
|
||||||
|
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
|
||||||
|
isInForeground = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
pushClientSecret = FakePushClientSecret(
|
||||||
|
getSecretForUserResult = { A_SECRET }
|
||||||
|
),
|
||||||
|
unifiedPushStore = FakeUnifiedPushStore(
|
||||||
|
getPushGatewayResult = { null }
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val result = sut.provide()
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getCurrentUserPushConfig no push key`() = runTest {
|
||||||
|
val sut = createDefaultUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
appNavigationStateService = FakeAppNavigationStateService(
|
||||||
|
appNavigationState = MutableStateFlow(
|
||||||
|
AppNavigationState(
|
||||||
|
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
|
||||||
|
isInForeground = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
pushClientSecret = FakePushClientSecret(
|
||||||
|
getSecretForUserResult = { A_SECRET }
|
||||||
|
),
|
||||||
|
unifiedPushStore = FakeUnifiedPushStore(
|
||||||
|
getPushGatewayResult = { "aPushGateway" },
|
||||||
|
getEndpointResult = { null }
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val result = sut.provide()
|
||||||
|
assertThat(result).isNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getCurrentUserPushConfig ok`() = runTest {
|
||||||
|
val sut = createDefaultUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
appNavigationStateService = FakeAppNavigationStateService(
|
||||||
|
appNavigationState = MutableStateFlow(
|
||||||
|
AppNavigationState(
|
||||||
|
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
|
||||||
|
isInForeground = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
pushClientSecret = FakePushClientSecret(
|
||||||
|
getSecretForUserResult = { A_SECRET }
|
||||||
|
),
|
||||||
|
unifiedPushStore = FakeUnifiedPushStore(
|
||||||
|
getPushGatewayResult = { "aPushGateway" },
|
||||||
|
getEndpointResult = { "aEndpoint" }
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val result = sut.provide()
|
||||||
|
assertThat(result).isEqualTo(CurrentUserPushConfig("aPushGateway", "aEndpoint"))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createDefaultUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
pushClientSecret: PushClientSecret = FakePushClientSecret(),
|
||||||
|
unifiedPushStore: UnifiedPushStore = FakeUnifiedPushStore(),
|
||||||
|
appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(),
|
||||||
|
): DefaultUnifiedPushCurrentUserPushConfigProvider {
|
||||||
|
return DefaultUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
pushClientSecret = pushClientSecret,
|
||||||
|
unifiedPushStore = unifiedPushStore,
|
||||||
|
appNavigationStateService = appNavigationStateService,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,23 +25,23 @@ import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
internal val matrixDiscoveryResponse = {
|
||||||
|
DiscoveryResponse(
|
||||||
|
unifiedpush = DiscoveryUnifiedPush(
|
||||||
|
gateway = "matrix"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val invalidDiscoveryResponse = {
|
||||||
|
DiscoveryResponse(
|
||||||
|
unifiedpush = DiscoveryUnifiedPush(
|
||||||
|
gateway = ""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class DefaultUnifiedPushGatewayResolverTest {
|
class DefaultUnifiedPushGatewayResolverTest {
|
||||||
private val matrixDiscoveryResponse = {
|
|
||||||
DiscoveryResponse(
|
|
||||||
unifiedpush = DiscoveryUnifiedPush(
|
|
||||||
gateway = "matrix"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val invalidDiscoveryResponse = {
|
|
||||||
DiscoveryResponse(
|
|
||||||
unifiedpush = DiscoveryUnifiedPush(
|
|
||||||
gateway = ""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when a custom url provide a correct matrix gateway, the custom url is returned`() = runTest {
|
fun `when a custom url provide a correct matrix gateway, the custom url is returned`() = runTest {
|
||||||
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
||||||
|
|
@ -95,7 +95,7 @@ class DefaultUnifiedPushGatewayResolverTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when a custom url is not reachable, the default url is returned`() = runTest {
|
fun `when a custom url is not reachable, the custom url is still returned`() = runTest {
|
||||||
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
||||||
discoveryResponse = { throw AN_EXCEPTION }
|
discoveryResponse = { throw AN_EXCEPTION }
|
||||||
)
|
)
|
||||||
|
|
@ -104,7 +104,7 @@ class DefaultUnifiedPushGatewayResolverTest {
|
||||||
)
|
)
|
||||||
val result = sut.getGateway("http://custom.url")
|
val result = sut.getGateway("http://custom.url")
|
||||||
assertThat(unifiedPushApiFactory.baseUrlParameter).isEqualTo("http://custom.url")
|
assertThat(unifiedPushApiFactory.baseUrlParameter).isEqualTo("http://custom.url")
|
||||||
assertThat(result).isEqualTo(UnifiedPushConfig.DEFAULT_PUSH_GATEWAY_HTTP_URL)
|
assertThat(result).isEqualTo("http://custom.url/_matrix/push/v1/notify")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -121,7 +121,7 @@ class DefaultUnifiedPushGatewayResolverTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when a custom url provides a invalid matrix gateway, the default url is returned`() = runTest {
|
fun `when a custom url provides a invalid matrix gateway, the custom url is still returned`() = runTest {
|
||||||
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
||||||
discoveryResponse = invalidDiscoveryResponse
|
discoveryResponse = invalidDiscoveryResponse
|
||||||
)
|
)
|
||||||
|
|
@ -130,7 +130,7 @@ class DefaultUnifiedPushGatewayResolverTest {
|
||||||
)
|
)
|
||||||
val result = sut.getGateway("https://custom.url")
|
val result = sut.getGateway("https://custom.url")
|
||||||
assertThat(unifiedPushApiFactory.baseUrlParameter).isEqualTo("https://custom.url")
|
assertThat(unifiedPushApiFactory.baseUrlParameter).isEqualTo("https://custom.url")
|
||||||
assertThat(result).isEqualTo(UnifiedPushConfig.DEFAULT_PUSH_GATEWAY_HTTP_URL)
|
assertThat(result).isEqualTo("https://custom.url/_matrix/push/v1/notify")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TestScope.createDefaultUnifiedPushGatewayResolver(
|
private fun TestScope.createDefaultUnifiedPushGatewayResolver(
|
||||||
|
|
|
||||||
|
|
@ -24,18 +24,14 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
import io.element.android.libraries.matrix.test.A_SECRET
|
import io.element.android.libraries.matrix.test.A_SECRET
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_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.FakeMatrixClient
|
||||||
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
|
||||||
import io.element.android.libraries.pushproviders.api.Distributor
|
import io.element.android.libraries.pushproviders.api.Distributor
|
||||||
|
import io.element.android.libraries.pushproviders.test.aCurrentUserPushConfig
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.troubleshoot.FakeUnifiedPushCurrentUserPushConfigProvider
|
||||||
import io.element.android.libraries.pushproviders.unifiedpush.troubleshoot.FakeUnifiedPushDistributorProvider
|
import io.element.android.libraries.pushproviders.unifiedpush.troubleshoot.FakeUnifiedPushDistributorProvider
|
||||||
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
|
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
|
||||||
import io.element.android.libraries.pushstore.test.userpushstore.clientsecret.FakePushClientSecret
|
import io.element.android.libraries.pushstore.test.userpushstore.clientsecret.FakePushClientSecret
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationState
|
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
|
||||||
import io.element.android.services.appnavstate.api.NavigationState
|
|
||||||
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
|
@ -226,78 +222,15 @@ class UnifiedPushProviderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `getCurrentUserPushConfig no session`() = runTest {
|
fun `getCurrentUserPushConfig invokes the provider methods`() = runTest {
|
||||||
val unifiedPushProvider = createUnifiedPushProvider()
|
val currentUserPushConfig = aCurrentUserPushConfig()
|
||||||
val result = unifiedPushProvider.getCurrentUserPushConfig()
|
|
||||||
assertThat(result).isNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getCurrentUserPushConfig no push gateway`() = runTest {
|
|
||||||
val unifiedPushProvider = createUnifiedPushProvider(
|
val unifiedPushProvider = createUnifiedPushProvider(
|
||||||
appNavigationStateService = FakeAppNavigationStateService(
|
unifiedPushCurrentUserPushConfigProvider = FakeUnifiedPushCurrentUserPushConfigProvider(
|
||||||
appNavigationState = MutableStateFlow(
|
currentUserPushConfig = { currentUserPushConfig }
|
||||||
AppNavigationState(
|
)
|
||||||
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
|
|
||||||
isInForeground = true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
pushClientSecret = FakePushClientSecret(
|
|
||||||
getSecretForUserResult = { A_SECRET }
|
|
||||||
),
|
|
||||||
unifiedPushStore = FakeUnifiedPushStore(
|
|
||||||
getPushGatewayResult = { null }
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
val result = unifiedPushProvider.getCurrentUserPushConfig()
|
val result = unifiedPushProvider.getCurrentUserPushConfig()
|
||||||
assertThat(result).isNull()
|
assertThat(result).isEqualTo(currentUserPushConfig)
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getCurrentUserPushConfig no push key`() = runTest {
|
|
||||||
val unifiedPushProvider = createUnifiedPushProvider(
|
|
||||||
appNavigationStateService = FakeAppNavigationStateService(
|
|
||||||
appNavigationState = MutableStateFlow(
|
|
||||||
AppNavigationState(
|
|
||||||
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
|
|
||||||
isInForeground = true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
pushClientSecret = FakePushClientSecret(
|
|
||||||
getSecretForUserResult = { A_SECRET }
|
|
||||||
),
|
|
||||||
unifiedPushStore = FakeUnifiedPushStore(
|
|
||||||
getPushGatewayResult = { "aPushGateway" },
|
|
||||||
getEndpointResult = { null }
|
|
||||||
),
|
|
||||||
)
|
|
||||||
val result = unifiedPushProvider.getCurrentUserPushConfig()
|
|
||||||
assertThat(result).isNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `getCurrentUserPushConfig ok`() = runTest {
|
|
||||||
val unifiedPushProvider = createUnifiedPushProvider(
|
|
||||||
appNavigationStateService = FakeAppNavigationStateService(
|
|
||||||
appNavigationState = MutableStateFlow(
|
|
||||||
AppNavigationState(
|
|
||||||
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
|
|
||||||
isInForeground = true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
pushClientSecret = FakePushClientSecret(
|
|
||||||
getSecretForUserResult = { A_SECRET }
|
|
||||||
),
|
|
||||||
unifiedPushStore = FakeUnifiedPushStore(
|
|
||||||
getPushGatewayResult = { "aPushGateway" },
|
|
||||||
getEndpointResult = { "aEndpoint" }
|
|
||||||
),
|
|
||||||
)
|
|
||||||
val result = unifiedPushProvider.getCurrentUserPushConfig()
|
|
||||||
assertThat(result).isEqualTo(CurrentUserPushConfig("aPushGateway", "aEndpoint"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createUnifiedPushProvider(
|
private fun createUnifiedPushProvider(
|
||||||
|
|
@ -306,7 +239,7 @@ class UnifiedPushProviderTest {
|
||||||
unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase = FakeUnregisterUnifiedPushUseCase(),
|
unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase = FakeUnregisterUnifiedPushUseCase(),
|
||||||
pushClientSecret: PushClientSecret = FakePushClientSecret(),
|
pushClientSecret: PushClientSecret = FakePushClientSecret(),
|
||||||
unifiedPushStore: UnifiedPushStore = FakeUnifiedPushStore(),
|
unifiedPushStore: UnifiedPushStore = FakeUnifiedPushStore(),
|
||||||
appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(),
|
unifiedPushCurrentUserPushConfigProvider: UnifiedPushCurrentUserPushConfigProvider = FakeUnifiedPushCurrentUserPushConfigProvider(),
|
||||||
): UnifiedPushProvider {
|
): UnifiedPushProvider {
|
||||||
return UnifiedPushProvider(
|
return UnifiedPushProvider(
|
||||||
unifiedPushDistributorProvider = unifiedPushDistributorProvider,
|
unifiedPushDistributorProvider = unifiedPushDistributorProvider,
|
||||||
|
|
@ -314,7 +247,7 @@ class UnifiedPushProviderTest {
|
||||||
unRegisterUnifiedPushUseCase = unRegisterUnifiedPushUseCase,
|
unRegisterUnifiedPushUseCase = unRegisterUnifiedPushUseCase,
|
||||||
pushClientSecret = pushClientSecret,
|
pushClientSecret = pushClientSecret,
|
||||||
unifiedPushStore = unifiedPushStore,
|
unifiedPushStore = unifiedPushStore,
|
||||||
appNavigationStateService = appNavigationStateService
|
unifiedPushCurrentUserPushConfigProvider = unifiedPushCurrentUserPushConfigProvider,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.pushproviders.unifiedpush.troubleshoot
|
||||||
|
|
||||||
|
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushCurrentUserPushConfigProvider
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
|
||||||
|
class FakeUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
private val currentUserPushConfig: () -> CurrentUserPushConfig? = { lambdaError() },
|
||||||
|
) : UnifiedPushCurrentUserPushConfigProvider {
|
||||||
|
override suspend fun provide(): CurrentUserPushConfig? {
|
||||||
|
return currentUserPushConfig()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.pushproviders.unifiedpush.troubleshoot
|
||||||
|
|
||||||
|
import app.cash.turbine.test
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
|
||||||
|
import io.element.android.libraries.pushproviders.test.aCurrentUserPushConfig
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.FakeUnifiedPushApiFactory
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.invalidDiscoveryResponse
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.matrixDiscoveryResponse
|
||||||
|
import io.element.android.libraries.pushproviders.unifiedpush.network.DiscoveryResponse
|
||||||
|
import io.element.android.libraries.troubleshoot.api.test.NotificationTroubleshootTestState
|
||||||
|
import io.element.android.libraries.troubleshoot.api.test.TestFilterData
|
||||||
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class UnifiedPushMatrixGatewayTestTest {
|
||||||
|
@Test
|
||||||
|
fun `test UnifiedPushMatrixGatewayTest success`() = runTest {
|
||||||
|
val sut = createUnifiedPushMatrixGatewayTest(
|
||||||
|
currentUserPushConfig = aCurrentUserPushConfig(),
|
||||||
|
discoveryResponse = matrixDiscoveryResponse,
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test UnifiedPushMatrixGatewayTest no config found`() = runTest {
|
||||||
|
val sut = createUnifiedPushMatrixGatewayTest(
|
||||||
|
currentUserPushConfig = null,
|
||||||
|
discoveryResponse = matrixDiscoveryResponse,
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test UnifiedPushMatrixGatewayTest not valid gateway`() = runTest {
|
||||||
|
val sut = createUnifiedPushMatrixGatewayTest(
|
||||||
|
currentUserPushConfig = aCurrentUserPushConfig(),
|
||||||
|
discoveryResponse = invalidDiscoveryResponse,
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
// Reset the error
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test UnifiedPushMatrixGatewayTest network error`() = runTest {
|
||||||
|
val sut = createUnifiedPushMatrixGatewayTest(
|
||||||
|
currentUserPushConfig = aCurrentUserPushConfig(),
|
||||||
|
discoveryResponse = { error("Network error") },
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test isRelevant`() = runTest {
|
||||||
|
val sut = createUnifiedPushMatrixGatewayTest()
|
||||||
|
assertThat(sut.isRelevant(TestFilterData(currentPushProviderName = UnifiedPushConfig.NAME))).isTrue()
|
||||||
|
assertThat(sut.isRelevant(TestFilterData(currentPushProviderName = "other"))).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TestScope.createUnifiedPushMatrixGatewayTest(
|
||||||
|
currentUserPushConfig: CurrentUserPushConfig? = null,
|
||||||
|
discoveryResponse: () -> DiscoveryResponse = matrixDiscoveryResponse,
|
||||||
|
): UnifiedPushMatrixGatewayTest {
|
||||||
|
return UnifiedPushMatrixGatewayTest(
|
||||||
|
unifiedPushApiFactory = FakeUnifiedPushApiFactory(discoveryResponse),
|
||||||
|
coroutineDispatchers = testCoroutineDispatchers(),
|
||||||
|
unifiedPushCurrentUserPushConfigProvider = FakeUnifiedPushCurrentUserPushConfigProvider(
|
||||||
|
currentUserPushConfig = { currentUserPushConfig }
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -84,6 +84,35 @@ class UnifiedPushTestTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test UnifiedPushTest error and reset`() = runTest {
|
||||||
|
val providers = FakeUnifiedPushDistributorProvider()
|
||||||
|
val sut = UnifiedPushTest(
|
||||||
|
unifiedPushDistributorProvider = providers,
|
||||||
|
openDistributorWebPageAction = FakeOpenDistributorWebPageAction(
|
||||||
|
executeAction = {
|
||||||
|
providers.setDistributorsResult(
|
||||||
|
listOf(
|
||||||
|
Distributor("value", "Name"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
stringProvider = FakeStringProvider(),
|
||||||
|
)
|
||||||
|
launch {
|
||||||
|
sut.run(this)
|
||||||
|
}
|
||||||
|
sut.state.test {
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(true))
|
||||||
|
sut.reset()
|
||||||
|
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.Idle(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test isRelevant`() {
|
fun `test isRelevant`() {
|
||||||
val sut = UnifiedPushTest(
|
val sut = UnifiedPushTest(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue