Skip to content

Commit

Permalink
test: cover some missed classes of sync with unit test - PART 2 (WPB-…
Browse files Browse the repository at this point in the history
…3472) (#1974)

* test: cover some missed classes of sync with unit test

* test: revert ignore test on iOS

* test: fix test on iOS
  • Loading branch information
ohassine authored Aug 11, 2023
1 parent c324301 commit f47c887
Show file tree
Hide file tree
Showing 15 changed files with 620 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ internal class SlowSyncRepositoryImpl(private val metadataDao: MetadataDAO) : Sl
return metadataDao.valueByKey(key = SLOW_SYNC_VERSION_KEY)?.toIntOrNull() ?: 0
}

private companion object {
companion object {
const val LAST_SLOW_SYNC_INSTANT_KEY = "lastSlowSyncInstant"
const val SLOW_SYNC_VERSION_KEY = "slowSyncVersion"
const val MLS_NEEDS_RECOVERY_KEY = "mlsNeedsRecovery"
const val NEEDS_TO_PERSIST_HISTORY_LOST_MESSAGES_KEY = "needsToPersistHistoryLostMessages"
private const val SLOW_SYNC_VERSION_KEY = "slowSyncVersion"
private const val MLS_NEEDS_RECOVERY_KEY = "mlsNeedsRecovery"
private const val NEEDS_TO_PERSIST_HISTORY_LOST_MESSAGES_KEY = "needsToPersistHistoryLostMessages"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,7 @@ internal class ConversationEventReceiverImpl(
Either.Right(Unit)
}

is Event.Conversation.ConversationMessageTimer -> {
conversationMessageTimerEventHandler.handle(event)
Either.Right(Unit)
}
is Event.Conversation.ConversationMessageTimer -> conversationMessageTimerEventHandler.handle(event)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import io.mockative.classOf
import io.mockative.given
import io.mockative.mock
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
Expand Down Expand Up @@ -204,7 +203,6 @@ class IncrementalSyncRepositoryTest {
assertEquals(initialValue, state)
}

@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun givenASlowStateCollector_whenStateIsUpdatedManyTimes_thenUpdateEmissionShouldNotBeBlockedByOverflownBuffer() = runTest {
val updateCount = 10_000
Expand All @@ -231,7 +229,6 @@ class IncrementalSyncRepositoryTest {
}
}

@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun givenASlowPolicyCollector_whenPolicyIsUpdatedManyTimes_thenUpdateEmissionShouldNotBeBlockedByOverflownBuffer() = runTest {
val updateCount = 10_000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds

class SlowSyncRepositoryTest {
Expand All @@ -43,6 +44,15 @@ class SlowSyncRepositoryTest {
slowSyncRepository = SlowSyncRepositoryImpl(database.builder.metadataDAO)
}

@Test
fun givenLastInstantWasNeverSet_whenGettingLastInstant_thenTheStateIsNull() = runTest(testDispatcher) {
// Empty Given

val lastSyncInstant = slowSyncRepository.observeLastSlowSyncCompletionInstant().first()

assertNull(lastSyncInstant)
}

@Test
fun givenInstantIsUpdated_whenGettingTheLastSlowSyncInstant_thenShouldReturnTheNewState() = runTest(testDispatcher) {
val instant = DateTimeUtil.currentInstant()
Expand All @@ -59,19 +69,6 @@ class SlowSyncRepositoryTest {
assertEquals(version, slowSyncRepository.getSlowSyncVersion())
}

@IgnoreIOS // TODO investigate why test is failing
@Test
fun givenLastInstantWasNeverSet_whenGettingLastInstant_thenTheStateIsNull() = runTest(testDispatcher) {
// Empty Given

val lastSyncInstant = slowSyncRepository.observeLastSlowSyncCompletionInstant().first()

assertNull(lastSyncInstant)
}

// TODO: Re-enable once we can update Turbine to 0.11.0+ (Requires Kotlin 1.6.21+)
// @Ignore
@IgnoreIOS // TODO investigate why test is failing
@Test
fun givenAnInstantIsUpdated_whenObservingTheLastSlowSyncInstant_thenTheNewStateIsPropagatedForObservers() = runTest(testDispatcher) {
val firstInstant = DateTimeUtil.currentInstant()
Expand Down Expand Up @@ -132,4 +129,13 @@ class SlowSyncRepositoryTest {

assertEquals(newStatus, currentState)
}

@Test
fun givenMetaDataDao_whenClearLastSlowSyncCompletionInstantIsCalled_thenInvokeDeleteValueOnce() = runTest(testDispatcher) {
slowSyncRepository.setNeedsToPersistHistoryLostMessage(true)

val result = slowSyncRepository.needsToPersistHistoryLostMessage()

assertTrue { result }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ import com.wire.kalium.logic.data.event.Event
import com.wire.kalium.logic.data.user.Connection
import com.wire.kalium.logic.data.user.ConnectionState
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.network.api.base.authenticated.client.ClientTypeDTO
import com.wire.kalium.network.api.base.authenticated.client.DeviceTypeDTO
import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString
import kotlinx.datetime.Instant

Expand All @@ -43,6 +41,15 @@ object TestEvent {
"2022-03-30T15:36:00.000Z"
)

fun memberLeave(eventId: String = "eventId", members: List<Member> = listOf()) = Event.Conversation.MemberLeave(
eventId,
TestConversation.ID,
false,
TestUser.USER_ID,
listOf(),
"2022-03-30T15:36:00.000Z"
)

fun memberChange(eventId: String = "eventId", member: Member) = Event.Conversation.MemberChanged.MemberChangedRole(
eventId,
TestConversation.ID,
Expand Down Expand Up @@ -188,4 +195,30 @@ object TestEvent {
timestamp.toIsoDateTimeString(),
"content",
)

fun newConversationEvent() = Event.Conversation.NewConversation(
id = "eventId",
conversationId = TestConversation.ID,
transient = false,
timestampIso = "timestamp",
conversation = TestConversation.CONVERSATION_RESPONSE,
senderUserId = TestUser.SELF.id
)

fun newMLSWelcomeEvent() = Event.Conversation.MLSWelcome(
"eventId",
TestConversation.ID,
false,
TestUser.USER_ID,
"dummy-message",
timestampIso = "2022-03-30T15:36:00.000Z"
)

fun newAccessUpdateEvent() = Event.Conversation.AccessUpdate(
id = "eventId",
conversationId = TestConversation.ID,
data = TestConversation.CONVERSATION_RESPONSE,
qualifiedFrom = TestUser.USER_ID,
transient = false
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ import io.mockative.given
import io.mockative.mock
import io.mockative.once
import io.mockative.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.yield
import kotlin.test.Test

@OptIn(ExperimentalCoroutinesApi::class)
class MissingMetadataUpdateManagerTest {

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,194 @@

package com.wire.kalium.logic.sync

import com.wire.kalium.logic.data.session.SessionRepository
import com.wire.kalium.logic.data.sync.InMemoryIncrementalSyncRepository
import com.wire.kalium.logic.data.sync.SlowSyncRepositoryImpl
import app.cash.turbine.test
import com.wire.kalium.logic.CoreFailure
import com.wire.kalium.logic.data.sync.IncrementalSyncRepository
import com.wire.kalium.logic.data.sync.IncrementalSyncStatus
import com.wire.kalium.logic.data.sync.SlowSyncRepository
import com.wire.kalium.persistence.TestUserDatabase
import com.wire.kalium.persistence.dao.UserIDEntity
import com.wire.kalium.logic.data.sync.SlowSyncStatus
import com.wire.kalium.logic.data.sync.SlowSyncStep
import com.wire.kalium.logic.data.sync.SyncState
import com.wire.kalium.logic.test_util.TestKaliumDispatcher
import io.mockative.Mock
import io.mockative.classOf
import io.mockative.given
import io.mockative.mock
import kotlin.test.BeforeTest
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals

class ObserveSyncStateUseCaseTest {

private lateinit var slowSyncRepository: SlowSyncRepository
private lateinit var incrementalSyncRepository: IncrementalSyncRepository
private lateinit var observeSyncState: ObserveSyncStateUseCase
@Test
fun givenSlowSyncStatusEmitsFailedState_whenRunningUseCase_thenEmitFailedState() = runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncFailureState()
.withIncrementalSyncLiveState()
.arrange()

@Mock
val sessionRepository = mock(classOf<SessionRepository>())
useCase().test {
val item = awaitItem()
assertEquals(SyncState.Failed(coreFailure), item)
}
}

@Test
fun givenSlowSyncStatusEmitsOngoingState_whenRunningUseCase_thenEmitSlowSyncState() = runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncOngoingState()
.withIncrementalSyncLiveState()
.arrange()

useCase().test {
val item = awaitItem()
assertEquals(SyncState.SlowSync, item)
}
}

@Test
fun givenSlowSyncStatusEmitsPendingState_whenRunningUseCase_thenEmitWaitingState() = runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncPendingState()
.withIncrementalSyncLiveState()
.arrange()

useCase().test {
val item = awaitItem()
assertEquals(SyncState.Waiting, item)
}
}

@Test
fun givenIncrementalSyncStateEmitsLiveState_whenRunningUseCase_thenEmitLiveState() = runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncCompletedState()
.withIncrementalSyncLiveState()
.arrange()

useCase().test {
val item = awaitItem()
assertEquals(SyncState.Live, item)
}
}

@Test
fun givenIncrementalSyncStateEmitsFailedState_whenRunningUseCase_thenEmitFailedState() =
runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncCompletedState()
.withIncrementalSyncFailedState()
.arrange()

useCase().test {
val item = awaitItem()
assertEquals(SyncState.Failed(coreFailure), item)
}
}

@Test
fun givenIncrementalSyncStateEmitsFetchingPendingEventsState_whenRunningUseCase_thenEmitGatheringPendingEventsState() =
runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncCompletedState()
.withIncrementalSyncFetchingPendingEventsState()
.arrange()

useCase().test {
val item = awaitItem()
assertEquals(SyncState.GatheringPendingEvents, item)
}
}

@BeforeTest
fun setup() {
val database = TestUserDatabase(UserIDEntity("SELF_USER", "DOMAIN"))
slowSyncRepository = SlowSyncRepositoryImpl(database.builder.metadataDAO)
incrementalSyncRepository = InMemoryIncrementalSyncRepository()
observeSyncState = ObserveSyncStateUseCase(slowSyncRepository, incrementalSyncRepository)
@Test
fun givenIncrementalSyncStateEmitsPendingState_whenRunningUseCase_thenEmitGatheringPendingEventsState() =
runTest(TestKaliumDispatcher.default) {
val (_, useCase) = Arrangement()
.withSlowSyncCompletedState()
.withIncrementalSyncPendingState()
.arrange()

useCase().test {
val item = awaitItem()
assertEquals(SyncState.GatheringPendingEvents, item)
}
}

private class Arrangement {

@Mock
val slowSyncRepository: SlowSyncRepository = mock(SlowSyncRepository::class)

@Mock
val incrementalSyncRepository: IncrementalSyncRepository = mock(IncrementalSyncRepository::class)

fun arrange() = this to ObserveSyncStateUseCase(
slowSyncRepository = slowSyncRepository,
incrementalSyncRepository = incrementalSyncRepository
)

fun withSlowSyncFailureState() = apply {
given(slowSyncRepository)
.getter(slowSyncRepository::slowSyncStatus)
.whenInvoked()
.thenReturn(slowSyncFailureFlow)
}

fun withSlowSyncOngoingState() = apply {
given(slowSyncRepository)
.getter(slowSyncRepository::slowSyncStatus)
.whenInvoked()
.thenReturn(MutableStateFlow(SlowSyncStatus.Ongoing(SlowSyncStep.CONTACTS)).asStateFlow())
}

fun withSlowSyncPendingState() = apply {
given(slowSyncRepository)
.getter(slowSyncRepository::slowSyncStatus)
.whenInvoked()
.thenReturn(MutableStateFlow(SlowSyncStatus.Pending).asStateFlow())
}

fun withSlowSyncCompletedState() = apply {
given(slowSyncRepository)
.getter(slowSyncRepository::slowSyncStatus)
.whenInvoked()
.thenReturn(MutableStateFlow(SlowSyncStatus.Complete).asStateFlow())
}

fun withIncrementalSyncLiveState() = apply {
given(incrementalSyncRepository)
.getter(incrementalSyncRepository::incrementalSyncState)
.whenInvoked()
.thenReturn(flowOf(IncrementalSyncStatus.Live))
}

fun withIncrementalSyncFailedState() = apply {
given(incrementalSyncRepository)
.getter(incrementalSyncRepository::incrementalSyncState)
.whenInvoked()
.thenReturn(incrementalSyncFailureFlow)
}

fun withIncrementalSyncFetchingPendingEventsState() = apply {
given(incrementalSyncRepository)
.getter(incrementalSyncRepository::incrementalSyncState)
.whenInvoked()
.thenReturn(flowOf(IncrementalSyncStatus.FetchingPendingEvents))
}

fun withIncrementalSyncPendingState() = apply {
given(incrementalSyncRepository)
.getter(incrementalSyncRepository::incrementalSyncState)
.whenInvoked()
.thenReturn(flowOf(IncrementalSyncStatus.Pending))
}
}

// TODO(test): Add tests
companion object {
val coreFailure = CoreFailure.Unknown(null)
val slowSyncFailureFlow = MutableStateFlow(SlowSyncStatus.Failed(coreFailure)).asStateFlow()
val incrementalSyncFailureFlow = flowOf(IncrementalSyncStatus.Failed(coreFailure))
}
}
Loading

0 comments on commit f47c887

Please sign in to comment.