Merge pull request #4889 from element-hq/feature/bma/genericNotification
Show generic notification when Event cannot be resolved
This commit is contained in:
commit
5ee33a8d16
17 changed files with 197 additions and 12 deletions
|
|
@ -59,6 +59,7 @@ class DefaultClearCacheUseCase @Inject constructor(
|
||||||
seenInvitesStore.clear()
|
seenInvitesStore.clear()
|
||||||
// Ensure any error will be displayed again
|
// Ensure any error will be displayed again
|
||||||
pushService.setIgnoreRegistrationError(matrixClient.sessionId, false)
|
pushService.setIgnoreRegistrationError(matrixClient.sessionId, false)
|
||||||
|
pushService.resetBatteryOptimizationState()
|
||||||
// Ensure the app is restarted
|
// Ensure the app is restarted
|
||||||
defaultCacheService.onClearedCache(matrixClient.sessionId)
|
defaultCacheService.onClearedCache(matrixClient.sessionId)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,10 @@ class DefaultClearCacheUseCaseTest {
|
||||||
resetLambda = resetFtueLambda,
|
resetLambda = resetFtueLambda,
|
||||||
)
|
)
|
||||||
val setIgnoreRegistrationErrorLambda = lambdaRecorder<SessionId, Boolean, Unit> { _, _ -> }
|
val setIgnoreRegistrationErrorLambda = lambdaRecorder<SessionId, Boolean, Unit> { _, _ -> }
|
||||||
|
val resetBatteryOptimizationStateResult = lambdaRecorder<Unit> { }
|
||||||
val pushService = FakePushService(
|
val pushService = FakePushService(
|
||||||
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda
|
setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
|
||||||
|
resetBatteryOptimizationStateResult = resetBatteryOptimizationStateResult,
|
||||||
)
|
)
|
||||||
val seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID))
|
val seenInvitesStore = InMemorySeenInvitesStore(setOf(A_ROOM_ID))
|
||||||
assertThat(seenInvitesStore.seenRoomIds().first()).isNotEmpty()
|
assertThat(seenInvitesStore.seenRoomIds().first()).isNotEmpty()
|
||||||
|
|
@ -68,6 +70,7 @@ class DefaultClearCacheUseCaseTest {
|
||||||
resetFtueLambda.assertions().isCalledOnce()
|
resetFtueLambda.assertions().isCalledOnce()
|
||||||
setIgnoreRegistrationErrorLambda.assertions().isCalledOnce()
|
setIgnoreRegistrationErrorLambda.assertions().isCalledOnce()
|
||||||
.with(value(matrixClient.sessionId), value(false))
|
.with(value(matrixClient.sessionId), value(false))
|
||||||
|
resetBatteryOptimizationStateResult.assertions().isCalledOnce()
|
||||||
assertThat(awaitItem()).isEqualTo(matrixClient.sessionId)
|
assertThat(awaitItem()).isEqualTo(matrixClient.sessionId)
|
||||||
assertThat(seenInvitesStore.seenRoomIds().first()).isEmpty()
|
assertThat(seenInvitesStore.seenRoomIds().first()).isEmpty()
|
||||||
assertThat(activeRoomsHolder.getActiveRoom(A_SESSION_ID)).isNull()
|
assertThat(activeRoomsHolder.getActiveRoom(A_SESSION_ID)).isNull()
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ sealed interface NotificationContent {
|
||||||
) : MessageLike
|
) : MessageLike
|
||||||
|
|
||||||
data object RoomEncrypted : MessageLike
|
data object RoomEncrypted : MessageLike
|
||||||
|
data object UnableToResolve : MessageLike
|
||||||
data class RoomMessage(
|
data class RoomMessage(
|
||||||
val senderId: UserId,
|
val senderId: UserId,
|
||||||
val messageType: MessageType
|
val messageType: MessageType
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
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.RoomId
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
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.notification.NotificationData
|
||||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
|
|
@ -24,7 +25,7 @@ class RustNotificationService(
|
||||||
private val sessionId: SessionId,
|
private val sessionId: SessionId,
|
||||||
private val notificationClient: NotificationClient,
|
private val notificationClient: NotificationClient,
|
||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
clock: SystemClock,
|
private val clock: SystemClock,
|
||||||
) : NotificationService {
|
) : NotificationService {
|
||||||
private val notificationMapper: NotificationMapper = NotificationMapper(clock)
|
private val notificationMapper: NotificationMapper = NotificationMapper(clock)
|
||||||
|
|
||||||
|
|
@ -43,11 +44,32 @@ class RustNotificationService(
|
||||||
val eventIds = requests.flatMap { it.eventIds }
|
val eventIds = requests.flatMap { it.eventIds }
|
||||||
for (eventId in eventIds) {
|
for (eventId in eventIds) {
|
||||||
val item = items[eventId]
|
val item = items[eventId]
|
||||||
|
val roomId = RoomId(requests.find { it.eventIds.contains(eventId) }?.roomId!!)
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
val roomId = RoomId(requests.find { it.eventIds.contains(eventId) }?.roomId!!)
|
|
||||||
put(EventId(eventId), notificationMapper.map(sessionId, EventId(eventId), roomId, item))
|
put(EventId(eventId), notificationMapper.map(sessionId, EventId(eventId), roomId, item))
|
||||||
} else {
|
} else {
|
||||||
Timber.e("Could not retrieve event for notification with $eventId")
|
Timber.e("Could not retrieve event for notification with $eventId")
|
||||||
|
put(
|
||||||
|
EventId(eventId),
|
||||||
|
NotificationData(
|
||||||
|
sessionId = sessionId,
|
||||||
|
eventId = EventId(eventId),
|
||||||
|
threadId = null,
|
||||||
|
roomId = roomId,
|
||||||
|
senderAvatarUrl = null,
|
||||||
|
senderDisplayName = null,
|
||||||
|
senderIsNameAmbiguous = false,
|
||||||
|
roomAvatarUrl = null,
|
||||||
|
roomDisplayName = null,
|
||||||
|
isDirect = false,
|
||||||
|
isDm = false,
|
||||||
|
isEncrypted = false,
|
||||||
|
isNoisy = false,
|
||||||
|
timestamp = clock.epochMillis(),
|
||||||
|
content = NotificationContent.MessageLike.UnableToResolve,
|
||||||
|
hasMention = false
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,11 @@ import org.matrix.rustcomponents.sdk.NotificationItemsRequest
|
||||||
|
|
||||||
class FakeFfiNotificationClient(
|
class FakeFfiNotificationClient(
|
||||||
var notificationItemResult: Map<String, NotificationItem> = emptyMap(),
|
var notificationItemResult: Map<String, NotificationItem> = emptyMap(),
|
||||||
|
val closeResult: () -> Unit = { }
|
||||||
) : NotificationClient(NoPointer) {
|
) : NotificationClient(NoPointer) {
|
||||||
override suspend fun getNotifications(requests: List<NotificationItemsRequest>): Map<String, NotificationItem> {
|
override suspend fun getNotifications(requests: List<NotificationItemsRequest>): Map<String, NotificationItem> {
|
||||||
return notificationItemResult
|
return notificationItemResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun close() = closeResult()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
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.api.systemclock.SystemClock
|
||||||
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -47,6 +48,33 @@ class RustNotificationServiceTest {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test unable to resolve event`() = runTest {
|
||||||
|
val notificationClient = FakeFfiNotificationClient(
|
||||||
|
notificationItemResult = emptyMap(),
|
||||||
|
)
|
||||||
|
val sut = createRustNotificationService(
|
||||||
|
notificationClient = notificationClient,
|
||||||
|
)
|
||||||
|
val result = sut.getNotifications(mapOf(A_ROOM_ID to listOf(AN_EVENT_ID))).getOrThrow()[AN_EVENT_ID]!!
|
||||||
|
assertThat(result.content).isEqualTo(
|
||||||
|
NotificationContent.MessageLike.UnableToResolve
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `close should invoke the close method of the service`() = runTest {
|
||||||
|
val closeResult = lambdaRecorder<Unit> { }
|
||||||
|
val notificationClient = FakeFfiNotificationClient(
|
||||||
|
closeResult = closeResult,
|
||||||
|
)
|
||||||
|
val sut = createRustNotificationService(
|
||||||
|
notificationClient = notificationClient,
|
||||||
|
)
|
||||||
|
sut.close()
|
||||||
|
closeResult.assertions().isCalledOnce()
|
||||||
|
}
|
||||||
|
|
||||||
private fun TestScope.createRustNotificationService(
|
private fun TestScope.createRustNotificationService(
|
||||||
notificationClient: NotificationClient = FakeFfiNotificationClient(),
|
notificationClient: NotificationClient = FakeFfiNotificationClient(),
|
||||||
clock: SystemClock = FakeSystemClock(),
|
clock: SystemClock = FakeSystemClock(),
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,9 @@ interface PushService {
|
||||||
* Reset the push history, including the push counter.
|
* Reset the push history, including the push counter.
|
||||||
*/
|
*/
|
||||||
suspend fun resetPushHistory()
|
suspend fun resetPushHistory()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the battery optimization state.
|
||||||
|
*/
|
||||||
|
suspend fun resetBatteryOptimizationState()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.push.api.GetCurrentPushProvider
|
import io.element.android.libraries.push.api.GetCurrentPushProvider
|
||||||
import io.element.android.libraries.push.api.PushService
|
import io.element.android.libraries.push.api.PushService
|
||||||
import io.element.android.libraries.push.api.history.PushHistoryItem
|
import io.element.android.libraries.push.api.history.PushHistoryItem
|
||||||
|
import io.element.android.libraries.push.impl.push.MutableBatteryOptimizationStore
|
||||||
import io.element.android.libraries.push.impl.store.PushDataStore
|
import io.element.android.libraries.push.impl.store.PushDataStore
|
||||||
import io.element.android.libraries.push.impl.test.TestPush
|
import io.element.android.libraries.push.impl.test.TestPush
|
||||||
import io.element.android.libraries.pushproviders.api.Distributor
|
import io.element.android.libraries.pushproviders.api.Distributor
|
||||||
|
|
@ -37,6 +38,7 @@ class DefaultPushService @Inject constructor(
|
||||||
private val sessionObserver: SessionObserver,
|
private val sessionObserver: SessionObserver,
|
||||||
private val pushClientSecretStore: PushClientSecretStore,
|
private val pushClientSecretStore: PushClientSecretStore,
|
||||||
private val pushDataStore: PushDataStore,
|
private val pushDataStore: PushDataStore,
|
||||||
|
private val mutableBatteryOptimizationStore: MutableBatteryOptimizationStore,
|
||||||
) : PushService, SessionListener {
|
) : PushService, SessionListener {
|
||||||
init {
|
init {
|
||||||
observeSessions()
|
observeSessions()
|
||||||
|
|
@ -138,4 +140,8 @@ class DefaultPushService @Inject constructor(
|
||||||
override suspend fun resetPushHistory() {
|
override suspend fun resetPushHistory() {
|
||||||
pushDataStore.reset()
|
pushDataStore.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun resetBatteryOptimizationState() {
|
||||||
|
mutableBatteryOptimizationStore.reset()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,11 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
val fallbackNotifiableEvent = fallbackNotifiableEvent(userId, roomId, eventId)
|
val fallbackNotifiableEvent = fallbackNotifiableEvent(userId, roomId, eventId)
|
||||||
ResolvedPushEvent.Event(fallbackNotifiableEvent)
|
ResolvedPushEvent.Event(fallbackNotifiableEvent)
|
||||||
}
|
}
|
||||||
|
NotificationContent.MessageLike.UnableToResolve -> {
|
||||||
|
Timber.tag(loggerTag.value).w("Unable to resolve notification -> fallback")
|
||||||
|
val fallbackNotifiableEvent = fallbackNotifiableEvent(userId, roomId, eventId)
|
||||||
|
ResolvedPushEvent.Event(fallbackNotifiableEvent)
|
||||||
|
}
|
||||||
is NotificationContent.MessageLike.RoomRedaction -> {
|
is NotificationContent.MessageLike.RoomRedaction -> {
|
||||||
// Note: this case will be handled below
|
// Note: this case will be handled below
|
||||||
val redactedEventId = content.redactedEventId
|
val redactedEventId = content.redactedEventId
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import io.element.android.libraries.push.impl.history.onUnableToRetrieveSession
|
||||||
import io.element.android.libraries.push.impl.notifications.NotificationEventRequest
|
import io.element.android.libraries.push.impl.notifications.NotificationEventRequest
|
||||||
import io.element.android.libraries.push.impl.notifications.NotificationResolverQueue
|
import io.element.android.libraries.push.impl.notifications.NotificationResolverQueue
|
||||||
import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels
|
import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels
|
||||||
|
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
||||||
|
|
@ -87,13 +88,24 @@ class DefaultPushHandler @Inject constructor(
|
||||||
} else {
|
} else {
|
||||||
result.fold(
|
result.fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
pushHistoryService.onSuccess(
|
if (it is ResolvedPushEvent.Event && it.notifiableEvent is FallbackNotifiableEvent) {
|
||||||
providerInfo = request.providerInfo,
|
pushHistoryService.onUnableToResolveEvent(
|
||||||
eventId = request.eventId,
|
providerInfo = request.providerInfo,
|
||||||
roomId = request.roomId,
|
eventId = request.eventId,
|
||||||
sessionId = request.sessionId,
|
roomId = request.roomId,
|
||||||
comment = "Push handled successfully",
|
sessionId = request.sessionId,
|
||||||
)
|
reason = "Showing fallback notification",
|
||||||
|
)
|
||||||
|
mutableBatteryOptimizationStore.showBatteryOptimizationBanner()
|
||||||
|
} else {
|
||||||
|
pushHistoryService.onSuccess(
|
||||||
|
providerInfo = request.providerInfo,
|
||||||
|
eventId = request.eventId,
|
||||||
|
roomId = request.roomId,
|
||||||
|
sessionId = request.sessionId,
|
||||||
|
comment = "Push handled successfully",
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onFailure = { exception ->
|
onFailure = { exception ->
|
||||||
pushHistoryService.onUnableToResolveEvent(
|
pushHistoryService.onUnableToResolveEvent(
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import javax.inject.Inject
|
||||||
interface MutableBatteryOptimizationStore {
|
interface MutableBatteryOptimizationStore {
|
||||||
suspend fun showBatteryOptimizationBanner()
|
suspend fun showBatteryOptimizationBanner()
|
||||||
suspend fun onOptimizationBannerDismissed()
|
suspend fun onOptimizationBannerDismissed()
|
||||||
|
suspend fun reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
|
|
@ -28,4 +29,8 @@ class DefaultMutableBatteryOptimizationStore @Inject constructor(
|
||||||
override suspend fun onOptimizationBannerDismissed() {
|
override suspend fun onOptimizationBannerDismissed() {
|
||||||
defaultPushDataStore.setBatteryOptimizationBannerState(DefaultPushDataStore.BATTERY_OPTIMIZATION_BANNER_STATE_DISMISSED)
|
defaultPushDataStore.setBatteryOptimizationBannerState(DefaultPushDataStore.BATTERY_OPTIMIZATION_BANNER_STATE_DISMISSED)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun reset() {
|
||||||
|
defaultPushDataStore.setBatteryOptimizationBannerState(DefaultPushDataStore.BATTERY_OPTIMIZATION_BANNER_STATE_INIT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<item quantity="one">"%d notification"</item>
|
<item quantity="one">"%d notification"</item>
|
||||||
<item quantity="other">"%d notifications"</item>
|
<item quantity="other">"%d notifications"</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="notification_fallback_content">"Notification"</string>
|
<string name="notification_fallback_content">"You have new messages."</string>
|
||||||
<string name="notification_incoming_call">"📹 Incoming call"</string>
|
<string name="notification_incoming_call">"📹 Incoming call"</string>
|
||||||
<string name="notification_inline_reply_failed">"** Failed to send - please open room"</string>
|
<string name="notification_inline_reply_failed">"** Failed to send - please open room"</string>
|
||||||
<string name="notification_invitation_action_join">"Join"</string>
|
<string name="notification_invitation_action_join">"Join"</string>
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,19 @@
|
||||||
|
|
||||||
package io.element.android.libraries.push.impl
|
package io.element.android.libraries.push.impl
|
||||||
|
|
||||||
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||||
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.push.api.GetCurrentPushProvider
|
import io.element.android.libraries.push.api.GetCurrentPushProvider
|
||||||
|
import io.element.android.libraries.push.api.history.PushHistoryItem
|
||||||
|
import io.element.android.libraries.push.impl.push.FakeMutableBatteryOptimizationStore
|
||||||
|
import io.element.android.libraries.push.impl.push.MutableBatteryOptimizationStore
|
||||||
import io.element.android.libraries.push.impl.store.InMemoryPushDataStore
|
import io.element.android.libraries.push.impl.store.InMemoryPushDataStore
|
||||||
import io.element.android.libraries.push.impl.store.PushDataStore
|
import io.element.android.libraries.push.impl.store.PushDataStore
|
||||||
import io.element.android.libraries.push.impl.test.FakeTestPush
|
import io.element.android.libraries.push.impl.test.FakeTestPush
|
||||||
|
|
@ -283,6 +289,53 @@ class DefaultPushServiceTest {
|
||||||
assertThat(userPushStore.getPushProviderName()).isEqualTo(aPushProvider.name)
|
assertThat(userPushStore.getPushProviderName()).isEqualTo(aPushProvider.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resetBatteryOptimizationState invokes the store method`() = runTest {
|
||||||
|
val resetResult = lambdaRecorder<Unit> { }
|
||||||
|
val defaultPushService = createDefaultPushService(
|
||||||
|
mutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore(
|
||||||
|
resetResult = resetResult,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
defaultPushService.resetBatteryOptimizationState()
|
||||||
|
resetResult.assertions().isCalledOnce()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resetPushHistory invokes the store method`() = runTest {
|
||||||
|
val resetResult = lambdaRecorder<Unit> { }
|
||||||
|
val defaultPushService = createDefaultPushService(
|
||||||
|
pushDataStore = InMemoryPushDataStore(
|
||||||
|
resetResult = resetResult
|
||||||
|
),
|
||||||
|
)
|
||||||
|
defaultPushService.resetPushHistory()
|
||||||
|
resetResult.assertions().isCalledOnce()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getPushHistoryItemsFlow invokes the store method`() = runTest {
|
||||||
|
val store = InMemoryPushDataStore()
|
||||||
|
val aPushHistoryItem = PushHistoryItem(
|
||||||
|
pushDate = 0L,
|
||||||
|
formattedDate = "formattedDate",
|
||||||
|
providerInfo = "providerInfo",
|
||||||
|
eventId = AN_EVENT_ID,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
sessionId = A_SESSION_ID,
|
||||||
|
hasBeenResolved = false,
|
||||||
|
comment = null,
|
||||||
|
)
|
||||||
|
val defaultPushService = createDefaultPushService(
|
||||||
|
pushDataStore = store,
|
||||||
|
)
|
||||||
|
defaultPushService.getPushHistoryItemsFlow().test {
|
||||||
|
assertThat(awaitItem().isEmpty()).isTrue()
|
||||||
|
store.emitPushHistoryItems(listOf(aPushHistoryItem))
|
||||||
|
assertThat(awaitItem().first()).isEqualTo(aPushHistoryItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun createDefaultPushService(
|
private fun createDefaultPushService(
|
||||||
testPush: TestPush = FakeTestPush(),
|
testPush: TestPush = FakeTestPush(),
|
||||||
userPushStoreFactory: UserPushStoreFactory = FakeUserPushStoreFactory(),
|
userPushStoreFactory: UserPushStoreFactory = FakeUserPushStoreFactory(),
|
||||||
|
|
@ -291,6 +344,7 @@ class DefaultPushServiceTest {
|
||||||
sessionObserver: SessionObserver = NoOpSessionObserver(),
|
sessionObserver: SessionObserver = NoOpSessionObserver(),
|
||||||
pushClientSecretStore: PushClientSecretStore = InMemoryPushClientSecretStore(),
|
pushClientSecretStore: PushClientSecretStore = InMemoryPushClientSecretStore(),
|
||||||
pushDataStore: PushDataStore = InMemoryPushDataStore(),
|
pushDataStore: PushDataStore = InMemoryPushDataStore(),
|
||||||
|
mutableBatteryOptimizationStore: MutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore(),
|
||||||
): DefaultPushService {
|
): DefaultPushService {
|
||||||
return DefaultPushService(
|
return DefaultPushService(
|
||||||
testPush = testPush,
|
testPush = testPush,
|
||||||
|
|
@ -300,6 +354,7 @@ class DefaultPushServiceTest {
|
||||||
sessionObserver = sessionObserver,
|
sessionObserver = sessionObserver,
|
||||||
pushClientSecretStore = pushClientSecretStore,
|
pushClientSecretStore = pushClientSecretStore,
|
||||||
pushDataStore = pushDataStore,
|
pushDataStore = pushDataStore,
|
||||||
|
mutableBatteryOptimizationStore = mutableBatteryOptimizationStore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -608,7 +608,32 @@ class DefaultNotifiableEventResolverTest {
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
eventId = AN_EVENT_ID,
|
eventId = AN_EVENT_ID,
|
||||||
editedEventId = null,
|
editedEventId = null,
|
||||||
description = "Notification",
|
description = "You have new messages.",
|
||||||
|
canBeReplaced = true,
|
||||||
|
isRedacted = false,
|
||||||
|
isUpdated = false,
|
||||||
|
timestamp = A_FAKE_TIMESTAMP,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve UnableToResolve`() = runTest {
|
||||||
|
val sut = createDefaultNotifiableEventResolver(
|
||||||
|
notificationResult = Result.success(
|
||||||
|
mapOf(AN_EVENT_ID to aNotificationData(content = NotificationContent.MessageLike.UnableToResolve))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase")
|
||||||
|
val result = sut.resolveEvents(A_SESSION_ID, listOf(request))
|
||||||
|
val expectedResult = ResolvedPushEvent.Event(
|
||||||
|
FallbackNotifiableEvent(
|
||||||
|
sessionId = A_SESSION_ID,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
eventId = AN_EVENT_ID,
|
||||||
|
editedEventId = null,
|
||||||
|
description = "You have new messages.",
|
||||||
canBeReplaced = true,
|
canBeReplaced = true,
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
class FakeMutableBatteryOptimizationStore(
|
class FakeMutableBatteryOptimizationStore(
|
||||||
private val showBatteryOptimizationBannerResult: () -> Unit = { lambdaError() },
|
private val showBatteryOptimizationBannerResult: () -> Unit = { lambdaError() },
|
||||||
private val onOptimizationBannerDismissedResult: () -> Unit = { lambdaError() },
|
private val onOptimizationBannerDismissedResult: () -> Unit = { lambdaError() },
|
||||||
|
private val resetResult: () -> Unit = { lambdaError() },
|
||||||
) : MutableBatteryOptimizationStore {
|
) : MutableBatteryOptimizationStore {
|
||||||
override suspend fun showBatteryOptimizationBanner() {
|
override suspend fun showBatteryOptimizationBanner() {
|
||||||
showBatteryOptimizationBannerResult()
|
showBatteryOptimizationBannerResult()
|
||||||
|
|
@ -20,4 +21,8 @@ class FakeMutableBatteryOptimizationStore(
|
||||||
override suspend fun onOptimizationBannerDismissed() {
|
override suspend fun onOptimizationBannerDismissed() {
|
||||||
onOptimizationBannerDismissedResult()
|
onOptimizationBannerDismissedResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun reset() {
|
||||||
|
resetResult()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,10 @@ class InMemoryPushDataStore(
|
||||||
return mutablePushHistoryItemsFlow.asStateFlow()
|
return mutablePushHistoryItemsFlow.asStateFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun emitPushHistoryItems(items: List<PushHistoryItem>) {
|
||||||
|
mutablePushHistoryItemsFlow.emit(items)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun reset() {
|
override suspend fun reset() {
|
||||||
resetResult()
|
resetResult()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ class FakePushService(
|
||||||
private val selectPushProviderLambda: suspend (SessionId, PushProvider) -> Unit = { _, _ -> lambdaError() },
|
private val selectPushProviderLambda: suspend (SessionId, PushProvider) -> Unit = { _, _ -> lambdaError() },
|
||||||
private val setIgnoreRegistrationErrorLambda: (SessionId, Boolean) -> Unit = { _, _ -> lambdaError() },
|
private val setIgnoreRegistrationErrorLambda: (SessionId, Boolean) -> Unit = { _, _ -> lambdaError() },
|
||||||
private val resetPushHistoryResult: () -> Unit = { lambdaError() },
|
private val resetPushHistoryResult: () -> Unit = { lambdaError() },
|
||||||
|
private val resetBatteryOptimizationStateResult: () -> Unit = { lambdaError() },
|
||||||
) : PushService {
|
) : PushService {
|
||||||
override suspend fun getCurrentPushProvider(): PushProvider? {
|
override suspend fun getCurrentPushProvider(): PushProvider? {
|
||||||
return registeredPushProvider ?: currentPushProvider()
|
return registeredPushProvider ?: currentPushProvider()
|
||||||
|
|
@ -92,4 +93,8 @@ class FakePushService(
|
||||||
override suspend fun resetPushHistory() = simulateLongTask {
|
override suspend fun resetPushHistory() = simulateLongTask {
|
||||||
resetPushHistoryResult()
|
resetPushHistoryResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun resetBatteryOptimizationState() {
|
||||||
|
resetBatteryOptimizationStateResult()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue