@@ -23,9 +23,67 @@ import io.mockk.coVerify
23
23
import io.mockk.every
24
24
import io.mockk.mockk
25
25
import io.mockk.spyk
26
+ import kotlinx.coroutines.delay
27
+ import kotlinx.coroutines.withTimeout
26
28
import org.json.JSONArray
27
29
import org.json.JSONObject
28
30
import org.robolectric.Robolectric
31
+ import org.robolectric.android.controller.ActivityController
32
+
33
+ private class Mocks {
34
+ val context = ApplicationProvider .getApplicationContext<Context >()
35
+ val applicationService =
36
+ run {
37
+ val applicationService = ApplicationService ()
38
+ applicationService.start(context)
39
+ applicationService
40
+ }
41
+
42
+ val mockSubscriptionManager: ISubscriptionManager =
43
+ run {
44
+ val mockSubManager = mockk<ISubscriptionManager >()
45
+ every { mockSubManager.subscriptions.push } returns
46
+ mockk<IPushSubscription >().apply { every { id } returns " UUID1" }
47
+ mockSubManager
48
+ }
49
+
50
+ val notificationLifecycleService =
51
+ spyk(
52
+ NotificationLifecycleService (
53
+ applicationService,
54
+ MockHelper .time(0 ),
55
+ MockHelper .configModelStore(),
56
+ mockk<IInfluenceManager >().apply {
57
+ every { onDirectInfluenceFromNotification(any()) } returns Unit
58
+ },
59
+ mockSubscriptionManager,
60
+ mockk<IDeviceService >().apply {
61
+ every { deviceType } returns IDeviceService .DeviceType .Android
62
+ },
63
+ mockk<INotificationBackendService >().apply {
64
+ coEvery { updateNotificationAsOpened(any(), any(), any(), any()) } coAnswers {
65
+ // assume every updateNotificationAsOpened call takes 5 ms
66
+ delay(5 )
67
+ Unit
68
+ }
69
+ },
70
+ mockk<IReceiveReceiptWorkManager >(),
71
+ mockk<IAnalyticsTracker >().apply {
72
+ every { trackOpenedEvent(any(), any()) } returns Unit
73
+ },
74
+ ),
75
+ )
76
+
77
+ val activity: Activity =
78
+ run {
79
+ val activityController: ActivityController <Activity >
80
+ Robolectric .buildActivity(Activity ::class .java).use { controller ->
81
+ controller.setup() // Moves Activity to RESUMED state
82
+ activityController = controller
83
+ }
84
+ activityController.get()
85
+ }
86
+ }
29
87
30
88
@RobolectricTest
31
89
class NotificationLifecycleServiceTests : FunSpec ({
@@ -36,41 +94,9 @@ class NotificationLifecycleServiceTests : FunSpec({
36
94
37
95
test("Fires openDestinationActivity") {
38
96
// Given
39
- val context = ApplicationProvider .getApplicationContext<Context >()
40
- val applicationService = ApplicationService ()
41
- applicationService.start(context)
42
-
43
- val mockSubscriptionManager = mockk<ISubscriptionManager >()
44
- every { mockSubscriptionManager.subscriptions.push } returns
45
- mockk<IPushSubscription >().apply { every { id } returns " UUID1" }
46
-
47
- val notificationLifecycleService =
48
- spyk(
49
- NotificationLifecycleService (
50
- applicationService,
51
- MockHelper .time(0),
52
- MockHelper .configModelStore(),
53
- mockk<IInfluenceManager >().apply {
54
- every { onDirectInfluenceFromNotification(any()) } returns Unit
55
- },
56
- mockSubscriptionManager,
57
- mockk<IDeviceService >().apply {
58
- every { deviceType } returns IDeviceService .DeviceType .Android
59
- },
60
- mockk<INotificationBackendService >().apply {
61
- coEvery { updateNotificationAsOpened(any(), any(), any(), any()) } returns Unit
62
- },
63
- mockk<IReceiveReceiptWorkManager >(),
64
- mockk<IAnalyticsTracker >().apply {
65
- every { trackOpenedEvent(any(), any()) } returns Unit
66
- },
67
- ),
68
- )
69
- val activity : Activity
70
- Robolectric .buildActivity(Activity ::class.java).use { controller ->
71
- controller.setup() // Moves Activity to RESUMED state
72
- activity = controller.get()
73
- }
97
+ val mocks = Mocks ()
98
+ val notificationLifecycleService = mocks.notificationLifecycleService
99
+ val activity = mocks.activity
74
100
75
101
// When
76
102
val payload =
@@ -94,4 +120,41 @@ class NotificationLifecycleServiceTests : FunSpec({
94
120
)
95
121
}
96
122
}
123
+
124
+ test("ensure notificationOpened makes backend updates in a background process") {
125
+ // Given
126
+ val mocks = Mocks ()
127
+ val notificationLifecycleService = mocks.notificationLifecycleService
128
+ val activity = mocks.activity
129
+
130
+ // When
131
+ val payload = JSONArray ()
132
+ for (i in 1..1000) {
133
+ // adding 1000 different notifications
134
+ payload.put(
135
+ JSONObject ()
136
+ .put("alert", "test message")
137
+ .put(
138
+ "custom",
139
+ JSONObject ()
140
+ .put("i", "UUID $i"),
141
+ ),
142
+ )
143
+ }
144
+
145
+ withTimeout(500) {
146
+ // 1000 notifications should be handled within a small amount of time
147
+ notificationLifecycleService.notificationOpened(activity, payload)
148
+ }
149
+
150
+ // Then
151
+ coVerify(exactly = 1) {
152
+ // ensure openDestinationActivity is called within the timeout, prove that the increasing
153
+ // number of notifications clicked does not delay the main thread proportionally
154
+ notificationLifecycleService.openDestinationActivity(
155
+ withArg { Any () },
156
+ withArg { Any () },
157
+ )
158
+ }
159
+ }
97
160
})
0 commit comments