Always use the custom url, even if no Matrix gateway is detected.
This commit is contained in:
@@ -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(projects.libraries.matrix.test)
|
||||
testImplementation(projects.libraries.push.test)
|
||||
testImplementation(projects.libraries.pushproviders.test)
|
||||
testImplementation(projects.libraries.pushstore.test)
|
||||
testImplementation(projects.tests.testutils)
|
||||
testImplementation(projects.services.toolbox.test)
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
package io.element.android.libraries.pushproviders.unifiedpush
|
||||
|
||||
object UnifiedPushConfig {
|
||||
const val PUSH_GATEWAY_PATH: String = "_matrix/push/v1/notify"
|
||||
|
||||
/**
|
||||
* It is the push gateway for UnifiedPush.
|
||||
* Note: default_push_gateway_http_url should have path '/_matrix/push/v1/notify'
|
||||
*/
|
||||
const val DEFAULT_PUSH_GATEWAY_HTTP_URL: String = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify"
|
||||
const val DEFAULT_PUSH_GATEWAY_HTTP_URL: String = "https://matrix.gateway.unifiedpush.org/$PUSH_GATEWAY_PATH"
|
||||
|
||||
const val UNIFIED_PUSH_DISTRIBUTORS_URL = "https://unifiedpush.org/users/distributors/"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package io.element.android.libraries.pushproviders.unifiedpush
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
@@ -34,12 +35,18 @@ class DefaultUnifiedPushGatewayResolver @Inject constructor(
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
) : UnifiedPushGatewayResolver {
|
||||
override suspend fun getGateway(endpoint: String): String {
|
||||
val gateway = UnifiedPushConfig.DEFAULT_PUSH_GATEWAY_HTTP_URL
|
||||
try {
|
||||
val url = URL(endpoint)
|
||||
val url = tryOrNull(
|
||||
onError = { Timber.d(it, "Cannot parse endpoint as an URL") }
|
||||
) {
|
||||
URL(endpoint)
|
||||
}
|
||||
return if (url == null) {
|
||||
Timber.d("Using default gateway")
|
||||
UnifiedPushConfig.DEFAULT_PUSH_GATEWAY_HTTP_URL
|
||||
} else {
|
||||
val port = if (url.port != -1) ":${url.port}" else ""
|
||||
val customBase = "${url.protocol}://${url.host}$port"
|
||||
val customUrl = "$customBase/_matrix/push/v1/notify"
|
||||
val customUrl = "$customBase/${UnifiedPushConfig.PUSH_GATEWAY_PATH}"
|
||||
Timber.i("Testing $customUrl")
|
||||
return withContext(coroutineDispatchers.io) {
|
||||
val api = unifiedPushApiFactory.create(customBase)
|
||||
@@ -47,16 +54,13 @@ class DefaultUnifiedPushGatewayResolver @Inject constructor(
|
||||
val discoveryResponse = api.discover()
|
||||
if (discoveryResponse.unifiedpush.gateway == "matrix") {
|
||||
Timber.d("Using custom gateway")
|
||||
return@withContext customUrl
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
Timber.tag("UnifiedPushHelper").e(throwable)
|
||||
}
|
||||
return@withContext gateway
|
||||
// Always return the custom url.
|
||||
customUrl
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Timber.d(e, "Cannot try custom gateway")
|
||||
}
|
||||
return gateway
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
package io.element.android.libraries.pushproviders.unifiedpush.network
|
||||
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig
|
||||
import retrofit2.http.GET
|
||||
|
||||
interface UnifiedPushApi {
|
||||
@GET("_matrix/push/v1/notify")
|
||||
@GET(UnifiedPushConfig.PUSH_GATEWAY_PATH)
|
||||
suspend fun discover(): DiscoveryResponse
|
||||
}
|
||||
|
||||
@@ -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.api.PushProvider
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushApiFactory
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig
|
||||
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 pushProvider: PushProvider,
|
||||
) : 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 = pushProvider.getCurrentUserPushConfig()
|
||||
if (config == null) {
|
||||
delegate.updateState(
|
||||
description = "No current push provider",
|
||||
status = NotificationTroubleshootTestState.Status.Failure(false)
|
||||
)
|
||||
} else {
|
||||
val gatewayBaseUrl = config.url.removeSuffix("/${UnifiedPushConfig.PUSH_GATEWAY_PATH}")
|
||||
// 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()
|
||||
}
|
||||
@@ -25,23 +25,23 @@ import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
internal val matrixDiscoveryResponse = {
|
||||
DiscoveryResponse(
|
||||
unifiedpush = DiscoveryUnifiedPush(
|
||||
gateway = "matrix"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
internal val invalidDiscoveryResponse = {
|
||||
DiscoveryResponse(
|
||||
unifiedpush = DiscoveryUnifiedPush(
|
||||
gateway = ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class DefaultUnifiedPushGatewayResolverTest {
|
||||
private val matrixDiscoveryResponse = {
|
||||
DiscoveryResponse(
|
||||
unifiedpush = DiscoveryUnifiedPush(
|
||||
gateway = "matrix"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val invalidDiscoveryResponse = {
|
||||
DiscoveryResponse(
|
||||
unifiedpush = DiscoveryUnifiedPush(
|
||||
gateway = ""
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when a custom url provide a correct matrix gateway, the custom url is returned`() = runTest {
|
||||
val unifiedPushApiFactory = FakeUnifiedPushApiFactory(
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.FakePushProvider
|
||||
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 = { throw RuntimeException("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(),
|
||||
pushProvider = FakePushProvider(currentUserPushConfig = currentUserPushConfig),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user