Add fallback notifications from UTDs to the push history (#5047)
This commit is contained in:
parent
b219c05d06
commit
b50e5430cb
7 changed files with 93 additions and 9 deletions
|
|
@ -236,7 +236,12 @@ class DefaultNotifiableEventResolver @Inject constructor(
|
||||||
}
|
}
|
||||||
NotificationContent.MessageLike.RoomEncrypted -> {
|
NotificationContent.MessageLike.RoomEncrypted -> {
|
||||||
Timber.tag(loggerTag.value).w("Notification with encrypted content -> fallback")
|
Timber.tag(loggerTag.value).w("Notification with encrypted content -> fallback")
|
||||||
val fallbackNotifiableEvent = fallbackNotificationFactory.create(userId, roomId, eventId)
|
val fallbackNotifiableEvent = fallbackNotificationFactory.create(
|
||||||
|
sessionId = userId,
|
||||||
|
roomId = roomId,
|
||||||
|
eventId = eventId,
|
||||||
|
cause = "Unable to decrypt event content",
|
||||||
|
)
|
||||||
ResolvedPushEvent.Event(fallbackNotifiableEvent)
|
ResolvedPushEvent.Event(fallbackNotifiableEvent)
|
||||||
}
|
}
|
||||||
is NotificationContent.MessageLike.RoomRedaction -> {
|
is NotificationContent.MessageLike.RoomRedaction -> {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class FallbackNotificationFactory @Inject constructor(
|
||||||
sessionId: SessionId,
|
sessionId: SessionId,
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
eventId: EventId,
|
eventId: EventId,
|
||||||
|
cause: String?,
|
||||||
): FallbackNotifiableEvent = FallbackNotifiableEvent(
|
): FallbackNotifiableEvent = FallbackNotifiableEvent(
|
||||||
sessionId = sessionId,
|
sessionId = sessionId,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
|
@ -34,5 +35,6 @@ class FallbackNotificationFactory @Inject constructor(
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
timestamp = clock.epochMillis(),
|
timestamp = clock.epochMillis(),
|
||||||
description = stringProvider.getString(R.string.notification_fallback_content),
|
description = stringProvider.getString(R.string.notification_fallback_content),
|
||||||
|
cause = cause,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,5 @@ data class FallbackNotifiableEvent(
|
||||||
override val isRedacted: Boolean,
|
override val isRedacted: Boolean,
|
||||||
override val isUpdated: Boolean,
|
override val isUpdated: Boolean,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
|
val cause: String?,
|
||||||
) : NotifiableEvent
|
) : NotifiableEvent
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import io.element.android.libraries.push.impl.notifications.FallbackNotification
|
||||||
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
|
||||||
|
|
@ -90,13 +91,23 @@ 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 = it.notifiableEvent.cause.orEmpty(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
pushHistoryService.onSuccess(
|
||||||
|
providerInfo = request.providerInfo,
|
||||||
|
eventId = request.eventId,
|
||||||
|
roomId = request.roomId,
|
||||||
|
sessionId = request.sessionId,
|
||||||
|
comment = "Push handled successfully",
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onFailure = { exception ->
|
onFailure = { exception ->
|
||||||
if (exception is NotificationResolverException.EventFilteredOut) {
|
if (exception is NotificationResolverException.EventFilteredOut) {
|
||||||
|
|
@ -140,7 +151,14 @@ class DefaultPushHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
Timber.tag(loggerTag.value).e(exception, "Failed to resolve push event")
|
Timber.tag(loggerTag.value).e(exception, "Failed to resolve push event")
|
||||||
ResolvedPushEvent.Event(fallbackNotificationFactory.create(request.sessionId, request.roomId, request.eventId))
|
ResolvedPushEvent.Event(
|
||||||
|
fallbackNotificationFactory.create(
|
||||||
|
sessionId = request.sessionId,
|
||||||
|
roomId = request.roomId,
|
||||||
|
eventId = request.eventId,
|
||||||
|
cause = exception.message,
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.getOrNull() ?: continue
|
}.getOrNull() ?: continue
|
||||||
|
|
|
||||||
|
|
@ -625,6 +625,7 @@ class DefaultNotifiableEventResolverTest {
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
timestamp = A_FAKE_TIMESTAMP,
|
timestamp = A_FAKE_TIMESTAMP,
|
||||||
|
cause = "Unable to decrypt event content",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult))
|
assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult))
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ class DefaultNotificationCreatorTest {
|
||||||
isRedacted = false,
|
isRedacted = false,
|
||||||
isUpdated = false,
|
isUpdated = false,
|
||||||
timestamp = A_FAKE_TIMESTAMP,
|
timestamp = A_FAKE_TIMESTAMP,
|
||||||
|
cause = null,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result.commonAssertions(
|
result.commonAssertions(
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
package io.element.android.libraries.push.impl.push
|
package io.element.android.libraries.push.impl.push
|
||||||
|
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.call.api.CallType
|
import io.element.android.features.call.api.CallType
|
||||||
import io.element.android.features.call.test.FakeElementCallEntryPoint
|
import io.element.android.features.call.test.FakeElementCallEntryPoint
|
||||||
import io.element.android.libraries.core.meta.BuildMeta
|
import io.element.android.libraries.core.meta.BuildMeta
|
||||||
|
|
@ -38,6 +39,7 @@ import io.element.android.libraries.push.impl.notifications.NotificationResolver
|
||||||
import io.element.android.libraries.push.impl.notifications.channels.FakeNotificationChannels
|
import io.element.android.libraries.push.impl.notifications.channels.FakeNotificationChannels
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableCallEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableCallEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
|
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.ResolvedPushEvent
|
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
||||||
import io.element.android.libraries.push.impl.test.DefaultTestPush
|
import io.element.android.libraries.push.impl.test.DefaultTestPush
|
||||||
|
|
@ -65,6 +67,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
private const val A_PUSHER_INFO = "info"
|
private const val A_PUSHER_INFO = "info"
|
||||||
|
|
||||||
|
@Suppress("LargeClass")
|
||||||
class DefaultPushHandlerTest {
|
class DefaultPushHandlerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `check handleInvalid behavior`() = runTest {
|
fun `check handleInvalid behavior`() = runTest {
|
||||||
|
|
@ -628,6 +631,59 @@ class DefaultPushHandlerTest {
|
||||||
.isCalledExactly(2)
|
.isCalledExactly(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when receiving a fallback event, we notify the push history service about it not being resolved`() = runTest {
|
||||||
|
val aNotifiableFallbackEvent = FallbackNotifiableEvent(
|
||||||
|
sessionId = A_SESSION_ID,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
eventId = AN_EVENT_ID,
|
||||||
|
editedEventId = null,
|
||||||
|
description = "A fallback notification",
|
||||||
|
canBeReplaced = false,
|
||||||
|
isRedacted = false,
|
||||||
|
isUpdated = false,
|
||||||
|
timestamp = 0L,
|
||||||
|
cause = "Unable to decrypt event",
|
||||||
|
)
|
||||||
|
val notifiableEventResult =
|
||||||
|
lambdaRecorder<SessionId, List<NotificationEventRequest>, Result<Map<NotificationEventRequest, Result<ResolvedPushEvent>>>> { _, _ ->
|
||||||
|
val request = NotificationEventRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, A_PUSHER_INFO)
|
||||||
|
Result.success(mapOf(request to Result.success(ResolvedPushEvent.Event(aNotifiableFallbackEvent))))
|
||||||
|
}
|
||||||
|
val onNotifiableEventsReceived = lambdaRecorder<List<NotifiableEvent>, Unit> {}
|
||||||
|
val incrementPushCounterResult = lambdaRecorder<Unit> {}
|
||||||
|
var receivedFallbackEvent = false
|
||||||
|
val onPushReceivedResult =
|
||||||
|
lambdaRecorder<String, EventId?, RoomId?, SessionId?, Boolean, Boolean, String?, Unit> { _, _, _, _, isResolved, _, comment ->
|
||||||
|
receivedFallbackEvent = !isResolved && comment == "Unable to resolve event: ${aNotifiableFallbackEvent.cause}"
|
||||||
|
}
|
||||||
|
val pushHistoryService = FakePushHistoryService(
|
||||||
|
onPushReceivedResult = onPushReceivedResult,
|
||||||
|
)
|
||||||
|
val aPushData = PushData(
|
||||||
|
eventId = AN_EVENT_ID,
|
||||||
|
roomId = A_ROOM_ID,
|
||||||
|
unread = 0,
|
||||||
|
clientSecret = A_SECRET,
|
||||||
|
)
|
||||||
|
val defaultPushHandler = createDefaultPushHandler(
|
||||||
|
onNotifiableEventsReceived = onNotifiableEventsReceived,
|
||||||
|
notifiableEventsResult = notifiableEventResult,
|
||||||
|
pushClientSecret = FakePushClientSecret(
|
||||||
|
getUserIdFromSecretResult = { A_USER_ID }
|
||||||
|
),
|
||||||
|
incrementPushCounterResult = incrementPushCounterResult,
|
||||||
|
pushHistoryService = pushHistoryService,
|
||||||
|
)
|
||||||
|
defaultPushHandler.handle(aPushData, A_PUSHER_INFO)
|
||||||
|
|
||||||
|
advanceTimeBy(300.milliseconds)
|
||||||
|
|
||||||
|
onNotifiableEventsReceived.assertions().isCalledOnce()
|
||||||
|
|
||||||
|
assertThat(receivedFallbackEvent).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
private fun TestScope.createDefaultPushHandler(
|
private fun TestScope.createDefaultPushHandler(
|
||||||
onNotifiableEventsReceived: (List<NotifiableEvent>) -> Unit = { lambdaError() },
|
onNotifiableEventsReceived: (List<NotifiableEvent>) -> Unit = { lambdaError() },
|
||||||
onRedactedEventsReceived: (List<ResolvedPushEvent.Redaction>) -> Unit = { lambdaError() },
|
onRedactedEventsReceived: (List<ResolvedPushEvent.Redaction>) -> Unit = { lambdaError() },
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue