adding happy path tests for the direct login use case

This commit is contained in:
Adam Brown 2022-03-24 15:41:53 +00:00
parent 88197991e1
commit 230c37597c
7 changed files with 169 additions and 15 deletions

View File

@ -21,3 +21,11 @@ fun <A> Result<A>.foldToCallback(callback: MatrixCallback<A>): Unit = fold(
{ callback.onSuccess(it) },
{ callback.onFailure(it) }
)
@Suppress("UNCHECKED_CAST") // We're casting null failure results to R
inline fun <T, R> Result<T>.andThen(block: (T) -> Result<R>): Result<R> {
return when (val result = getOrNull()) {
null -> this as Result<R>
else -> block(result)
}
}

View File

@ -16,7 +16,6 @@
package im.vector.app.features.onboarding
import android.net.Uri
import im.vector.app.R
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.onboarding.OnboardingAction.LoginOrRegister
@ -25,11 +24,13 @@ import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.internal.extensions.andThen
import javax.inject.Inject
class DirectLoginUseCase @Inject constructor(
private val authenticationService: AuthenticationService,
private val stringProvider: StringProvider,
private val uriFactory: UriFactory
) {
suspend fun execute(action: LoginOrRegister, homeServerConnectionConfig: HomeServerConnectionConfig?): Result<Session> {
@ -69,23 +70,15 @@ class DirectLoginUseCase @Inject constructor(
}
private fun HomeServerConnectionConfig.updateWith(wellKnownPrompt: WellknownResult.Prompt) = copy(
homeServerUriBase = Uri.parse(wellKnownPrompt.homeServerUrl),
identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
homeServerUriBase = uriFactory.parse(wellKnownPrompt.homeServerUrl),
identityServerUri = wellKnownPrompt.identityServerUrl?.let { uriFactory.parse(it) }
)
private fun fallbackConfig(action: LoginOrRegister, wellKnownPrompt: WellknownResult.Prompt) = HomeServerConnectionConfig(
homeServerUri = Uri.parse("https://${action.username.getDomain()}"),
homeServerUriBase = Uri.parse(wellKnownPrompt.homeServerUrl),
identityServerUri = wellKnownPrompt.identityServerUrl?.let { Uri.parse(it) }
homeServerUri = uriFactory.parse("https://${action.username.getDomain()}"),
homeServerUriBase = uriFactory.parse(wellKnownPrompt.homeServerUrl),
identityServerUri = wellKnownPrompt.identityServerUrl?.let { uriFactory.parse(it) }
)
private fun onWellKnownError() = Result.failure<Session>(Exception(stringProvider.getString(R.string.autodiscover_well_known_error)))
}
@Suppress("UNCHECKED_CAST") // We're casting null failure results to R
private inline fun <T, R> Result<T>.andThen(block: (T) -> Result<R>): Result<R> {
return when (val result = getOrNull()) {
null -> this as Result<R>
else -> block(result)
}
}

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 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 im.vector.app.features.onboarding
import android.net.Uri
import javax.inject.Inject
class UriFactory @Inject constructor() {
fun parse(value: String): Uri {
return Uri.parse(value)
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022 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 im.vector.app.features.onboarding
import im.vector.app.test.fakes.FakeAuthenticationService
import im.vector.app.test.fakes.FakeSession
import im.vector.app.test.fakes.FakeStringProvider
import im.vector.app.test.fakes.FakeUri
import im.vector.app.test.fakes.FakeUriFactory
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
import org.matrix.android.sdk.api.MatrixPatterns.getDomain
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.data.WellKnown
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
private val A_LOGIN_OR_REGISTER_ACTION = OnboardingAction.LoginOrRegister("@a-user:id.org", "a-password", "a-device-name")
private val A_WELLKNOWN_SUCCESS_RESULT = WellknownResult.Prompt("https://homeserverurl.com", identityServerUrl = null, WellKnown())
private val A_WELLKNOWN_FAILED_WITH_CONTENT_RESULT = WellknownResult.FailPrompt("https://homeserverurl.com", WellKnown())
private val NO_HOMESERVER_CONFIG: HomeServerConnectionConfig? = null
private val A_FALLBACK_CONFIG: HomeServerConnectionConfig = HomeServerConnectionConfig(
homeServerUri = FakeUri("https://${A_LOGIN_OR_REGISTER_ACTION.username.getDomain()}").instance,
homeServerUriBase = FakeUri(A_WELLKNOWN_SUCCESS_RESULT.homeServerUrl).instance,
identityServerUri = null
)
class DirectLoginUseCaseTest {
private val fakeAuthenticationService = FakeAuthenticationService()
private val fakeStringProvider = FakeStringProvider()
private val fakeSession = FakeSession()
private val useCase = DirectLoginUseCase(fakeAuthenticationService, fakeStringProvider.instance, FakeUriFactory().instance)
@Test
fun `when logging in directly, then returns success with direct session result`() = runTest {
fakeAuthenticationService.givenWellKnown(A_LOGIN_OR_REGISTER_ACTION.username, config = NO_HOMESERVER_CONFIG, result = A_WELLKNOWN_SUCCESS_RESULT)
val (username, password, initialDeviceName) = A_LOGIN_OR_REGISTER_ACTION
fakeAuthenticationService.givenDirectAuthentication(A_FALLBACK_CONFIG, username, password, initialDeviceName, result = fakeSession)
val result = useCase.execute(A_LOGIN_OR_REGISTER_ACTION, homeServerConnectionConfig = NO_HOMESERVER_CONFIG)
result shouldBeEqualTo Result.success(fakeSession)
}
@Test
fun `given wellknown fails but has content, when logging in directly, then returns success with direct session result`() = runTest {
fakeAuthenticationService.givenWellKnown(A_LOGIN_OR_REGISTER_ACTION.username, config = NO_HOMESERVER_CONFIG, result = A_WELLKNOWN_FAILED_WITH_CONTENT_RESULT)
val (username, password, initialDeviceName) = A_LOGIN_OR_REGISTER_ACTION
fakeAuthenticationService.givenDirectAuthentication(A_FALLBACK_CONFIG, username, password, initialDeviceName, result = fakeSession)
val result = useCase.execute(A_LOGIN_OR_REGISTER_ACTION, homeServerConnectionConfig = NO_HOMESERVER_CONFIG)
result shouldBeEqualTo Result.success(fakeSession)
}
}

View File

@ -16,11 +16,14 @@
package im.vector.app.test.fakes
import io.mockk.coEvery
import io.mockk.coJustRun
import io.mockk.every
import io.mockk.mockk
import org.matrix.android.sdk.api.auth.AuthenticationService
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
import org.matrix.android.sdk.api.auth.registration.RegistrationWizard
import org.matrix.android.sdk.api.auth.wellknown.WellknownResult
class FakeAuthenticationService : AuthenticationService by mockk() {
@ -35,4 +38,12 @@ class FakeAuthenticationService : AuthenticationService by mockk() {
fun expectReset() {
coJustRun { reset() }
}
fun givenWellKnown(matrixId: String, config: HomeServerConnectionConfig?, result: WellknownResult) {
coEvery { getWellKnownData(matrixId, config) } returns result
}
fun givenDirectAuthentication(config: HomeServerConnectionConfig, matrixId: String, password: String, deviceName: String, result: FakeSession) {
coEvery { directAuthentication(config, matrixId, password, deviceName) } returns result
}
}

View File

@ -20,9 +20,14 @@ import android.net.Uri
import io.mockk.every
import io.mockk.mockk
class FakeUri {
class FakeUri(contentEquals: String? = null) {
val instance = mockk<Uri>()
init {
contentEquals?.let { givenEquals(it) }
}
fun givenNonHierarchical() {
givenContent(schema = "mail", path = null)
}
@ -31,4 +36,12 @@ class FakeUri {
every { instance.scheme } returns schema
every { instance.path } returns path
}
@Suppress("ReplaceCallWithBinaryOperator")
fun givenEquals(content: String) {
every { instance.equals(any()) } answers {
it.invocation.args.first() == content
}
every { instance.hashCode() } answers { content.hashCode() }
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2022 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 im.vector.app.test.fakes
import im.vector.app.features.onboarding.UriFactory
import io.mockk.every
import io.mockk.mockk
class FakeUriFactory {
val instance = mockk<UriFactory>().also {
every { it.parse(any()) } answers {
val input = it.invocation.args.first() as String
FakeUri().also { it.givenEquals(input) }.instance
}
}
}