Initial labels data fetch added to LabelRepository.
MAILAND-1525
This commit is contained in:
parent
23e672d10e
commit
6e17f1b679
|
@ -27,9 +27,7 @@ import android.text.TextUtils
|
|||
import ch.protonmail.android.api.models.ContactEncryptedData
|
||||
import ch.protonmail.android.api.models.ContactResponse
|
||||
import ch.protonmail.android.api.models.CreateContact
|
||||
import ch.protonmail.android.labels.data.mapper.LabelsMapper
|
||||
import ch.protonmail.android.api.models.contacts.send.LabelContactsBody
|
||||
import ch.protonmail.android.labels.data.model.LabelRequestBody
|
||||
import ch.protonmail.android.api.segments.RESPONSE_CODE_ERROR_CONTACT_EXIST_THIS_EMAIL
|
||||
import ch.protonmail.android.api.segments.RESPONSE_CODE_ERROR_EMAIL_DUPLICATE_FAILED
|
||||
import ch.protonmail.android.api.segments.RESPONSE_CODE_ERROR_EMAIL_EXIST
|
||||
|
@ -47,6 +45,8 @@ import ch.protonmail.android.data.local.model.ContactData
|
|||
import ch.protonmail.android.data.local.model.ContactEmailContactLabelJoin
|
||||
import ch.protonmail.android.events.ContactEvent
|
||||
import ch.protonmail.android.events.ContactProgressEvent
|
||||
import ch.protonmail.android.labels.data.mapper.LabelsMapper
|
||||
import ch.protonmail.android.labels.data.model.LabelRequestBody
|
||||
import ch.protonmail.android.utils.AppUtil
|
||||
import ch.protonmail.android.views.models.LocalContact
|
||||
import ch.protonmail.android.views.models.LocalContactAddress
|
||||
|
|
|
@ -21,6 +21,7 @@ package ch.protonmail.android.labels.data
|
|||
|
||||
import ch.protonmail.android.labels.data.db.LabelEntity
|
||||
import ch.protonmail.android.labels.data.model.LabelId
|
||||
import ch.protonmail.android.labels.data.model.LabelType
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import me.proton.core.domain.entity.UserId
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import ch.protonmail.android.labels.data.db.LabelEntity
|
|||
import ch.protonmail.android.labels.data.mapper.LabelsMapper
|
||||
import ch.protonmail.android.labels.data.model.LabelId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import timber.log.Timber
|
||||
|
@ -38,9 +39,19 @@ internal class LabelRepositoryImpl @Inject constructor(
|
|||
|
||||
override fun observeAllLabels(userId: UserId): Flow<List<LabelEntity>> =
|
||||
labelDao.observeAllLabels(userId)
|
||||
.onStart {
|
||||
Timber.v("Fetching fresh labels")
|
||||
fetchAndSaveAllLabels(userId)
|
||||
}
|
||||
|
||||
override suspend fun findAllLabels(userId: UserId): List<LabelEntity> =
|
||||
labelDao.findAllLabels(userId)
|
||||
override suspend fun findAllLabels(userId: UserId): List<LabelEntity> {
|
||||
val dbData = labelDao.findAllLabels(userId)
|
||||
return if (dbData.isEmpty()) {
|
||||
fetchAndSaveAllLabels(userId)
|
||||
} else {
|
||||
dbData
|
||||
}
|
||||
}
|
||||
|
||||
override fun observeLabels(userId: UserId, labelsIds: List<LabelId>): Flow<List<LabelEntity>> =
|
||||
labelDao.observeLabelsById(userId, labelsIds)
|
||||
|
@ -72,4 +83,18 @@ internal class LabelRepositoryImpl @Inject constructor(
|
|||
override suspend fun deleteAllLabels(userId: UserId) {
|
||||
labelDao.deleteAllLabels(userId)
|
||||
}
|
||||
|
||||
private suspend fun fetchAndSaveAllLabels(
|
||||
userId: UserId
|
||||
): List<LabelEntity> {
|
||||
val serverLabels = api.fetchLabels(userId).valueOrThrow.labels
|
||||
val serverFolders = api.fetchFolders(userId).valueOrThrow.labels
|
||||
val serverContactGroups = api.fetchContactGroups(userId).valueOrThrow.labels
|
||||
val labelList = serverLabels.map { labelMapper.mapLabelToLabelEntity(it, userId) }
|
||||
val foldersList = serverFolders.map { labelMapper.mapLabelToLabelEntity(it, userId) }
|
||||
val groupsList = serverContactGroups.map { labelMapper.mapLabelToLabelEntity(it, userId) }
|
||||
val allLabels = labelList + foldersList + groupsList
|
||||
saveLabels(allLabels)
|
||||
return allLabels
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,18 @@
|
|||
|
||||
package ch.protonmail.android.labels.data.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
enum class LabelType(val typeInt: Int) {
|
||||
|
||||
@SerialName("1")
|
||||
MESSAGE_LABEL(1),
|
||||
|
||||
@SerialName("2")
|
||||
CONTACT_GROUP(2),
|
||||
|
||||
@SerialName("3")
|
||||
FOLDER(3)
|
||||
}
|
||||
|
|
|
@ -377,7 +377,7 @@ class MessageDetailsViewModelTest : ArchTest, CoroutinesTest {
|
|||
)
|
||||
val exclusiveLabels = hashMapOf(INPUT_ITEM_DETAIL_ID to allLabels.takeLast(3))
|
||||
every {
|
||||
labelRepository.observeLabels(testId1, allLabelIds)
|
||||
labelRepository.observeLabels(testId1, allLabelIds,)
|
||||
} returns flowOf(allLabels)
|
||||
coEvery { messageRepository.getMessage(testId1, INPUT_ITEM_DETAIL_ID, true) } returns downLoadedMessage
|
||||
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Proton Technologies AG
|
||||
*
|
||||
* This file is part of ProtonMail.
|
||||
*
|
||||
* ProtonMail is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ProtonMail is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ProtonMail. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
package ch.protonmail.android.labels.data
|
||||
|
||||
import app.cash.turbine.test
|
||||
import ch.protonmail.android.api.ProtonMailApi
|
||||
import ch.protonmail.android.labels.data.db.LabelDao
|
||||
import ch.protonmail.android.labels.data.db.LabelEntity
|
||||
import ch.protonmail.android.labels.data.mapper.LabelsMapper
|
||||
import ch.protonmail.android.labels.data.model.Label
|
||||
import ch.protonmail.android.labels.data.model.LabelId
|
||||
import ch.protonmail.android.labels.data.model.LabelType
|
||||
import ch.protonmail.android.labels.data.model.LabelsResponse
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.test.runBlockingTest
|
||||
import me.proton.core.domain.entity.UserId
|
||||
import me.proton.core.network.domain.ApiResult
|
||||
import me.proton.core.test.kotlin.CoroutinesTest
|
||||
import org.junit.Test
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class LabelRepositoryImplTest : CoroutinesTest {
|
||||
|
||||
private val labelDao = mockk<LabelDao>()
|
||||
private val api = mockk<ProtonMailApi>()
|
||||
private val labelMapper = LabelsMapper()
|
||||
val testUserId = UserId("testUser")
|
||||
|
||||
private val repository = LabelRepositoryImpl(labelDao, api, labelMapper)
|
||||
|
||||
private val dbFlow = MutableSharedFlow<List<LabelEntity>>(replay = 1, onBufferOverflow = BufferOverflow.SUSPEND)
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
coEvery {
|
||||
labelDao.observeAllLabels(
|
||||
testUserId
|
||||
)
|
||||
} returns dbFlow
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyThatObserveAllLabelsStartsWithFetchingDataFromRemoteApiAndSavingInDb() = runBlockingTest {
|
||||
// given
|
||||
coEvery { api.fetchLabels(testUserId) } returns ApiResult.Success(LabelsResponse(listOf(testLabel1)))
|
||||
coEvery { api.fetchContactGroups(testUserId) } returns ApiResult.Success(LabelsResponse(listOf(testLabel2)))
|
||||
coEvery { api.fetchFolders(testUserId) } returns ApiResult.Success(LabelsResponse(listOf(testLabel3)))
|
||||
|
||||
val testLabelEntity1 = LabelEntity(
|
||||
id = LabelId(labelId1),
|
||||
userId = testUserId,
|
||||
name = labelName1,
|
||||
path = testPath,
|
||||
color = labelColor,
|
||||
type = LabelType.MESSAGE_LABEL,
|
||||
notify = 0,
|
||||
order = 0,
|
||||
expanded = 0,
|
||||
sticky = 0,
|
||||
parentId = testParentId
|
||||
)
|
||||
val testLabelEntity2 = LabelEntity(
|
||||
id = LabelId(labelId2),
|
||||
userId = testUserId,
|
||||
name = labelName1,
|
||||
path = testPath,
|
||||
color = labelColor,
|
||||
type = LabelType.CONTACT_GROUP,
|
||||
notify = 0,
|
||||
order = 0,
|
||||
expanded = 0,
|
||||
sticky = 0,
|
||||
parentId = testParentId
|
||||
)
|
||||
val testLabelEntity3 = LabelEntity(
|
||||
id = LabelId(labelId3),
|
||||
userId = testUserId,
|
||||
name = labelName1,
|
||||
path = testPath,
|
||||
color = labelColor,
|
||||
type = LabelType.FOLDER,
|
||||
notify = 0,
|
||||
order = 0,
|
||||
expanded = 0,
|
||||
sticky = 0,
|
||||
parentId = testParentId
|
||||
)
|
||||
|
||||
val dataToSaveInDb = listOf(testLabelEntity1, testLabelEntity2, testLabelEntity3)
|
||||
coEvery { labelDao.saveLabels(any()) } answers {
|
||||
dbFlow.tryEmit(dataToSaveInDb)
|
||||
listOf(3L)
|
||||
}
|
||||
|
||||
val subsequentDbReply = listOf(testLabelEntity1)
|
||||
|
||||
// when
|
||||
repository.observeAllLabels(testUserId).test {
|
||||
|
||||
// then
|
||||
coVerify { labelDao.saveLabels(any()) }
|
||||
assertEquals(dataToSaveInDb, expectItem())
|
||||
dbFlow.tryEmit(subsequentDbReply)
|
||||
assertEquals(subsequentDbReply, expectItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun verifyThatFetchLabelsTriesToGetLabelsFromApiIfTheDbIsEmpty() = runBlocking {
|
||||
// given
|
||||
coEvery { labelDao.findAllLabels(testUserId) } returns emptyList()
|
||||
coEvery { api.fetchLabels(testUserId) } returns ApiResult.Success(LabelsResponse(listOf(testLabel1)))
|
||||
coEvery { api.fetchContactGroups(testUserId) } returns ApiResult.Success(LabelsResponse(listOf(testLabel2)))
|
||||
coEvery { api.fetchFolders(testUserId) } returns ApiResult.Success(LabelsResponse(listOf(testLabel3)))
|
||||
coEvery { labelDao.saveLabels(any()) } returns listOf(1L)
|
||||
// when
|
||||
val response = repository.findAllLabels(testUserId)
|
||||
|
||||
// then
|
||||
assertTrue(response.size == 3)
|
||||
coVerify { labelDao.saveLabels(any()) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val labelId1 = "labelId1"
|
||||
private const val labelId2 = "labelId2"
|
||||
private const val labelId3 = "labelId3"
|
||||
private const val labelName1 = "labelName1"
|
||||
private const val labelColor = "labelColor11"
|
||||
private const val testPath = "a/bcPath"
|
||||
private const val testParentId = "parentIdForTests"
|
||||
val testLabel1 = Label(
|
||||
id = labelId1,
|
||||
name = labelName1,
|
||||
path = testPath,
|
||||
color = labelColor,
|
||||
type = LabelType.MESSAGE_LABEL,
|
||||
notify = 0,
|
||||
order = 0,
|
||||
expanded = null,
|
||||
sticky = null,
|
||||
parentId = testParentId
|
||||
)
|
||||
val testLabel2 = Label(
|
||||
id = labelId2,
|
||||
name = labelName1,
|
||||
path = testPath,
|
||||
color = labelColor,
|
||||
type = LabelType.CONTACT_GROUP,
|
||||
notify = 0,
|
||||
order = 0,
|
||||
expanded = null,
|
||||
sticky = null,
|
||||
parentId = testParentId
|
||||
)
|
||||
val testLabel3 = Label(
|
||||
id = labelId3,
|
||||
name = labelName1,
|
||||
path = testPath,
|
||||
color = labelColor,
|
||||
type = LabelType.FOLDER,
|
||||
notify = 0,
|
||||
order = 0,
|
||||
expanded = null,
|
||||
sticky = null,
|
||||
parentId = testParentId
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -19,6 +19,6 @@
|
|||
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
Loading…
Reference in New Issue