Initial labels data fetch added to LabelRepository.

MAILAND-1525
This commit is contained in:
Tomasz Giszczak 2021-08-26 14:21:38 +02:00 committed by stefanija
parent 23e672d10e
commit 6e17f1b679
7 changed files with 238 additions and 6 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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

View File

@ -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
)
}
}

View File

@ -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