Skip to content

Commit 6a8b9f8

Browse files
committed
chore(notifications): add log when no commands can be created for notification type
1 parent 91c33cc commit 6a8b9f8

File tree

7 files changed

+148
-7
lines changed

7 files changed

+148
-7
lines changed

feature/notification/impl/src/commonMain/kotlin/net/thunderbird/feature/notification/impl/dismisser/DefaultNotificationDismisser.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,22 @@ class DefaultNotificationDismisser internal constructor(
6666

6767
if (notification in notificationRegistry) {
6868
val commands = buildCommands(notification)
69-
commands.forEach { command -> emit(command.execute()) }
69+
commands
70+
.ifEmpty {
71+
val message = "The notification is present in the registrar; " +
72+
"however no commands where found to execute for notification $notification"
73+
logger.warn { message }
74+
emit(
75+
Outcome.Failure(
76+
Failure(
77+
command = null,
78+
throwable = NotificationCommandException(message),
79+
),
80+
),
81+
)
82+
emptyList()
83+
}
84+
.forEach { command -> emit(command.execute()) }
7085
} else {
7186
emit(
7287
value = Outcome.failure(

feature/notification/impl/src/commonMain/kotlin/net/thunderbird/feature/notification/impl/sender/DefaultNotificationSender.kt

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import net.thunderbird.feature.notification.api.NotificationRegistry
99
import net.thunderbird.feature.notification.api.command.NotificationCommand
1010
import net.thunderbird.feature.notification.api.command.NotificationCommand.Failure
1111
import net.thunderbird.feature.notification.api.command.NotificationCommand.Success
12+
import net.thunderbird.feature.notification.api.command.NotificationCommandException
1213
import net.thunderbird.feature.notification.api.content.InAppNotification
1314
import net.thunderbird.feature.notification.api.content.Notification
1415
import net.thunderbird.feature.notification.api.content.SystemNotification
@@ -40,9 +41,22 @@ class DefaultNotificationSender internal constructor(
4041
) : NotificationSender {
4142
override fun send(notification: Notification): Flow<Outcome<Success<Notification>, Failure<Notification>>> = flow {
4243
val commands = buildCommands(notification)
43-
commands.forEach { command ->
44-
emit(command.execute())
45-
}
44+
45+
commands
46+
.ifEmpty {
47+
val message = "No commands to execute for notification $notification"
48+
logger.warn { message }
49+
emit(
50+
Outcome.Failure(
51+
Failure(
52+
command = null,
53+
throwable = NotificationCommandException(message),
54+
),
55+
),
56+
)
57+
emptyList()
58+
}
59+
.forEach { command -> emit(command.execute()) }
4660
}
4761

4862
private fun buildCommands(notification: Notification): List<NotificationCommand<out Notification>> = buildList {

feature/notification/impl/src/commonTest/kotlin/net/thunderbird/feature/notification/impl/dismisser/DefaultNotificationDismisserTest.kt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ package net.thunderbird.feature.notification.impl.dismisser
22

33
import assertk.all
44
import assertk.assertThat
5+
import assertk.assertions.contains
56
import assertk.assertions.hasMessage
7+
import assertk.assertions.hasSize
68
import assertk.assertions.isEqualTo
79
import assertk.assertions.isInstanceOf
10+
import assertk.assertions.isNull
811
import assertk.assertions.prop
912
import dev.mokkery.matcher.any
1013
import dev.mokkery.spy
@@ -16,23 +19,28 @@ import kotlinx.coroutines.flow.toList
1619
import kotlinx.coroutines.test.runTest
1720
import net.thunderbird.core.featureflag.FeatureFlagProvider
1821
import net.thunderbird.core.featureflag.FeatureFlagResult
22+
import net.thunderbird.core.logging.LogLevel
1923
import net.thunderbird.core.logging.testing.TestLogger
2024
import net.thunderbird.core.outcome.Outcome
2125
import net.thunderbird.feature.notification.api.NotificationId
2226
import net.thunderbird.feature.notification.api.NotificationRegistry
27+
import net.thunderbird.feature.notification.api.NotificationSeverity
2328
import net.thunderbird.feature.notification.api.command.NotificationCommand.Failure
2429
import net.thunderbird.feature.notification.api.command.NotificationCommand.Success
2530
import net.thunderbird.feature.notification.api.command.NotificationCommandException
31+
import net.thunderbird.feature.notification.api.content.AppNotification
2632
import net.thunderbird.feature.notification.api.content.InAppNotification
2733
import net.thunderbird.feature.notification.api.content.Notification
2834
import net.thunderbird.feature.notification.api.content.SystemNotification
2935
import net.thunderbird.feature.notification.api.receiver.NotificationNotifier
36+
import net.thunderbird.feature.notification.api.ui.icon.NotificationIcon
3037
import net.thunderbird.feature.notification.impl.command.DismissInAppNotificationCommand
3138
import net.thunderbird.feature.notification.impl.command.DismissSystemNotificationCommand
3239
import net.thunderbird.feature.notification.testing.fake.FakeInAppOnlyNotification
3340
import net.thunderbird.feature.notification.testing.fake.FakeNotification
3441
import net.thunderbird.feature.notification.testing.fake.FakeNotificationRegistry
3542
import net.thunderbird.feature.notification.testing.fake.FakeSystemOnlyNotification
43+
import net.thunderbird.feature.notification.testing.fake.icon.EMPTY_SYSTEM_NOTIFICATION_ICON
3644
import net.thunderbird.feature.notification.testing.fake.receiver.FakeInAppNotificationNotifier
3745
import net.thunderbird.feature.notification.testing.fake.receiver.FakeSystemNotificationNotifier
3846

@@ -138,6 +146,54 @@ class DefaultNotificationDismisserTest {
138146
}
139147
}
140148

149+
@Test
150+
fun `send should emit Failure when no commands can be executed`() = runTest {
151+
// Arrange
152+
val registry = FakeNotificationRegistry()
153+
val systemNotifier = spy(FakeSystemNotificationNotifier())
154+
val inAppNotifier = spy(FakeInAppNotificationNotifier())
155+
val logger = TestLogger()
156+
val testSubject = createTestSubject(
157+
logger = logger,
158+
notificationRegistry = registry,
159+
systemNotificationNotifier = systemNotifier,
160+
inAppNotificationNotifier = inAppNotifier,
161+
)
162+
val notification = object : AppNotification() {
163+
override val accountUuid: String? get() = ""
164+
override val title: String = ""
165+
override val contentText: String? = null
166+
override val severity: NotificationSeverity = NotificationSeverity.Critical
167+
override val icon: NotificationIcon = NotificationIcon(
168+
systemNotificationIcon = EMPTY_SYSTEM_NOTIFICATION_ICON,
169+
)
170+
}
171+
// register notification to be dismissible
172+
registry.register(notification)
173+
val expectedMessage = "The notification is present in the registrar; " +
174+
"however no commands where found to execute for notification $notification"
175+
176+
// Act
177+
val outcomes = testSubject.dismiss(notification).toList(mutableListOf())
178+
179+
// Assert
180+
assertThat(outcomes).all {
181+
hasSize(size = 1)
182+
transform { it.single() }
183+
.isInstanceOf<Outcome.Failure<Failure<Notification>>>()
184+
.prop(Outcome.Failure<Failure<Notification>>::error)
185+
.all {
186+
prop(Failure<Notification>::command).isNull()
187+
prop(Failure<Notification>::throwable)
188+
.isInstanceOf<NotificationCommandException>()
189+
.hasMessage(expectedMessage)
190+
}
191+
}
192+
assertThat(logger.events)
193+
.transform { it.map { event -> event.level to event.message } }
194+
.contains(LogLevel.WARN to expectedMessage)
195+
}
196+
141197
private fun createTestSubject(
142198
logger: TestLogger = TestLogger(),
143199
featureFlagProvider: FeatureFlagProvider = FeatureFlagProvider { FeatureFlagResult.Enabled },

feature/notification/impl/src/commonTest/kotlin/net/thunderbird/feature/notification/impl/sender/DefaultNotificationSenderTest.kt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package net.thunderbird.feature.notification.impl.sender
22

3+
import assertk.all
34
import assertk.assertThat
5+
import assertk.assertions.contains
6+
import assertk.assertions.hasMessage
7+
import assertk.assertions.hasSize
48
import assertk.assertions.isInstanceOf
9+
import assertk.assertions.isNull
510
import assertk.assertions.prop
611
import dev.mokkery.matcher.any
712
import dev.mokkery.spy
@@ -12,21 +17,27 @@ import kotlinx.coroutines.flow.toList
1217
import kotlinx.coroutines.test.runTest
1318
import net.thunderbird.core.featureflag.FeatureFlagProvider
1419
import net.thunderbird.core.featureflag.FeatureFlagResult
20+
import net.thunderbird.core.logging.LogLevel
1521
import net.thunderbird.core.logging.testing.TestLogger
1622
import net.thunderbird.core.outcome.Outcome
1723
import net.thunderbird.feature.notification.api.NotificationRegistry
1824
import net.thunderbird.feature.notification.api.NotificationSeverity
25+
import net.thunderbird.feature.notification.api.command.NotificationCommand.Failure
1926
import net.thunderbird.feature.notification.api.command.NotificationCommand.Success
27+
import net.thunderbird.feature.notification.api.command.NotificationCommandException
28+
import net.thunderbird.feature.notification.api.content.AppNotification
2029
import net.thunderbird.feature.notification.api.content.InAppNotification
2130
import net.thunderbird.feature.notification.api.content.Notification
2231
import net.thunderbird.feature.notification.api.content.SystemNotification
2332
import net.thunderbird.feature.notification.api.receiver.NotificationNotifier
33+
import net.thunderbird.feature.notification.api.ui.icon.NotificationIcon
2434
import net.thunderbird.feature.notification.impl.command.DisplayInAppNotificationCommand
2535
import net.thunderbird.feature.notification.impl.command.DisplaySystemNotificationCommand
2636
import net.thunderbird.feature.notification.testing.fake.FakeInAppOnlyNotification
2737
import net.thunderbird.feature.notification.testing.fake.FakeNotification
2838
import net.thunderbird.feature.notification.testing.fake.FakeNotificationRegistry
2939
import net.thunderbird.feature.notification.testing.fake.FakeSystemOnlyNotification
40+
import net.thunderbird.feature.notification.testing.fake.icon.EMPTY_SYSTEM_NOTIFICATION_ICON
3041
import net.thunderbird.feature.notification.testing.fake.receiver.FakeInAppNotificationNotifier
3142
import net.thunderbird.feature.notification.testing.fake.receiver.FakeSystemNotificationNotifier
3243

@@ -122,6 +133,51 @@ class DefaultNotificationSenderTest {
122133
verifySuspend(exactly(0)) { systemNotifier.show(id = any(), notification = any()) }
123134
}
124135

136+
@Test
137+
fun `send should emit Failure when no commands can be executed`() = runTest {
138+
// Arrange
139+
val registry = FakeNotificationRegistry()
140+
val systemNotifier = spy(FakeSystemNotificationNotifier())
141+
val inAppNotifier = spy(FakeInAppNotificationNotifier())
142+
val logger = TestLogger()
143+
val testSubject = createTestSubject(
144+
logger = logger,
145+
notificationRegistry = registry,
146+
systemNotificationNotifier = systemNotifier,
147+
inAppNotificationNotifier = inAppNotifier,
148+
)
149+
val notification = object : AppNotification() {
150+
override val accountUuid: String? get() = ""
151+
override val title: String = ""
152+
override val contentText: String? = null
153+
override val severity: NotificationSeverity = NotificationSeverity.Critical
154+
override val icon: NotificationIcon = NotificationIcon(
155+
systemNotificationIcon = EMPTY_SYSTEM_NOTIFICATION_ICON,
156+
)
157+
}
158+
val expectedMessage = "No commands to execute for notification $notification"
159+
160+
// Act
161+
val outcomes = testSubject.send(notification).toList(mutableListOf())
162+
163+
// Assert
164+
assertThat(outcomes).all {
165+
hasSize(size = 1)
166+
transform { it.single() }
167+
.isInstanceOf<Outcome.Failure<Failure<Notification>>>()
168+
.prop(Outcome.Failure<Failure<Notification>>::error)
169+
.all {
170+
prop(Failure<Notification>::command).isNull()
171+
prop(Failure<Notification>::throwable)
172+
.isInstanceOf<NotificationCommandException>()
173+
.hasMessage(expectedMessage)
174+
}
175+
}
176+
assertThat(logger.events)
177+
.transform { it.map { event -> event.level to event.message } }
178+
.contains(LogLevel.WARN to expectedMessage)
179+
}
180+
125181
private fun createTestSubject(
126182
logger: TestLogger = TestLogger(),
127183
featureFlagProvider: FeatureFlagProvider = FeatureFlagProvider { FeatureFlagResult.Enabled },

feature/notification/testing/src/androidMain/kotlin/net/thunderbird/feature/notification/testing/fake/icon/SystemNotificationIcon.android.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ package net.thunderbird.feature.notification.testing.fake.icon
22

33
import net.thunderbird.feature.notification.api.ui.icon.SystemNotificationIcon
44

5-
internal actual val EMPTY_SYSTEM_NOTIFICATION_ICON: SystemNotificationIcon = 0
5+
actual val EMPTY_SYSTEM_NOTIFICATION_ICON: SystemNotificationIcon = 0

feature/notification/testing/src/commonMain/kotlin/net/thunderbird/feature/notification/testing/fake/icon/FakeSystemNotificationIcon.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ package net.thunderbird.feature.notification.testing.fake.icon
22

33
import net.thunderbird.feature.notification.api.ui.icon.SystemNotificationIcon
44

5-
internal expect val EMPTY_SYSTEM_NOTIFICATION_ICON: SystemNotificationIcon
5+
expect val EMPTY_SYSTEM_NOTIFICATION_ICON: SystemNotificationIcon

feature/notification/testing/src/jvmMain/kotlin/net/thunderbird/feature/notification/testing/fake/icon/SystemNotificationIcon.jvm.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ package net.thunderbird.feature.notification.testing.fake.icon
22

33
import net.thunderbird.feature.notification.api.ui.icon.SystemNotificationIcon
44

5-
internal actual val EMPTY_SYSTEM_NOTIFICATION_ICON: SystemNotificationIcon = 0
5+
actual val EMPTY_SYSTEM_NOTIFICATION_ICON: SystemNotificationIcon = 0

0 commit comments

Comments
 (0)