Add unit test on RustNotificationService

And fix mapping error.
This commit is contained in:
Benoit Marty 2024-09-19 18:26:36 +02:00
parent 145c40ddfa
commit 6fa585f4c8
15 changed files with 242 additions and 50 deletions

View file

@ -140,7 +140,7 @@ class RustMatrixClient(
)
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(syncService)
private val notificationClient = runBlocking { client.notificationClient(notificationProcessSetup) }
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
private val notificationService = RustNotificationService(notificationClient, dispatchers, clock)
private val notificationSettingsService = RustNotificationSettingsService(client, dispatchers)
.apply { start() }
private val encryptionService = RustEncryptionService(

View file

@ -10,10 +10,9 @@ package io.element.android.libraries.matrix.impl.notification
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.notification.NotificationContent
import io.element.android.libraries.matrix.api.notification.NotificationData
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.isDm
import io.element.android.services.toolbox.api.systemclock.SystemClock
import org.matrix.rustcomponents.sdk.NotificationEvent
@ -21,10 +20,9 @@ import org.matrix.rustcomponents.sdk.NotificationItem
import org.matrix.rustcomponents.sdk.use
class NotificationMapper(
sessionId: SessionId,
private val clock: SystemClock,
) {
private val notificationContentMapper = NotificationContentMapper(sessionId)
private val notificationContentMapper = NotificationContentMapper()
fun map(
eventId: EventId,
@ -56,15 +54,14 @@ class NotificationMapper(
}
}
class NotificationContentMapper(private val sessionId: SessionId) {
class NotificationContentMapper {
private val timelineEventToNotificationContentMapper = TimelineEventToNotificationContentMapper()
fun map(notificationEvent: NotificationEvent): NotificationContent =
when (notificationEvent) {
is NotificationEvent.Timeline -> timelineEventToNotificationContentMapper.map(notificationEvent.event)
is NotificationEvent.Invite -> NotificationContent.StateEvent.RoomMemberContent(
userId = sessionId.value,
membershipState = RoomMembershipState.INVITE,
is NotificationEvent.Invite -> NotificationContent.Invite(
senderId = UserId(notificationEvent.sender),
)
}
}

View file

@ -10,7 +10,6 @@ package io.element.android.libraries.matrix.impl.notification
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.notification.NotificationData
import io.element.android.libraries.matrix.api.notification.NotificationService
import io.element.android.services.toolbox.api.systemclock.SystemClock
@ -19,15 +18,13 @@ import org.matrix.rustcomponents.sdk.NotificationClient
import org.matrix.rustcomponents.sdk.use
class RustNotificationService(
sessionId: SessionId,
private val notificationClient: NotificationClient,
private val dispatchers: CoroutineDispatchers,
clock: SystemClock,
) : NotificationService {
private val notificationMapper: NotificationMapper = NotificationMapper(sessionId, clock)
private val notificationMapper: NotificationMapper = NotificationMapper(clock)
override suspend fun getNotification(
userId: SessionId,
roomId: RoomId,
eventId: EventId,
): Result<NotificationData?> = withContext(dispatchers.io) {

View file

@ -51,7 +51,10 @@ private fun StateEventContent.toContent(): NotificationContent.StateEvent {
StateEventContent.RoomHistoryVisibility -> NotificationContent.StateEvent.RoomHistoryVisibility
StateEventContent.RoomJoinRules -> NotificationContent.StateEvent.RoomJoinRules
is StateEventContent.RoomMemberContent -> {
NotificationContent.StateEvent.RoomMemberContent(userId, RoomMemberMapper.mapMembership(membershipState))
NotificationContent.StateEvent.RoomMemberContent(
userId = UserId(userId),
membershipState = RoomMemberMapper.mapMembership(membershipState),
)
}
StateEventContent.RoomName -> NotificationContent.StateEvent.RoomName
StateEventContent.RoomPinnedEvents -> NotificationContent.StateEvent.RoomPinnedEvents

View file

@ -0,0 +1,63 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.fixtures.factories
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineEvent
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_USER_NAME
import org.matrix.rustcomponents.sdk.NotificationEvent
import org.matrix.rustcomponents.sdk.NotificationItem
import org.matrix.rustcomponents.sdk.NotificationRoomInfo
import org.matrix.rustcomponents.sdk.NotificationSenderInfo
import org.matrix.rustcomponents.sdk.TimelineEvent
fun aRustNotificationItem(
event: NotificationEvent = aRustNotificationEventTimeline(),
senderInfo: NotificationSenderInfo = aRustNotificationSenderInfo(),
roomInfo: NotificationRoomInfo = aRustNotificationRoomInfo(),
isNoisy: Boolean? = false,
hasMention: Boolean? = false,
) = NotificationItem(
event = event,
senderInfo = senderInfo,
roomInfo = roomInfo,
isNoisy = isNoisy,
hasMention = hasMention,
)
fun aRustNotificationSenderInfo(
displayName: String? = A_USER_NAME,
avatarUrl: String? = null,
isNameAmbiguous: Boolean = false,
) = NotificationSenderInfo(
displayName = displayName,
avatarUrl = avatarUrl,
isNameAmbiguous = isNameAmbiguous,
)
fun aRustNotificationRoomInfo(
displayName: String = A_ROOM_NAME,
avatarUrl: String? = null,
canonicalAlias: String? = null,
joinedMembersCount: ULong = 2u,
isEncrypted: Boolean? = true,
isDirect: Boolean = false,
) = NotificationRoomInfo(
displayName = displayName,
avatarUrl = avatarUrl,
canonicalAlias = canonicalAlias,
joinedMembersCount = joinedMembersCount,
isEncrypted = isEncrypted,
isDirect = isDirect,
)
fun aRustNotificationEventTimeline(
event: TimelineEvent = FakeRustTimelineEvent(),
) = NotificationEvent.Timeline(
event = event,
)

View file

@ -0,0 +1,45 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.fixtures.factories
import io.element.android.libraries.matrix.test.A_MESSAGE
import org.matrix.rustcomponents.sdk.FormattedBody
import org.matrix.rustcomponents.sdk.MessageLikeEventContent
import org.matrix.rustcomponents.sdk.MessageType
import org.matrix.rustcomponents.sdk.TextMessageContent
import org.matrix.rustcomponents.sdk.TimelineEventType
fun aRustTimelineEventTypeMessageLike(
content: MessageLikeEventContent = aRustMessageLikeEventContentRoomMessage(),
): TimelineEventType.MessageLike {
return TimelineEventType.MessageLike(
content = content,
)
}
fun aRustMessageLikeEventContentRoomMessage(
messageType: MessageType = aRustMessageTypeText(),
inReplyToEventId: String? = null,
) = MessageLikeEventContent.RoomMessage(
messageType = messageType,
inReplyToEventId = inReplyToEventId,
)
fun aRustMessageTypeText(
content: TextMessageContent = aRustTextMessageContent(),
) = MessageType.Text(
content = content,
)
fun aRustTextMessageContent(
body: String = A_MESSAGE,
formatted: FormattedBody? = null,
) = TextMessageContent(
body = body,
formatted = formatted,
)

View file

@ -7,7 +7,15 @@
package io.element.android.libraries.matrix.impl.fixtures.fakes
import io.element.android.tests.testutils.simulateLongTask
import org.matrix.rustcomponents.sdk.NoPointer
import org.matrix.rustcomponents.sdk.NotificationClient
import org.matrix.rustcomponents.sdk.NotificationItem
class FakeRustNotificationClient : NotificationClient(NoPointer)
class FakeRustNotificationClient(
var notificationItemResult: NotificationItem? = null
) : NotificationClient(NoPointer) {
override suspend fun getNotification(roomId: String, eventId: String): NotificationItem? = simulateLongTask {
notificationItemResult
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.fixtures.fakes
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustTimelineEventTypeMessageLike
import io.element.android.libraries.matrix.test.A_USER_ID_2
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
import org.matrix.rustcomponents.sdk.NoPointer
import org.matrix.rustcomponents.sdk.TimelineEvent
import org.matrix.rustcomponents.sdk.TimelineEventType
class FakeRustTimelineEvent(
val timestamp: ULong = A_FAKE_TIMESTAMP.toULong(),
val timelineEventType: TimelineEventType = aRustTimelineEventTypeMessageLike(),
val senderId: String = A_USER_ID_2.value,
) : TimelineEvent(NoPointer) {
override fun timestamp(): ULong = timestamp
override fun eventType(): TimelineEventType = timelineEventType
override fun senderId(): String = senderId
}

View file

@ -0,0 +1,58 @@
/*
* Copyright 2024 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only
* Please see LICENSE in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.notification
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.notification.NotificationContent
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustNotificationItem
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustNotificationClient
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_MESSAGE
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_USER_ID_2
import io.element.android.services.toolbox.api.systemclock.SystemClock
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.matrix.rustcomponents.sdk.NotificationClient
class RustNotificationServiceTest {
@Test
fun test() = runTest {
val notificationClient = FakeRustNotificationClient(
notificationItemResult = aRustNotificationItem(),
)
val sut = createRustNotificationService(
notificationClient = notificationClient,
)
val result = sut.getNotification(A_ROOM_ID, AN_EVENT_ID).getOrThrow()!!
assertThat(result.isEncrypted).isTrue()
assertThat(result.content).isEqualTo(
NotificationContent.MessageLike.RoomMessage(
senderId = A_USER_ID_2,
messageType = TextMessageType(
body = A_MESSAGE,
formatted = null,
)
)
)
}
private fun TestScope.createRustNotificationService(
notificationClient: NotificationClient = FakeRustNotificationClient(),
clock: SystemClock = FakeSystemClock(),
) =
RustNotificationService(
notificationClient = notificationClient,
dispatchers = testCoroutineDispatchers(),
clock = clock,
)
}