mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
Fix and add tests
This commit is contained in:
committed by
Jorge Martin Espinosa
parent
e3290707d9
commit
e24468c74f
+9
-3
@@ -12,6 +12,7 @@ import androidx.compose.ui.graphics.Color
|
||||
import io.element.android.compound.colors.SemanticColorsLightDark
|
||||
import io.element.android.features.enterprise.api.BugReportUrl
|
||||
import io.element.android.features.enterprise.api.EnterpriseService
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
@@ -31,8 +32,9 @@ class FakeEnterpriseService(
|
||||
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
|
||||
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
|
||||
private val getNoisyNotificationChannelIdResult: (SessionId?) -> String? = { lambdaError() },
|
||||
private val tweakMasUrlResult: (String, String) -> String = { _, _ -> lambdaError() },
|
||||
private val tweakMasUrlResult: (String, String, GetUrlResolver) -> String = { _, _, _ -> lambdaError() },
|
||||
private val overrideWellKnownResult: () -> ElementWellKnown? = { lambdaError() },
|
||||
private val essConfigEndpointUrlResult: (String) -> String = { lambdaError() },
|
||||
) : EnterpriseService {
|
||||
private val brandColorState = MutableStateFlow(initialBrandColor)
|
||||
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
|
||||
@@ -41,8 +43,8 @@ class FakeEnterpriseService(
|
||||
isEnterpriseUserResult(sessionId)
|
||||
}
|
||||
|
||||
override suspend fun tweakMasUrl(url: String, homeserver: String): String = simulateLongTask {
|
||||
tweakMasUrlResult(url, homeserver)
|
||||
override suspend fun tweakMasUrl(url: String, homeserver: String, getUrlResolver: GetUrlResolver): String = simulateLongTask {
|
||||
tweakMasUrlResult(url, homeserver, getUrlResolver)
|
||||
}
|
||||
|
||||
override fun defaultHomeserverList(): List<String> {
|
||||
@@ -85,4 +87,8 @@ class FakeEnterpriseService(
|
||||
override fun overriddenElementWellKnown(): ElementWellKnown? {
|
||||
return overrideWellKnownResult()
|
||||
}
|
||||
|
||||
override fun essConfigEndpointUrl(domain: String): String {
|
||||
return essConfigEndpointUrlResult(domain)
|
||||
}
|
||||
}
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.enterprise.test.remoteconfig
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfig
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
|
||||
class FakeRemoteEnterpriseConfigProvider(
|
||||
private val getResult: (SessionId) -> WellknownRetrieverResult<RemoteEnterpriseConfig> = { WellknownRetrieverResult.NotFound }
|
||||
) : RemoteEnterpriseConfigProvider {
|
||||
override suspend fun get(sessionId: SessionId): WellknownRetrieverResult<RemoteEnterpriseConfig> {
|
||||
return getResult(sessionId)
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.enterprise.test.remoteconfig
|
||||
|
||||
import io.element.android.features.enterprise.api.remoteconfig.RemoteEnterpriseConfigProvider
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
|
||||
class FakeRemoteEnterpriseConfigProviderFactory(
|
||||
private val remoteEnterpriseConfigProvider: RemoteEnterpriseConfigProvider = FakeRemoteEnterpriseConfigProvider(),
|
||||
) : RemoteEnterpriseConfigProvider.Factory {
|
||||
override fun create(getUrlResolver: GetUrlResolver): RemoteEnterpriseConfigProvider = remoteEnterpriseConfigProvider
|
||||
}
|
||||
+13
-8
@@ -12,10 +12,12 @@ import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||
import io.element.android.features.login.impl.changeserver.AccountProviderAccessException
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetrieverFactory
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER
|
||||
import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_2
|
||||
import io.element.android.libraries.matrix.test.AN_ACCOUNT_PROVIDER_URL
|
||||
import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -156,15 +158,18 @@ class DefaultAccountProviderAccessControlTest {
|
||||
isAllowedToConnectToHomeserverResult = { isAllowedToConnectToHomeserver },
|
||||
defaultHomeserverListResult = { allowedAccountProviders },
|
||||
),
|
||||
wellknownRetriever = FakeWellknownRetriever(
|
||||
getElementWellKnownResult = {
|
||||
if (elementWellKnown == null) {
|
||||
WellknownRetrieverResult.NotFound
|
||||
} else {
|
||||
WellknownRetrieverResult.Success(elementWellKnown)
|
||||
}
|
||||
},
|
||||
wellknownRetrieverFactory = FakeWellknownRetrieverFactory(
|
||||
wellknownRetriever = FakeWellknownRetriever(
|
||||
getElementWellKnownResult = { _, _ ->
|
||||
if (elementWellKnown == null) {
|
||||
WellknownRetrieverResult.NotFound
|
||||
} else {
|
||||
WellknownRetrieverResult.Success(elementWellKnown)
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(),
|
||||
)
|
||||
|
||||
private fun DefaultAccountProviderAccessControl.expectNeedElementProException() {
|
||||
|
||||
+8
-9
@@ -17,18 +17,19 @@ import io.element.android.features.login.impl.accountprovider.AccountProviderDat
|
||||
import io.element.android.features.login.impl.error.ChangeServerError
|
||||
import io.element.android.features.login.impl.localnetwork.LocalNetworkPermissionGate
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetrieverFactory
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.core.uri.ensureProtocol
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||
import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.test.auth.aMatrixHomeServerDetails
|
||||
import io.element.android.libraries.permissions.api.localnetwork.LocalNetworkPermissionDialog
|
||||
import io.element.android.libraries.permissions.test.FakeLocalNetworkPermissionAdvisor
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenter
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
@@ -158,7 +159,8 @@ class ChangeServerPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - change server element pro required error`() = runTest {
|
||||
val getElementWellKnownResult = lambdaRecorder<String, WellknownRetrieverResult<ElementWellKnown>> {
|
||||
val getElementWellKnownResult = lambdaRecorder { homeserver: String, _: EnterpriseRemoteConfigSource ->
|
||||
assertThat(homeserver).isEqualTo(A_HOMESERVER_URL)
|
||||
WellknownRetrieverResult.Success(
|
||||
anElementWellKnown(
|
||||
enforceElementPro = true,
|
||||
@@ -174,8 +176,6 @@ class ChangeServerPresenterTest {
|
||||
assertThat(initialState.changeServerAction).isEqualTo(AsyncData.Uninitialized)
|
||||
val anAccountProvider = AccountProvider(url = A_HOMESERVER_URL)
|
||||
initialState.eventSink.invoke(ChangeServerEvents.ChangeServer(anAccountProvider))
|
||||
val loadingState = awaitItem()
|
||||
assertThat(loadingState.changeServerAction).isInstanceOf(AsyncData.Loading::class.java)
|
||||
val failureState = awaitItem()
|
||||
assertThat(
|
||||
(failureState.changeServerAction.errorOrNull() as ChangeServerError.NeedElementPro).unauthorisedAccountProviderTitle
|
||||
@@ -183,9 +183,7 @@ class ChangeServerPresenterTest {
|
||||
assertThat(
|
||||
(failureState.changeServerAction.errorOrNull() as ChangeServerError.NeedElementPro).applicationId
|
||||
).isEqualTo("io.element.enterprise")
|
||||
getElementWellKnownResult.assertions()
|
||||
.isCalledOnce()
|
||||
.with(value(A_HOMESERVER_URL.ensureProtocol()))
|
||||
getElementWellKnownResult.assertions().isCalledOnce()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +267,8 @@ class ChangeServerPresenterTest {
|
||||
accountProviderDataSource = accountProviderDataSource,
|
||||
defaultAccountProviderAccessControl = DefaultAccountProviderAccessControl(
|
||||
enterpriseService = enterpriseService,
|
||||
wellknownRetriever = wellknownRetriever,
|
||||
wellknownRetrieverFactory = FakeWellknownRetrieverFactory(wellknownRetriever = wellknownRetriever),
|
||||
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(),
|
||||
),
|
||||
localNetworkPermissionGate = LocalNetworkPermissionGate(
|
||||
advisor = localNetworkPermissionAdvisor,
|
||||
|
||||
+10
-4
@@ -20,6 +20,7 @@ import io.element.android.features.login.impl.login.LoginModePresenter
|
||||
import io.element.android.features.login.impl.web.FakeWebClientUrlForAuthenticationRetriever
|
||||
import io.element.android.features.login.impl.web.WebClientUrlForAuthenticationRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetriever
|
||||
import io.element.android.features.wellknown.test.FakeWellknownRetrieverFactory
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
@@ -30,11 +31,15 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL_2
|
||||
import io.element.android.libraries.matrix.test.A_LOGIN_HINT
|
||||
import io.element.android.libraries.matrix.test.FakeTemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||
import io.element.android.libraries.oauth.api.OAuthActionFlow
|
||||
import io.element.android.libraries.oauth.test.customtab.FakeOAuthActionFlow
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.api.localnetwork.LocalNetworkPermissionAdvisor
|
||||
import io.element.android.libraries.permissions.test.FakeLocalNetworkPermissionAdvisor
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||
import io.element.android.libraries.sessionstorage.test.aSessionData
|
||||
@@ -304,7 +309,8 @@ private fun createPresenter(
|
||||
enterpriseService = enterpriseService,
|
||||
defaultAccountProviderAccessControl = DefaultAccountProviderAccessControl(
|
||||
enterpriseService = enterpriseService,
|
||||
wellknownRetriever = wellknownRetriever,
|
||||
wellknownRetrieverFactory = FakeWellknownRetrieverFactory(wellknownRetriever = wellknownRetriever),
|
||||
temporaryMatrixClientFactory = FakeTemporaryMatrixClientFactory(),
|
||||
),
|
||||
rageshakeFeatureAvailability = rageshakeFeatureAvailability,
|
||||
loginModePresenter = loginModePresenter,
|
||||
@@ -318,9 +324,9 @@ fun createLoginModePresenter(
|
||||
authenticationService: MatrixAuthenticationService = FakeMatrixAuthenticationService(),
|
||||
webClientUrlForAuthenticationRetriever: WebClientUrlForAuthenticationRetriever = FakeWebClientUrlForAuthenticationRetriever(),
|
||||
localNetworkPermissionAdvisor: LocalNetworkPermissionAdvisor =
|
||||
io.element.android.libraries.permissions.test.FakeLocalNetworkPermissionAdvisor(),
|
||||
permissionsPresenterFactory: io.element.android.libraries.permissions.api.PermissionsPresenter.Factory =
|
||||
io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory(),
|
||||
FakeLocalNetworkPermissionAdvisor(),
|
||||
permissionsPresenterFactory: PermissionsPresenter.Factory =
|
||||
FakePermissionsPresenterFactory(),
|
||||
): LoginModePresenter = LoginModePresenter(
|
||||
oAuthActionFlow = oAuthActionFlow,
|
||||
authenticationService = authenticationService,
|
||||
|
||||
+2
-2
@@ -52,7 +52,7 @@ fun TestScope.createRustMatrixClientFactory(
|
||||
),
|
||||
clientBuilderProvider: ClientBuilderProvider = FakeClientBuilderProvider(),
|
||||
workManagerScheduler: FakeWorkManagerScheduler = FakeWorkManagerScheduler(),
|
||||
contentScannerUrlProvider: ContentScannerUrlProvider = { Result.success(null) },
|
||||
contentScannerUrlProviderFactory: ContentScannerUrlProvider.Factory = { ContentScannerUrlProvider { Result.success(null) } },
|
||||
) = RustMatrixClientFactory(
|
||||
cacheDirectory = cacheDirectory,
|
||||
appCoroutineScope = backgroundScope,
|
||||
@@ -67,5 +67,5 @@ fun TestScope.createRustMatrixClientFactory(
|
||||
clientBuilderProvider = clientBuilderProvider,
|
||||
sqliteStoreBuilderProvider = FakeSqliteStoreBuilderProvider(),
|
||||
workManagerScheduler = workManagerScheduler,
|
||||
contentScannerUrlProvider = contentScannerUrlProvider,
|
||||
contentScannerUrlProviderFactory = contentScannerUrlProviderFactory,
|
||||
)
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.test
|
||||
|
||||
import io.element.android.libraries.matrix.api.TemporaryMatrixClient
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
|
||||
class FakeTemporaryMatrixClient(
|
||||
private val getUrlResult: (String) -> Result<ByteArray> = { lambdaError() },
|
||||
private val closeLambda: () -> Unit = {},
|
||||
) : TemporaryMatrixClient {
|
||||
override suspend fun getUrl(url: String): Result<ByteArray> = getUrlResult(url)
|
||||
|
||||
override fun close() = closeLambda()
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.test
|
||||
|
||||
import io.element.android.libraries.matrix.api.TemporaryMatrixClientFactory
|
||||
import io.element.android.libraries.matrix.api.TemporaryMatrixClient
|
||||
|
||||
class FakeTemporaryMatrixClientFactory(
|
||||
private val createResult: (String) -> Result<TemporaryMatrixClient> = { Result.success(FakeTemporaryMatrixClient()) },
|
||||
) : TemporaryMatrixClientFactory {
|
||||
override suspend fun createTemporaryMatrixClient(homeServerUrl: String): Result<TemporaryMatrixClient> = createResult(homeServerUrl)
|
||||
}
|
||||
+14
@@ -148,11 +148,25 @@ class DefaultWellKnownStoreTest {
|
||||
assertThat(result).isEqualTo(WellknownRetrieverResult.Success(wellKnown.map()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `prefix is used`() = runTest {
|
||||
val prefix = "test-prefix"
|
||||
val clock = FakeSystemClock(epochMillisResult = A_FAKE_TIMESTAMP)
|
||||
val cacheStore = InMemoryCacheStore(
|
||||
initialData = mapOf("$prefix-$A_DOMAIN" to CacheData("{}", A_FAKE_TIMESTAMP))
|
||||
)
|
||||
val sut = createDefaultWellKnownStore(prefix = prefix, cacheStore = cacheStore, systemClock = clock)
|
||||
|
||||
assertThat(sut.get(A_DOMAIN)).isInstanceOf(WellknownRetrieverResult.Success::class.java)
|
||||
}
|
||||
|
||||
private fun createDefaultWellKnownStore(
|
||||
prefix: String? = null,
|
||||
cacheStore: InMemoryCacheStore = InMemoryCacheStore(),
|
||||
systemClock: FakeSystemClock = FakeSystemClock(),
|
||||
elementWellKnownParser: ElementWellKnownParser = DefaultElementWellKnownParser(jsonProvider),
|
||||
) = DefaultWellKnownStore(
|
||||
prefix = prefix,
|
||||
cacheStore = cacheStore,
|
||||
systemClock = systemClock,
|
||||
elementWellKnownParser = elementWellKnownParser,
|
||||
|
||||
+61
-240
@@ -14,275 +14,93 @@ import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.enterprise.test.FakeEnterpriseService
|
||||
import io.element.android.features.wellknown.test.FakeElementWellknownStore
|
||||
import io.element.android.features.wellknown.test.anElementWellKnown
|
||||
import io.element.android.libraries.androidutils.json.DefaultJsonProvider
|
||||
import io.element.android.libraries.androidutils.json.JsonProvider
|
||||
import io.element.android.libraries.network.RetrofitFactory
|
||||
import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
import io.element.android.libraries.matrix.api.exception.ClientException
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnownParser
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.Call
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.ResponseBody.Companion.toResponseBody
|
||||
import okio.IOException
|
||||
import org.junit.Test
|
||||
import java.net.PortUnreachableException
|
||||
|
||||
class DefaultWellknownRetrieverTest {
|
||||
@Test
|
||||
fun `get empty element wellknown`() = runTest {
|
||||
val mockCall = mockCall(defaultResponse(body = "{}"))
|
||||
fun `get element wellknown calls resolver and parser`() = runTest {
|
||||
val parser = lambdaRecorder<String, Result<ElementWellKnown>> { Result.success(anElementWellKnown()) }
|
||||
val resolver = SpyGetUrlResolver { Result.success(WELLKNOWN_CONTENT.toByteArray()) }
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = { mockCall },
|
||||
elementWellKnownParser = parser,
|
||||
urlResolver = resolver,
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
ElementWellKnown(
|
||||
registrationHelperUrl = null,
|
||||
enforceElementPro = null,
|
||||
rageshakeUrl = null,
|
||||
brandColor = null,
|
||||
notificationSound = null,
|
||||
identityProviderAppScheme = null,
|
||||
customRecoveryPassphrase = null,
|
||||
contentScannerUrl = null,
|
||||
forceDisableE2EE = null,
|
||||
)
|
||||
)
|
||||
)
|
||||
verify(exactly = 1) { mockCall.enqueue(any()) }
|
||||
|
||||
sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT)
|
||||
|
||||
resolver.assertions().isCalledOnce().with(value(WELLKNOWN_URL))
|
||||
parser.assertions().isCalledOnce().with(value(WELLKNOWN_CONTENT))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown with full content`() = runTest {
|
||||
fun `get element wellknown parser error`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = { mockCall(defaultResponse()) }
|
||||
elementWellKnownParser = { Result.failure(IllegalStateException("Invalid JSON")) },
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
ElementWellKnown(
|
||||
registrationHelperUrl = "a_registration_url",
|
||||
enforceElementPro = true,
|
||||
rageshakeUrl = "a_rageshake_url",
|
||||
brandColor = "#FF0000",
|
||||
notificationSound = "a_notification_sound.flac",
|
||||
identityProviderAppScheme = "an_app_scheme",
|
||||
customRecoveryPassphrase = null,
|
||||
contentScannerUrl = "https://content-scanner.example.com",
|
||||
forceDisableE2EE = false,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown with unknown key`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = {
|
||||
mockCall(defaultResponse(body = """{
|
||||
"registration_helper_url": "a_registration_url",
|
||||
"enforce_element_pro": true,
|
||||
"rageshake_url": "a_rageshake_url",
|
||||
// Note the trailing comma, and the comment!
|
||||
"other": true,
|
||||
}""".trimIndent()))
|
||||
}
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
ElementWellKnown(
|
||||
registrationHelperUrl = "a_registration_url",
|
||||
enforceElementPro = true,
|
||||
rageshakeUrl = "a_rageshake_url",
|
||||
brandColor = null,
|
||||
notificationSound = null,
|
||||
identityProviderAppScheme = null,
|
||||
contentScannerUrl = null,
|
||||
customRecoveryPassphrase = null,
|
||||
forceDisableE2EE = null,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown with custom recovery passphrase settings`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = {
|
||||
mockCall(defaultResponse(body = """{
|
||||
"custom_recovery_passphrase": {
|
||||
"min_character_count": 8
|
||||
}
|
||||
}""".trimIndent()))
|
||||
}
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
anElementWellKnown(
|
||||
customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 8)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown with custom recovery passphrase settings missing min character count floors to 1`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = {
|
||||
mockCall(defaultResponse(body = """{
|
||||
"custom_recovery_passphrase": {}
|
||||
}""".trimIndent()))
|
||||
}
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
anElementWellKnown(
|
||||
customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown with zero min character count floors to 1`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = {
|
||||
mockCall(
|
||||
defaultResponse(
|
||||
body = """{
|
||||
"custom_recovery_passphrase": {
|
||||
"min_character_count": 0
|
||||
}
|
||||
}""".trimIndent()
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
anElementWellKnown(
|
||||
customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown with negative min character count floors to 1`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = {
|
||||
mockCall(
|
||||
defaultResponse(
|
||||
body = """{
|
||||
"custom_recovery_passphrase": {
|
||||
"min_character_count": -5
|
||||
}
|
||||
}""".trimIndent()
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(
|
||||
anElementWellKnown(
|
||||
customRecoveryPassphrase = CustomRecoveryPassphrase(minCharacterCount = 1)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown json error`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = { mockCall(defaultResponse(status = 500)) }
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown network error`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = { mockCall(error = PortUnreachableException()) }
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
val resolver = SpyGetUrlResolver { Result.failure(IllegalStateException("Network error")) }
|
||||
val sut = createDefaultWellknownRetriever(urlResolver = resolver)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown 404 http error counts as not found`() = runTest {
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = { mockCall(defaultResponse(status = 404)) }
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isInstanceOf(WellknownRetrieverResult.NotFound::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown hitting cache containing invalid json`() = runTest {
|
||||
val cacheStore = FakeElementWellknownStore(
|
||||
initialData = mapOf(
|
||||
WELLKNOWN_URL to WellknownRetrieverResult.Error(IllegalStateException("Invalid JSON"))
|
||||
)
|
||||
)
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = { mockCall(defaultResponse(body = "invalid json")) },
|
||||
cacheStore = cacheStore,
|
||||
jsonProvider = JsonProvider { error("Failed to parse JSON") }
|
||||
)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isInstanceOf(WellknownRetrieverResult.Error::class.java)
|
||||
// Ensure that the cache is deleted after the failure to parse it
|
||||
assertThat(cacheStore.get(WELLKNOWN_URL)).isEqualTo(WellknownRetrieverResult.NotFound)
|
||||
val resolver = SpyGetUrlResolver { Result.failure(ClientException.Generic("Http error: 404", null)) }
|
||||
val sut = createDefaultWellknownRetriever(urlResolver = resolver)
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT))
|
||||
.isInstanceOf(WellknownRetrieverResult.NotFound::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `get element wellknown was overridden`() = runTest {
|
||||
val getLambda = lambdaRecorder<Request, Call> { mockCall() }
|
||||
val wellKnown = anElementWellKnown()
|
||||
|
||||
val resolver = SpyGetUrlResolver { Result.success(WELLKNOWN_CONTENT.toByteArray()) }
|
||||
|
||||
val sut = createDefaultWellknownRetriever(
|
||||
callFactory = getLambda,
|
||||
enterpriseService = FakeEnterpriseService(
|
||||
overrideWellKnownResult = { wellKnown }
|
||||
)
|
||||
overrideWellKnownResult = { wellKnown },
|
||||
),
|
||||
urlResolver = resolver,
|
||||
)
|
||||
|
||||
// The overridden value is returned
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo(
|
||||
assertThat(sut.getElementWellKnown(WELLKNOWN_URL, EnterpriseRemoteConfigSource.WELLKNOWN_ENDPOINT)).isEqualTo(
|
||||
WellknownRetrieverResult.Success(wellKnown)
|
||||
)
|
||||
|
||||
// And the endpoint is never hit
|
||||
getLambda.assertions().isNeverCalled()
|
||||
resolver.assertions().isNeverCalled()
|
||||
}
|
||||
|
||||
private fun defaultResponse(
|
||||
body: String = WELLKNOWN_CONTENT,
|
||||
status: Int = 200,
|
||||
) = Response.Builder()
|
||||
.code(status)
|
||||
.message("OK")
|
||||
.protocol(okhttp3.Protocol.HTTP_1_1)
|
||||
.request(Request.Builder().url(WELLKNOWN_URL).build())
|
||||
.body(body.toByteArray().toResponseBody())
|
||||
.build()
|
||||
|
||||
private fun createDefaultWellknownRetriever(
|
||||
callFactory: Call.Factory = Call.Factory { _: Request -> mockCall(defaultResponse()) },
|
||||
private fun TestScope.createDefaultWellknownRetriever(
|
||||
cacheStore: FakeElementWellknownStore = FakeElementWellknownStore(),
|
||||
jsonProvider: JsonProvider = DefaultJsonProvider(),
|
||||
elementWellKnownParser: ElementWellKnownParser = { Result.success(expectedElementWellKnown) },
|
||||
enterpriseService: FakeEnterpriseService = FakeEnterpriseService(overrideWellKnownResult = { null }),
|
||||
urlResolver: GetUrlResolver = SpyGetUrlResolver { Result.success(WELLKNOWN_CONTENT.toByteArray()) },
|
||||
) = DefaultWellknownRetriever(
|
||||
retrofitFactory = RetrofitFactory(
|
||||
callFactory = { callFactory },
|
||||
json = { jsonProvider }
|
||||
),
|
||||
jsonProvider = jsonProvider,
|
||||
elementWellknownStore = cacheStore,
|
||||
elementWellknownStoreFactory = { cacheStore },
|
||||
enterpriseService = enterpriseService,
|
||||
elementWellKnownParser = elementWellKnownParser,
|
||||
getUrlResolver = urlResolver,
|
||||
coroutineScope = backgroundScope,
|
||||
)
|
||||
|
||||
companion object {
|
||||
@@ -297,24 +115,27 @@ class DefaultWellknownRetrieverTest {
|
||||
"content_scanner_url": "https://content-scanner.example.com",
|
||||
"force_disable_e2ee": false
|
||||
}"""
|
||||
|
||||
private val expectedElementWellKnown = ElementWellKnown(
|
||||
registrationHelperUrl = "a_registration_url",
|
||||
enforceElementPro = true,
|
||||
rageshakeUrl = "a_rageshake_url",
|
||||
brandColor = "#FF0000",
|
||||
notificationSound = "a_notification_sound.flac",
|
||||
identityProviderAppScheme = "an_app_scheme",
|
||||
contentScannerUrl = "https://content-scanner.example.com",
|
||||
customRecoveryPassphrase = null,
|
||||
forceDisableE2EE = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mockCall(
|
||||
response: Response? = null,
|
||||
error: IOException? = null,
|
||||
): Call = mockk<Call> {
|
||||
if (error != null) {
|
||||
every { enqueue(any()) } answers {
|
||||
val callback = firstArg<okhttp3.Callback>()
|
||||
callback.onFailure(this@mockk, error)
|
||||
}
|
||||
} else if (response != null) {
|
||||
every { enqueue(any()) } answers {
|
||||
val callback = firstArg<okhttp3.Callback>()
|
||||
callback.onResponse(this@mockk, response)
|
||||
}
|
||||
} else {
|
||||
error("Either response or error must be provided")
|
||||
private class SpyGetUrlResolver(lambda: (String) -> Result<ByteArray>) : GetUrlResolver {
|
||||
private val spy = lambdaRecorder<String, Result<ByteArray>> { lambda(it) }
|
||||
|
||||
override suspend fun getUrl(url: String): Result<ByteArray> {
|
||||
return spy(url)
|
||||
}
|
||||
|
||||
fun assertions() = spy.assertions()
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ android {
|
||||
dependencies {
|
||||
implementation(libs.serialization.json)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.wellknown.api)
|
||||
implementation(projects.libraries.wellknown.impl)
|
||||
implementation(projects.tests.testutils)
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Element Creations Ltd.
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.SessionWellknownRetriever
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
|
||||
class FakeSessionWellknownRetriever(
|
||||
private val getElementWellKnownResult: () -> WellknownRetrieverResult<ElementWellKnown> = { WellknownRetrieverResult.NotFound },
|
||||
) : SessionWellknownRetriever {
|
||||
override suspend fun getElementWellKnown(): WellknownRetrieverResult<ElementWellKnown> = simulateLongTask {
|
||||
getElementWellKnownResult()
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -9,14 +9,16 @@
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.wellknown.api.ElementWellKnown
|
||||
import io.element.android.libraries.wellknown.api.EnterpriseRemoteConfigSource
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetrieverResult
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
|
||||
class FakeWellknownRetriever(
|
||||
private val getElementWellKnownResult: (String) -> WellknownRetrieverResult<ElementWellKnown> = { WellknownRetrieverResult.NotFound },
|
||||
private val getElementWellKnownResult: (String, EnterpriseRemoteConfigSource) -> WellknownRetrieverResult<ElementWellKnown> = { _, _ ->
|
||||
WellknownRetrieverResult.NotFound
|
||||
},
|
||||
) : WellknownRetriever {
|
||||
override suspend fun getElementWellKnown(baseUrl: String): WellknownRetrieverResult<ElementWellKnown> = simulateLongTask {
|
||||
getElementWellKnownResult(baseUrl)
|
||||
override suspend fun getElementWellKnown(host: String, source: EnterpriseRemoteConfigSource): WellknownRetrieverResult<ElementWellKnown> {
|
||||
return getElementWellKnownResult(host, source)
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.wellknown.test
|
||||
|
||||
import io.element.android.libraries.matrix.api.GetUrlResolver
|
||||
import io.element.android.libraries.wellknown.api.WellknownRetriever
|
||||
|
||||
class FakeWellknownRetrieverFactory(
|
||||
private val wellknownRetriever: WellknownRetriever = FakeWellknownRetriever(),
|
||||
) : WellknownRetriever.Factory {
|
||||
override fun create(getUrlResolver: GetUrlResolver): WellknownRetriever = wellknownRetriever
|
||||
}
|
||||
Reference in New Issue
Block a user