Set base url through Interceptor

This commit is contained in:
Kirill Kamakin
2022-12-11 20:22:36 +01:00
parent 85b863227d
commit f6c0e862fc
27 changed files with 265 additions and 234 deletions

View File

@@ -19,18 +19,16 @@ class AuthDataSourceImpl @Inject constructor(
private suspend fun getVersion(): ServerVersion = serverInfoRepo.getVersion()
private suspend fun getUrl(): String = serverInfoRepo.requireUrl()
override suspend fun authenticate(
username: String,
password: String,
): String = when (getVersion()) {
ServerVersion.V0 -> v0Source.authenticate(getUrl(), username, password)
ServerVersion.V1 -> v1Source.authenticate(getUrl(), username, password)
ServerVersion.V0 -> v0Source.authenticate(username, password)
ServerVersion.V1 -> v1Source.authenticate(username, password)
}
override suspend fun createApiToken(name: String): String = when (getVersion()) {
ServerVersion.V0 -> v0Source.createApiToken(getUrl(), CreateApiTokenRequestV0(name))
ServerVersion.V1 -> v1Source.createApiToken(getUrl(), CreateApiTokenRequestV1(name)).token
ServerVersion.V0 -> v0Source.createApiToken(CreateApiTokenRequestV0(name))
ServerVersion.V1 -> v1Source.createApiToken(CreateApiTokenRequestV1(name)).token
}
}

View File

@@ -4,10 +4,9 @@ interface ServerInfoRepo {
suspend fun getUrl(): String?
suspend fun requireUrl(): String
suspend fun getVersion(): ServerVersion
suspend fun storeBaseURL(baseURL: String, version: String)
suspend fun tryBaseURL(baseURL: String): Result<Unit>
}

View File

@@ -1,6 +1,8 @@
package gq.kirmanak.mealient.data.baseurl
import gq.kirmanak.mealient.datasource.NetworkError
import gq.kirmanak.mealient.datasource.ServerUrlProvider
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
import gq.kirmanak.mealient.logging.Logger
import javax.inject.Inject
import javax.inject.Singleton
@@ -10,7 +12,7 @@ class ServerInfoRepoImpl @Inject constructor(
private val serverInfoStorage: ServerInfoStorage,
private val versionDataSource: VersionDataSource,
private val logger: Logger,
) : ServerInfoRepo {
) : ServerInfoRepo, ServerUrlProvider {
override suspend fun getUrl(): String? {
val result = serverInfoStorage.getBaseURL()
@@ -18,17 +20,11 @@ class ServerInfoRepoImpl @Inject constructor(
return result
}
override suspend fun requireUrl(): String {
val result = checkNotNull(getUrl()) { "Server URL was null when it was required" }
logger.v { "requireUrl() returned: $result" }
return result
}
override suspend fun getVersion(): ServerVersion {
var version = serverInfoStorage.getServerVersion()
val serverVersion = if (version == null) {
logger.d { "getVersion: version is null, requesting" }
version = versionDataSource.getVersionInfo(requireUrl()).version
version = versionDataSource.getVersionInfo().version
val result = determineServerVersion(version)
serverInfoStorage.storeServerVersion(version)
result
@@ -45,8 +41,16 @@ class ServerInfoRepoImpl @Inject constructor(
else -> throw NetworkError.NotMealie(IllegalStateException("Server version is unknown: $version"))
}
override suspend fun storeBaseURL(baseURL: String, version: String) {
logger.v { "storeBaseURL() called with: baseURL = $baseURL, version = $version" }
serverInfoStorage.storeBaseURL(baseURL, version)
override suspend fun tryBaseURL(baseURL: String): Result<Unit> {
val oldVersion = serverInfoStorage.getServerVersion()
val oldBaseUrl = serverInfoStorage.getBaseURL()
return runCatchingExceptCancel {
serverInfoStorage.storeBaseURL(baseURL)
val version = versionDataSource.getVersionInfo().version
serverInfoStorage.storeServerVersion(version)
}.onFailure {
serverInfoStorage.storeBaseURL(oldBaseUrl, oldVersion)
}
}
}

View File

@@ -4,9 +4,12 @@ interface ServerInfoStorage {
suspend fun getBaseURL(): String?
suspend fun storeBaseURL(baseURL: String, version: String)
suspend fun storeBaseURL(baseURL: String)
suspend fun storeBaseURL(baseURL: String?, version: String?)
suspend fun storeServerVersion(version: String)
suspend fun getServerVersion(): String?
}

View File

@@ -2,5 +2,5 @@ package gq.kirmanak.mealient.data.baseurl
interface VersionDataSource {
suspend fun getVersionInfo(baseUrl: String): VersionInfo
suspend fun getVersionInfo(): VersionInfo
}

View File

@@ -16,13 +16,13 @@ class VersionDataSourceImpl @Inject constructor(
private val v1Source: MealieDataSourceV1,
) : VersionDataSource {
override suspend fun getVersionInfo(baseUrl: String): VersionInfo {
override suspend fun getVersionInfo(): VersionInfo {
val responses = coroutineScope {
val v0Deferred = async {
runCatchingExceptCancel { v0Source.getVersionInfo(baseUrl).toVersionInfo() }
runCatchingExceptCancel { v0Source.getVersionInfo().toVersionInfo() }
}
val v1Deferred = async {
runCatchingExceptCancel { v1Source.getVersionInfo(baseUrl).toVersionInfo() }
runCatchingExceptCancel { v1Source.getVersionInfo().toVersionInfo() }
}
listOf(v0Deferred, v1Deferred).awaitAll()
}

View File

@@ -19,11 +19,28 @@ class ServerInfoStorageImpl @Inject constructor(
override suspend fun getBaseURL(): String? = getValue(baseUrlKey)
override suspend fun storeBaseURL(baseURL: String, version: String) {
preferencesStorage.storeValues(
Pair(baseUrlKey, baseURL),
Pair(serverVersionKey, version),
)
override suspend fun storeBaseURL(baseURL: String) {
preferencesStorage.storeValues(Pair(baseUrlKey, baseURL))
preferencesStorage.removeValues(serverVersionKey)
}
override suspend fun storeBaseURL(baseURL: String?, version: String?) {
when {
baseURL == null -> {
preferencesStorage.removeValues(baseUrlKey, serverVersionKey)
}
version != null -> {
preferencesStorage.storeValues(
Pair(baseUrlKey, baseURL), Pair(serverVersionKey, version)
)
}
else -> {
preferencesStorage.removeValues(serverVersionKey)
preferencesStorage.storeValues(Pair(baseUrlKey, baseURL))
}
}
}
override suspend fun getServerVersion(): String? = getValue(serverVersionKey)
@@ -33,4 +50,5 @@ class ServerInfoStorageImpl @Inject constructor(
}
private suspend fun <T> getValue(key: Preferences.Key<T>): T? = preferencesStorage.getValue(key)
}

View File

@@ -29,13 +29,11 @@ class MealieDataSourceWrapper @Inject constructor(
private suspend fun getVersion(): ServerVersion = serverInfoRepo.getVersion()
private suspend fun getUrl(): String = serverInfoRepo.requireUrl()
override suspend fun addRecipe(recipe: AddRecipeInfo): String = when (getVersion()) {
ServerVersion.V0 -> v0Source.addRecipe(getUrl(), recipe.toV0Request())
ServerVersion.V0 -> v0Source.addRecipe(recipe.toV0Request())
ServerVersion.V1 -> {
val slug = v1Source.createRecipe(getUrl(), recipe.toV1CreateRequest())
v1Source.updateRecipe(getUrl(), slug, recipe.toV1UpdateRequest())
val slug = v1Source.createRecipe(recipe.toV1CreateRequest())
v1Source.updateRecipe(slug, recipe.toV1UpdateRequest())
slug
}
}
@@ -45,25 +43,25 @@ class MealieDataSourceWrapper @Inject constructor(
limit: Int,
): List<RecipeSummaryInfo> = when (getVersion()) {
ServerVersion.V0 -> {
v0Source.requestRecipes(getUrl(), start, limit).map { it.toRecipeSummaryInfo() }
v0Source.requestRecipes(start, limit).map { it.toRecipeSummaryInfo() }
}
ServerVersion.V1 -> {
// Imagine start is 30 and limit is 15. It means that we already have page 1 and 2, now we need page 3
val page = start / limit + 1
v1Source.requestRecipes(getUrl(), page, limit).map { it.toRecipeSummaryInfo() }
v1Source.requestRecipes(page, limit).map { it.toRecipeSummaryInfo() }
}
}
override suspend fun requestRecipeInfo(slug: String): FullRecipeInfo = when (getVersion()) {
ServerVersion.V0 -> v0Source.requestRecipeInfo(getUrl(), slug).toFullRecipeInfo()
ServerVersion.V1 -> v1Source.requestRecipeInfo(getUrl(), slug).toFullRecipeInfo()
ServerVersion.V0 -> v0Source.requestRecipeInfo(slug).toFullRecipeInfo()
ServerVersion.V1 -> v1Source.requestRecipeInfo(slug).toFullRecipeInfo()
}
override suspend fun parseRecipeFromURL(
parseRecipeURLInfo: ParseRecipeURLInfo,
): String = when (getVersion()) {
ServerVersion.V0 -> v0Source.parseRecipeFromURL(getUrl(), parseRecipeURLInfo.toV0Request())
ServerVersion.V1 -> v1Source.parseRecipeFromURL(getUrl(), parseRecipeURLInfo.toV1Request())
ServerVersion.V0 -> v0Source.parseRecipeFromURL(parseRecipeURLInfo.toV0Request())
ServerVersion.V1 -> v1Source.parseRecipeFromURL(parseRecipeURLInfo.toV1Request())
}
}

View File

@@ -6,6 +6,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.data.baseurl.*
import gq.kirmanak.mealient.data.baseurl.impl.ServerInfoStorageImpl
import gq.kirmanak.mealient.datasource.ServerUrlProvider
import javax.inject.Singleton
@Module
@@ -23,4 +24,8 @@ interface BaseURLModule {
@Binds
@Singleton
fun bindServerInfoRepo(serverInfoRepoImpl: ServerInfoRepoImpl): ServerInfoRepo
@Binds
@Singleton
fun bindServerUrlProvider(serverInfoRepoImpl: ServerInfoRepoImpl): ServerUrlProvider
}

View File

@@ -7,9 +7,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import gq.kirmanak.mealient.data.auth.AuthRepo
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
import gq.kirmanak.mealient.data.baseurl.VersionDataSource
import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
import gq.kirmanak.mealient.logging.Logger
import gq.kirmanak.mealient.ui.OperationUiState
import kotlinx.coroutines.launch
@@ -20,7 +18,6 @@ class BaseURLViewModel @Inject constructor(
private val serverInfoRepo: ServerInfoRepo,
private val authRepo: AuthRepo,
private val recipeRepo: RecipeRepo,
private val versionDataSource: VersionDataSource,
private val logger: Logger,
) : ViewModel() {
@@ -42,10 +39,8 @@ class BaseURLViewModel @Inject constructor(
_uiState.value = OperationUiState.fromResult(Result.success(Unit))
return
}
val result = runCatchingExceptCancel {
// If it returns proper version info then it must be a Mealie
val version = versionDataSource.getVersionInfo(baseURL).version
serverInfoRepo.storeBaseURL(baseURL, version)
val result = serverInfoRepo.tryBaseURL(baseURL)
if (result.isSuccess) {
authRepo.logout()
recipeRepo.clearLocalData()
}

View File

@@ -9,7 +9,6 @@ import gq.kirmanak.mealient.datasource.runCatchingExceptCancel
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_API_AUTH_HEADER
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_API_TOKEN
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_AUTH_HEADER
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_PASSWORD
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_SERVER_VERSION_V0
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_TOKEN
@@ -54,7 +53,6 @@ class AuthRepoImplTest : BaseUnitTest() {
fun `when authenticate successfully then saves to storage`() = runTest {
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
coEvery { dataSource.authenticate(any(), any()) } returns TEST_TOKEN
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { dataSource.createApiToken(any()) } returns TEST_API_TOKEN
subject.authenticate(TEST_USERNAME, TEST_PASSWORD)
coVerify {
@@ -69,7 +67,6 @@ class AuthRepoImplTest : BaseUnitTest() {
@Test
fun `when authenticate fails then does not change storage`() = runTest {
coEvery { dataSource.authenticate(any(), any()) } throws RuntimeException()
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
runCatchingExceptCancel { subject.authenticate("invalid", "") }
confirmVerified(storage)
}

View File

@@ -13,6 +13,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import java.io.IOException
@OptIn(ExperimentalCoroutinesApi::class)
class ServerInfoRepoTest : BaseUnitTest() {
@@ -44,12 +45,6 @@ class ServerInfoRepoTest : BaseUnitTest() {
assertThat(subject.getUrl()).isEqualTo(expected)
}
@Test(expected = IllegalStateException::class)
fun `when storage returns null url expect requireUrl to throw`() = runTest {
coEvery { storage.getBaseURL() } returns null
subject.requireUrl()
}
@Test
fun `when getUrl expect storage is accessed`() = runTest {
coEvery { storage.getBaseURL() } returns null
@@ -58,32 +53,45 @@ class ServerInfoRepoTest : BaseUnitTest() {
}
@Test
fun `when requireUrl expect storage is accessed`() = runTest {
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
subject.requireUrl()
coVerify { storage.getBaseURL() }
fun `when tryBaseURL succeeds expect call to storage`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns null
coEvery { dataSource.getVersionInfo() } returns VersionInfo(TEST_VERSION)
subject.tryBaseURL(TEST_BASE_URL)
coVerify {
storage.storeBaseURL(eq(TEST_BASE_URL))
dataSource.getVersionInfo()
storage.storeServerVersion(TEST_VERSION)
}
}
@Test
fun `when storeBaseUrl expect call to storage`() = runTest {
subject.storeBaseURL(TEST_BASE_URL, TEST_VERSION)
coVerify { storage.storeBaseURL(TEST_BASE_URL, TEST_VERSION) }
fun `when tryBaseURL fails expect call to storage`() = runTest {
coEvery { storage.getServerVersion() } returns "serverVersion"
coEvery { storage.getBaseURL() } returns "baseUrl"
coEvery { dataSource.getVersionInfo() } throws IOException()
subject.tryBaseURL(TEST_BASE_URL)
coVerify {
storage.storeBaseURL(eq(TEST_BASE_URL))
dataSource.getVersionInfo()
storage.storeBaseURL(eq("baseUrl"), eq("serverVersion"))
}
}
@Test
fun `when storage is empty expect getVersion to call data source`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
coEvery { dataSource.getVersionInfo(eq(TEST_BASE_URL)) } returns VERSION_INFO_V0
coEvery { dataSource.getVersionInfo() } returns VERSION_INFO_V0
subject.getVersion()
coVerify { dataSource.getVersionInfo(eq(TEST_BASE_URL)) }
coVerify { dataSource.getVersionInfo() }
}
@Test
fun `when storage is empty and data source has value expect getVersion to save it`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
coEvery { dataSource.getVersionInfo(eq(TEST_BASE_URL)) } returns VersionInfo(TEST_VERSION)
coEvery { dataSource.getVersionInfo() } returns VersionInfo(TEST_VERSION)
subject.getVersion()
coVerify { storage.storeServerVersion(TEST_VERSION) }
}
@@ -92,7 +100,7 @@ class ServerInfoRepoTest : BaseUnitTest() {
fun `when data source has invalid value expect getVersion to throw`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
coEvery { dataSource.getVersionInfo(eq(TEST_BASE_URL)) } returns VersionInfo("v2.0.0")
coEvery { dataSource.getVersionInfo() } returns VersionInfo("v2.0.0")
subject.getVersion()
}
@@ -100,7 +108,7 @@ class ServerInfoRepoTest : BaseUnitTest() {
fun `when data source has invalid value expect getVersion not to save`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
coEvery { dataSource.getVersionInfo(eq(TEST_BASE_URL)) } returns VersionInfo("v2.0.0")
coEvery { dataSource.getVersionInfo() } returns VersionInfo("v2.0.0")
subject.runCatching { getVersion() }
coVerify(inverse = true) { storage.storeServerVersion(any()) }
}
@@ -116,7 +124,7 @@ class ServerInfoRepoTest : BaseUnitTest() {
fun `when storage has value expect getVersion to not call data source`() = runTest {
coEvery { storage.getServerVersion() } returns TEST_VERSION
subject.getVersion()
coVerify(inverse = true) { dataSource.getVersionInfo(any()) }
coVerify(inverse = true) { dataSource.getVersionInfo() }
}
@Test
@@ -135,7 +143,7 @@ class ServerInfoRepoTest : BaseUnitTest() {
fun `when data source has valid v0 value expect getVersion to return it`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
coEvery { dataSource.getVersionInfo(eq(TEST_BASE_URL)) } returns VersionInfo("v0.5.6")
coEvery { dataSource.getVersionInfo() } returns VersionInfo("v0.5.6")
assertThat(subject.getVersion()).isEqualTo(ServerVersion.V0)
}
@@ -143,7 +151,7 @@ class ServerInfoRepoTest : BaseUnitTest() {
fun `when data source has valid v1 value expect getVersion to return it`() = runTest {
coEvery { storage.getServerVersion() } returns null
coEvery { storage.getBaseURL() } returns TEST_BASE_URL
coEvery { dataSource.getVersionInfo(eq(TEST_BASE_URL)) } returns VersionInfo("v1.0.0-beta05")
coEvery { dataSource.getVersionInfo() } returns VersionInfo("v1.0.0-beta05")
assertThat(subject.getVersion()).isEqualTo(ServerVersion.V1)
}
}

View File

@@ -6,7 +6,6 @@ import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
import gq.kirmanak.mealient.datasource.v0.MealieDataSourceV0
import gq.kirmanak.mealient.datasource.v1.MealieDataSourceV1
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_AUTH_HEADER
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_SERVER_VERSION_V0
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_SERVER_VERSION_V1
import gq.kirmanak.mealient.test.BaseUnitTest
@@ -55,15 +54,14 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
fun `when server version v1 expect requestRecipeInfo to call v1`() = runTest {
val slug = "porridge"
coEvery {
v1Source.requestRecipeInfo(eq(TEST_BASE_URL), eq(slug))
v1Source.requestRecipeInfo(eq(slug))
} returns PORRIDGE_RECIPE_RESPONSE_V1
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
val actual = subject.requestRecipeInfo(slug)
coVerify { v1Source.requestRecipeInfo(eq(TEST_BASE_URL), eq(slug)) }
coVerify { v1Source.requestRecipeInfo(eq(slug)) }
assertThat(actual).isEqualTo(PORRIDGE_FULL_RECIPE_INFO)
}
@@ -71,10 +69,9 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
@Test
fun `when server version v1 expect requestRecipes to call v1`() = runTest {
coEvery {
v1Source.requestRecipes(any(), any(), any())
v1Source.requestRecipes(any(), any())
} returns listOf(PORRIDGE_RECIPE_SUMMARY_RESPONSE_V1)
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
val actual = subject.requestRecipes(40, 10)
@@ -82,7 +79,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
val page = 5 // 0-9 (1), 10-19 (2), 20-29 (3), 30-39 (4), 40-49 (5)
val perPage = 10
coVerify {
v1Source.requestRecipes(eq(TEST_BASE_URL), eq(page), eq(perPage))
v1Source.requestRecipes(eq(page), eq(perPage))
}
assertThat(actual).isEqualTo(listOf(RECIPE_SUMMARY_PORRIDGE_V1))
@@ -91,10 +88,9 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
@Test
fun `when server version v0 expect requestRecipes to call v0`() = runTest {
coEvery {
v0Source.requestRecipes(any(), any(), any())
v0Source.requestRecipes(any(), any())
} returns listOf(PORRIDGE_RECIPE_SUMMARY_RESPONSE_V0)
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
val start = 40
@@ -102,7 +98,7 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
val actual = subject.requestRecipes(start, limit)
coVerify {
v0Source.requestRecipes(eq(TEST_BASE_URL), eq(start), eq(limit))
v0Source.requestRecipes(eq(start), eq(limit))
}
assertThat(actual).isEqualTo(listOf(RECIPE_SUMMARY_PORRIDGE_V0))
@@ -110,9 +106,8 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
@Test(expected = IOException::class)
fun `when request fails expect addRecipe to rethrow`() = runTest {
coEvery { v0Source.addRecipe(any(), any()) } throws IOException()
coEvery { v0Source.addRecipe(any()) } throws IOException()
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
subject.addRecipe(PORRIDGE_ADD_RECIPE_INFO)
}
@@ -121,16 +116,14 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
fun `when server version v0 expect addRecipe to call v0`() = runTest {
val slug = "porridge"
coEvery { v0Source.addRecipe(any(), any()) } returns slug
coEvery { v0Source.addRecipe(any()) } returns slug
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V0
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
val actual = subject.addRecipe(PORRIDGE_ADD_RECIPE_INFO)
coVerify {
v0Source.addRecipe(
eq(TEST_BASE_URL),
eq(PORRIDGE_ADD_RECIPE_REQUEST_V0),
)
}
@@ -142,24 +135,21 @@ class MealieDataSourceWrapperTest : BaseUnitTest() {
fun `when server version v1 expect addRecipe to call v1`() = runTest {
val slug = "porridge"
coEvery { v1Source.createRecipe(any(), any()) } returns slug
coEvery { v1Source.createRecipe(any()) } returns slug
coEvery {
v1Source.updateRecipe(any(), any(), any())
v1Source.updateRecipe(any(), any())
} returns PORRIDGE_RECIPE_RESPONSE_V1
coEvery { serverInfoRepo.getVersion() } returns TEST_SERVER_VERSION_V1
coEvery { serverInfoRepo.requireUrl() } returns TEST_BASE_URL
coEvery { authRepo.getAuthHeader() } returns TEST_AUTH_HEADER
val actual = subject.addRecipe(PORRIDGE_ADD_RECIPE_INFO)
coVerifySequence {
v1Source.createRecipe(
eq(TEST_BASE_URL),
eq(PORRIDGE_CREATE_RECIPE_REQUEST_V1),
)
v1Source.updateRecipe(
eq(TEST_BASE_URL),
eq(slug),
eq(PORRIDGE_UPDATE_RECIPE_REQUEST_V1),
)

View File

@@ -3,11 +3,8 @@ package gq.kirmanak.mealient.ui.baseurl
import com.google.common.truth.Truth.assertThat
import gq.kirmanak.mealient.data.auth.AuthRepo
import gq.kirmanak.mealient.data.baseurl.ServerInfoRepo
import gq.kirmanak.mealient.data.baseurl.VersionDataSource
import gq.kirmanak.mealient.data.baseurl.VersionInfo
import gq.kirmanak.mealient.data.recipes.RecipeRepo
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_BASE_URL
import gq.kirmanak.mealient.test.AuthImplTestData.TEST_VERSION
import gq.kirmanak.mealient.test.BaseUnitTest
import gq.kirmanak.mealient.ui.OperationUiState
import io.mockk.coEvery
@@ -31,9 +28,6 @@ class BaseURLViewModelTest : BaseUnitTest() {
@MockK(relaxUnitFun = true)
lateinit var recipeRepo: RecipeRepo
@MockK
lateinit var versionDataSource: VersionDataSource
lateinit var subject: BaseURLViewModel
@Before
@@ -43,7 +37,6 @@ class BaseURLViewModelTest : BaseUnitTest() {
serverInfoRepo = serverInfoRepo,
authRepo = authRepo,
recipeRepo = recipeRepo,
versionDataSource = versionDataSource,
logger = logger,
)
}
@@ -51,13 +44,13 @@ class BaseURLViewModelTest : BaseUnitTest() {
@Test
fun `when saveBaseURL expect no version checks given that current URL matches new`() = runTest {
setupSaveBaseUrlWithOldUrl()
coVerify(inverse = true) { versionDataSource.getVersionInfo(any()) }
coVerify(inverse = true) { serverInfoRepo.tryBaseURL(any()) }
}
@Test
fun `when saveBaseURL expect URL isn't saved given that current URL matches new`() = runTest {
setupSaveBaseUrlWithOldUrl()
coVerify(inverse = true) { serverInfoRepo.storeBaseURL(any(), any()) }
coVerify(inverse = true) { serverInfoRepo.tryBaseURL(any()) }
}
@Test
@@ -74,7 +67,7 @@ class BaseURLViewModelTest : BaseUnitTest() {
private fun TestScope.setupSaveBaseUrlWithOldUrl() {
coEvery { serverInfoRepo.getUrl() } returns TEST_BASE_URL
versionDataSourceReturnsSuccess()
coEvery { serverInfoRepo.tryBaseURL(any()) } returns Result.success(Unit)
subject.saveBaseUrl(TEST_BASE_URL)
advanceUntilIdle()
}
@@ -82,7 +75,7 @@ class BaseURLViewModelTest : BaseUnitTest() {
@Test
fun `when saveBaseUrl expect URL is saved given that new URL doesn't match old`() = runTest {
setupSaveBaseUrlWithNewUrl()
coVerify { serverInfoRepo.storeBaseURL(eq(TEST_BASE_URL), eq(TEST_VERSION)) }
coVerify { serverInfoRepo.tryBaseURL(eq(TEST_BASE_URL)) }
}
@Test
@@ -99,21 +92,15 @@ class BaseURLViewModelTest : BaseUnitTest() {
private fun TestScope.setupSaveBaseUrlWithNewUrl() {
coEvery { serverInfoRepo.getUrl() } returns null
versionDataSourceReturnsSuccess()
coEvery { serverInfoRepo.tryBaseURL(any()) } returns Result.success(Unit)
subject.saveBaseUrl(TEST_BASE_URL)
advanceUntilIdle()
}
private fun versionDataSourceReturnsSuccess() {
coEvery {
versionDataSource.getVersionInfo(eq(TEST_BASE_URL))
} returns VersionInfo(TEST_VERSION)
}
@Test
fun `when saveBaseURL expect error given that version can't be fetched`() = runTest {
coEvery { serverInfoRepo.getUrl() } returns null
coEvery { versionDataSource.getVersionInfo(eq(TEST_BASE_URL)) } throws IOException()
coEvery { serverInfoRepo.tryBaseURL(any()) } returns Result.failure(IOException())
subject.saveBaseUrl(TEST_BASE_URL)
advanceUntilIdle()
assertThat(subject.uiState.value).isInstanceOf(OperationUiState.Failure::class.java)