Add tests.
This commit is contained in:
parent
319d74b12b
commit
563f8d3403
7 changed files with 180 additions and 77 deletions
|
|
@ -59,6 +59,7 @@ dependencies {
|
|||
testImplementation(libs.test.truth)
|
||||
testImplementation(libs.test.turbine)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
testImplementation(projects.tests.testutils)
|
||||
|
||||
androidTestImplementation(libs.test.junitext)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,11 @@ class DefaultHomeserverResolver @Inject constructor(
|
|||
emit(Async.Uninitialized)
|
||||
// Debounce
|
||||
delay(300)
|
||||
val clean = userInput.trim()
|
||||
if (clean.length < 4) return@flow
|
||||
val trimmedUserInput = userInput.trim()
|
||||
if (trimmedUserInput.length < 4) return@flow
|
||||
emit(Async.Loading())
|
||||
val list = getUrlCandidate(clean.ensureProtocol().removeSuffix("/"))
|
||||
val candidateBase = trimmedUserInput.ensureProtocol().removeSuffix("/")
|
||||
val list = getUrlCandidates(candidateBase)
|
||||
val currentList = Collections.synchronizedList(mutableListOf<HomeserverData>())
|
||||
// Run all the requests in parallel
|
||||
withContext(dispatchers.io) {
|
||||
|
|
@ -77,14 +78,14 @@ class DefaultHomeserverResolver @Inject constructor(
|
|||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
// If list is empty, and the user as entered an URL, do not block the user.
|
||||
// If list is empty, and the user has entered an URL, do not block the user.
|
||||
if (currentList.isEmpty()) {
|
||||
if (userInput.isValidUrl()) {
|
||||
if (trimmedUserInput.isValidUrl()) {
|
||||
emit(
|
||||
Async.Success(
|
||||
listOf(
|
||||
HomeserverData(
|
||||
homeserverUrl = userInput,
|
||||
homeserverUrl = trimmedUserInput,
|
||||
isWellknownValid = false,
|
||||
supportSlidingSync = false,
|
||||
)
|
||||
|
|
@ -97,7 +98,7 @@ class DefaultHomeserverResolver @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getUrlCandidate(data: String): List<String> {
|
||||
private fun getUrlCandidates(data: String): List<String> {
|
||||
return buildList {
|
||||
if (data.contains(".")) {
|
||||
// TLD detected?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2023 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.features.login.impl.changeaccountprovider.form.network
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.network.RetrofitFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultWellknownRequest @Inject constructor(
|
||||
private val retrofitFactory: RetrofitFactory,
|
||||
) : WellknownRequest {
|
||||
/**
|
||||
* Return the WellKnown data, if found.
|
||||
* @param baseUrl for instance https://matrix.org
|
||||
*/
|
||||
override suspend fun execute(baseUrl: String): WellKnown {
|
||||
val wellknownApi = retrofitFactory.create(baseUrl)
|
||||
.create(WellknownAPI::class.java)
|
||||
return wellknownApi.getWellKnown()
|
||||
}
|
||||
}
|
||||
|
|
@ -15,19 +15,10 @@
|
|||
*/
|
||||
package io.element.android.features.login.impl.changeaccountprovider.form.network
|
||||
|
||||
import io.element.android.libraries.network.RetrofitFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
class WellknownRequest @Inject constructor(
|
||||
private val retrofitFactory: RetrofitFactory,
|
||||
) {
|
||||
interface WellknownRequest {
|
||||
/**
|
||||
* Return the WellKnown data, if found.
|
||||
* Return the WellKnown data, or throw an error if not found.
|
||||
* @param baseUrl for instance https://matrix.org
|
||||
*/
|
||||
suspend fun execute(baseUrl: String): WellKnown {
|
||||
val wellknownApi = retrofitFactory.create(baseUrl)
|
||||
.create(WellknownAPI::class.java)
|
||||
return wellknownApi.getWellKnown()
|
||||
}
|
||||
suspend fun execute(baseUrl: String): WellKnown
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,22 +21,27 @@ import app.cash.molecule.moleculeFlow
|
|||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.login.impl.changeaccountprovider.common.ChangeServerPresenter
|
||||
import io.element.android.features.login.impl.changeaccountprovider.form.network.WellKnown
|
||||
import io.element.android.features.login.impl.changeaccountprovider.form.network.WellKnownBaseConfig
|
||||
import io.element.android.features.login.impl.changeaccountprovider.form.network.WellKnownSlidingSyncConfig
|
||||
import io.element.android.features.login.impl.datasource.AccountProviderDataSource
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.test.A_HOMESERVER_URL
|
||||
import io.element.android.libraries.matrix.test.auth.FakeAuthenticationService
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class ChangeAccountProviderFormPresenterTest {
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
val homeServerResolver = FakeHomeServerResolver()
|
||||
val fakeWellknownRequest = FakeWellknownRequest()
|
||||
val changeServerPresenter = ChangeServerPresenter(
|
||||
FakeAuthenticationService(),
|
||||
AccountProviderDataSource()
|
||||
)
|
||||
val presenter = ChangeAccountProviderFormPresenter(
|
||||
homeServerResolver,
|
||||
DefaultHomeserverResolver(testCoroutineDispatchers(), fakeWellknownRequest),
|
||||
changeServerPresenter
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
|
|
@ -50,13 +55,13 @@ class ChangeAccountProviderFormPresenterTest {
|
|||
|
||||
@Test
|
||||
fun `present - enter text no result`() = runTest {
|
||||
val homeServerResolver = FakeHomeServerResolver()
|
||||
val fakeWellknownRequest = FakeWellknownRequest()
|
||||
val changeServerPresenter = ChangeServerPresenter(
|
||||
FakeAuthenticationService(),
|
||||
AccountProviderDataSource()
|
||||
)
|
||||
val presenter = ChangeAccountProviderFormPresenter(
|
||||
homeServerResolver,
|
||||
DefaultHomeserverResolver(testCoroutineDispatchers(), fakeWellknownRequest),
|
||||
changeServerPresenter
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
|
|
@ -73,12 +78,41 @@ class ChangeAccountProviderFormPresenterTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `present - enter text one then two results`() = runTest {
|
||||
val homeServerResolver = FakeHomeServerResolver()
|
||||
homeServerResolver.givenResult(
|
||||
listOf(
|
||||
listOf(aHomeserverData()),
|
||||
listOf(aHomeserverData(), aHomeserverData()),
|
||||
fun `present - enter valid url no wellknown`() = runTest {
|
||||
val fakeWellknownRequest = FakeWellknownRequest()
|
||||
val changeServerPresenter = ChangeServerPresenter(
|
||||
FakeAuthenticationService(),
|
||||
AccountProviderDataSource()
|
||||
)
|
||||
val presenter = ChangeAccountProviderFormPresenter(
|
||||
DefaultHomeserverResolver(testCoroutineDispatchers(), fakeWellknownRequest),
|
||||
changeServerPresenter
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(ChangeAccountProviderFormEvents.UserInput("https://test.org"))
|
||||
val withInputState = awaitItem()
|
||||
assertThat(withInputState.userInput).isEqualTo("https://test.org")
|
||||
assertThat(initialState.userInputResult).isEqualTo(Async.Uninitialized)
|
||||
assertThat(awaitItem().userInputResult).isInstanceOf(Async.Loading::class.java)
|
||||
assertThat(awaitItem().userInputResult).isEqualTo(
|
||||
Async.Success(
|
||||
listOf(
|
||||
aHomeserverData(homeserverUrl = "https://test.org", isWellknownValid = false, supportSlidingSync = false)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - enter text one result no sliding sync`() = runTest {
|
||||
val fakeWellknownRequest = FakeWellknownRequest()
|
||||
fakeWellknownRequest.givenResultMap(
|
||||
mapOf(
|
||||
"https://test.org" to aWellKnown().copy(slidingSyncProxy = null),
|
||||
)
|
||||
)
|
||||
val changeServerPresenter = ChangeServerPresenter(
|
||||
|
|
@ -86,7 +120,7 @@ class ChangeAccountProviderFormPresenterTest {
|
|||
AccountProviderDataSource()
|
||||
)
|
||||
val presenter = ChangeAccountProviderFormPresenter(
|
||||
homeServerResolver,
|
||||
DefaultHomeserverResolver(testCoroutineDispatchers(), fakeWellknownRequest),
|
||||
changeServerPresenter
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
|
|
@ -98,8 +132,62 @@ class ChangeAccountProviderFormPresenterTest {
|
|||
assertThat(withInputState.userInput).isEqualTo("test")
|
||||
assertThat(initialState.userInputResult).isEqualTo(Async.Uninitialized)
|
||||
assertThat(awaitItem().userInputResult).isInstanceOf(Async.Loading::class.java)
|
||||
assertThat(awaitItem().userInputResult).isEqualTo(Async.Success(listOf(aHomeserverData())))
|
||||
assertThat(awaitItem().userInputResult).isEqualTo(Async.Success(listOf(aHomeserverData(), aHomeserverData())))
|
||||
assertThat(awaitItem().userInputResult).isEqualTo(
|
||||
Async.Success(
|
||||
listOf(
|
||||
aHomeserverData(homeserverUrl = "https://test.org", isWellknownValid = true, supportSlidingSync = false)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - enter text one result with sliding sync`() = runTest {
|
||||
val fakeWellknownRequest = FakeWellknownRequest()
|
||||
fakeWellknownRequest.givenResultMap(
|
||||
mapOf(
|
||||
"https://test.io" to aWellKnown(),
|
||||
)
|
||||
)
|
||||
val changeServerPresenter = ChangeServerPresenter(
|
||||
FakeAuthenticationService(),
|
||||
AccountProviderDataSource()
|
||||
)
|
||||
val presenter = ChangeAccountProviderFormPresenter(
|
||||
DefaultHomeserverResolver(testCoroutineDispatchers(), fakeWellknownRequest),
|
||||
changeServerPresenter
|
||||
)
|
||||
moleculeFlow(RecompositionClock.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(ChangeAccountProviderFormEvents.UserInput("test"))
|
||||
val withInputState = awaitItem()
|
||||
assertThat(withInputState.userInput).isEqualTo("test")
|
||||
assertThat(initialState.userInputResult).isEqualTo(Async.Uninitialized)
|
||||
assertThat(awaitItem().userInputResult).isInstanceOf(Async.Loading::class.java)
|
||||
assertThat(awaitItem().userInputResult).isEqualTo(
|
||||
Async.Success(
|
||||
listOf(
|
||||
aHomeserverData(homeserverUrl = "https://test.io")
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun aWellKnown(): WellKnown {
|
||||
return WellKnown(
|
||||
homeServer = WellKnownBaseConfig(
|
||||
baseURL = A_HOMESERVER_URL
|
||||
),
|
||||
identityServer = WellKnownBaseConfig(
|
||||
baseURL = A_HOMESERVER_URL
|
||||
),
|
||||
slidingSyncProxy = WellKnownSlidingSyncConfig(
|
||||
url = A_HOMESERVER_URL
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 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.features.login.impl.changeaccountprovider.form
|
||||
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
class FakeHomeServerResolver : HomeserverResolver {
|
||||
private var pendingResult: List<List<HomeserverData>> = emptyList()
|
||||
fun givenResult(result: List<List<HomeserverData>>) {
|
||||
pendingResult = result
|
||||
}
|
||||
|
||||
override suspend fun resolve(userInput: String): Flow<Async<List<HomeserverData>>> = flow {
|
||||
emit(Async.Uninitialized)
|
||||
delay(FAKE_DELAY_IN_MS)
|
||||
emit(Async.Loading())
|
||||
// Sending the pending result
|
||||
if (pendingResult.isEmpty()) {
|
||||
emit(Async.Uninitialized)
|
||||
} else {
|
||||
pendingResult.forEach {
|
||||
delay(FAKE_DELAY_IN_MS)
|
||||
emit(Async.Success(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2023 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.features.login.impl.changeaccountprovider.form
|
||||
|
||||
import io.element.android.features.login.impl.changeaccountprovider.form.network.WellKnown
|
||||
import io.element.android.features.login.impl.changeaccountprovider.form.network.WellknownRequest
|
||||
|
||||
class FakeWellknownRequest : WellknownRequest {
|
||||
private var resultMap: Map<String, WellKnown> = emptyMap()
|
||||
fun givenResultMap(map: Map<String, WellKnown>) {
|
||||
resultMap = map
|
||||
}
|
||||
|
||||
override suspend fun execute(baseUrl: String): WellKnown {
|
||||
return resultMap[baseUrl] ?: error("No result provided for $baseUrl")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue