adding tests around marking room as read

- fixes wrong message instance being used for filtering
This commit is contained in:
Adam Brown 2022-11-06 18:31:59 +00:00
parent aab6170caa
commit 6dc98ef8d3
3 changed files with 77 additions and 13 deletions

View File

@ -5,9 +5,7 @@ import app.dapk.st.matrix.common.EventId
import app.dapk.st.matrix.common.RoomId import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.common.UserId import app.dapk.st.matrix.common.UserId
import app.dapk.st.matrix.room.RoomService import app.dapk.st.matrix.room.RoomService
import app.dapk.st.matrix.sync.RoomEvent
import app.dapk.st.matrix.sync.RoomStore import app.dapk.st.matrix.sync.RoomStore
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
@ -24,7 +22,7 @@ class ReadMarkingTimeline(
val credentials = credentialsStore.credentials()!! val credentials = credentialsStore.credentials()!!
roomStore.markRead(roomId) roomStore.markRead(roomId)
emit(credentials) emit(credentials)
}.flatMapMerge { credentials -> }.flatMapConcat { credentials ->
var lastKnownReadEvent: EventId? = null var lastKnownReadEvent: EventId? = null
observeTimelineUseCase.invoke(roomId, credentials.userId).distinctUntilChanged().onEach { state -> observeTimelineUseCase.invoke(roomId, credentials.userId).distinctUntilChanged().onEach { state ->
state.latestMessageEventFromOthers(self = credentials.userId)?.let { state.latestMessageEventFromOthers(self = credentials.userId)?.let {
@ -37,8 +35,9 @@ class ReadMarkingTimeline(
} }
} }
private suspend fun updateRoomReadStateAsync(latestReadEvent: EventId, state: MessengerPageState, isReadReceiptsDisabled: Boolean): Deferred<*> { @Suppress("DeferredResultUnused")
return coroutineScope { private suspend fun updateRoomReadStateAsync(latestReadEvent: EventId, state: MessengerPageState, isReadReceiptsDisabled: Boolean) {
coroutineScope {
async { async {
runCatching { runCatching {
roomService.markFullyRead(state.roomState.roomOverview.roomId, latestReadEvent, isPrivate = isReadReceiptsDisabled) roomService.markFullyRead(state.roomState.roomOverview.roomId, latestReadEvent, isPrivate = isReadReceiptsDisabled)
@ -48,10 +47,9 @@ class ReadMarkingTimeline(
} }
} }
} private fun MessengerPageState.latestMessageEventFromOthers(self: UserId) = this.roomState.events
.filterIsInstance<RoomEvent.Message>()
private fun MessengerPageState.latestMessageEventFromOthers(self: UserId) = this.roomState.events .filterNot { it.author.id == self }
.filterIsInstance<RoomEvent.Message>() .firstOrNull()
.filterNot { it.author.id == self } ?.eventId
.firstOrNull() }
?.eventId

View File

@ -0,0 +1,66 @@
package app.dapk.st.engine
import app.dapk.st.matrix.common.RoomId
import app.dapk.st.matrix.common.UserId
import fake.FakeCredentialsStore
import fake.FakeRoomStore
import fixture.*
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import org.amshove.kluent.shouldBeEqualTo
import org.junit.Test
import test.delegateReturn
import test.runExpectTest
private val A_ROOM_ID = aRoomId()
private val A_USER_CREDENTIALS = aUserCredentials()
private val A_ROOM_MESSAGE_FROM_OTHER_USER = aRoomMessageEvent(author = aRoomMember(id = aUserId("another-user")))
private val A_ROOM_MESSAGE_FROM_SELF = aRoomMessageEvent(author = aRoomMember(id = A_USER_CREDENTIALS.userId))
private val READ_RECEIPTS_ARE_DISABLED = true
class ReadMarkingTimelineTest {
private val fakeRoomStore = FakeRoomStore()
private val fakeCredentialsStore = FakeCredentialsStore().apply { givenCredentials().returns(A_USER_CREDENTIALS) }
private val fakeObserveTimelineUseCase = FakeObserveTimelineUseCase()
private val fakeRoomService = FakeRoomService()
private val readMarkingTimeline = ReadMarkingTimeline(
fakeRoomStore,
fakeCredentialsStore,
fakeObserveTimelineUseCase,
fakeRoomService,
)
@Test
fun `given a message from self, when fetching, then only marks room as read on initial launch`() = runExpectTest {
fakeRoomStore.expectUnit(times = 1) { it.markRead(A_ROOM_ID) }
val messengerState = aMessengerState(roomState = aRoomState(events = listOf(A_ROOM_MESSAGE_FROM_SELF)))
fakeObserveTimelineUseCase.given(A_ROOM_ID, A_USER_CREDENTIALS.userId).returns(flowOf(messengerState))
val result = readMarkingTimeline.fetch(A_ROOM_ID, isReadReceiptsDisabled = READ_RECEIPTS_ARE_DISABLED).first()
result shouldBeEqualTo messengerState
verifyExpects()
}
@Test
fun `given a message from other user, when fetching, then marks room as read`() = runExpectTest {
fakeRoomStore.expectUnit(times = 2) { it.markRead(A_ROOM_ID) }
fakeRoomService.expectUnit { it.markFullyRead(A_ROOM_ID, A_ROOM_MESSAGE_FROM_OTHER_USER.eventId, isPrivate = READ_RECEIPTS_ARE_DISABLED) }
val messengerState = aMessengerState(roomState = aRoomState(events = listOf(A_ROOM_MESSAGE_FROM_OTHER_USER)))
fakeObserveTimelineUseCase.given(A_ROOM_ID, A_USER_CREDENTIALS.userId).returns(flowOf(messengerState))
val result = readMarkingTimeline.fetch(A_ROOM_ID, isReadReceiptsDisabled = READ_RECEIPTS_ARE_DISABLED).first()
result shouldBeEqualTo messengerState
verifyExpects()
}
}
class FakeObserveTimelineUseCase : ObserveTimelineUseCase by mockk() {
fun given(roomId: RoomId, userId: UserId) = every { this@FakeObserveTimelineUseCase.invoke(roomId, userId) }.delegateReturn()
}

View File

@ -136,7 +136,7 @@ class FakeRoomService : RoomService by mockk() {
fun aMessengerState( fun aMessengerState(
self: UserId = aUserId(), self: UserId = aUserId(),
roomState: app.dapk.st.engine.RoomState, roomState: app.dapk.st.engine.RoomState = aRoomState(),
typing: Typing? = null, typing: Typing? = null,
isMuted: Boolean = IS_ROOM_MUTED, isMuted: Boolean = IS_ROOM_MUTED,
) = MessengerPageState(self, roomState, typing, isMuted) ) = MessengerPageState(self, roomState, typing, isMuted)