@@ -148,6 +148,9 @@ class SentryFrameMetricsCollectorTest {
148
148
collector.startCollection(mock())
149
149
assertEquals(0 , fixture.addOnFrameMetricsAvailableListenerCounter)
150
150
collector.onActivityStarted(fixture.activity)
151
+ // Execute pending main looper tasks since addOnFrameMetricsAvailableListener is posted to main
152
+ // thread
153
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
151
154
assertEquals(1 , fixture.addOnFrameMetricsAvailableListenerCounter)
152
155
}
153
156
@@ -157,8 +160,12 @@ class SentryFrameMetricsCollectorTest {
157
160
158
161
collector.startCollection(mock())
159
162
collector.onActivityStarted(fixture.activity)
163
+ // Execute pending add operations
164
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
160
165
assertEquals(0 , fixture.removeOnFrameMetricsAvailableListenerCounter)
161
166
collector.onActivityStopped(fixture.activity)
167
+ // Execute pending remove operations
168
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
162
169
assertEquals(1 , fixture.removeOnFrameMetricsAvailableListenerCounter)
163
170
}
164
171
@@ -181,6 +188,8 @@ class SentryFrameMetricsCollectorTest {
181
188
collector.onActivityStarted(fixture.activity)
182
189
assertEquals(0 , fixture.addOnFrameMetricsAvailableListenerCounter)
183
190
collector.startCollection(mock())
191
+ // Execute pending main looper tasks
192
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
184
193
assertEquals(1 , fixture.addOnFrameMetricsAvailableListenerCounter)
185
194
}
186
195
@@ -189,9 +198,13 @@ class SentryFrameMetricsCollectorTest {
189
198
val collector = fixture.getSut(context)
190
199
val id = collector.startCollection(mock())
191
200
collector.onActivityStarted(fixture.activity)
201
+ // Execute pending add operations
202
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
192
203
193
204
assertEquals(0 , fixture.removeOnFrameMetricsAvailableListenerCounter)
194
205
collector.stopCollection(id)
206
+ // Execute pending remove operations
207
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
195
208
assertEquals(1 , fixture.removeOnFrameMetricsAvailableListenerCounter)
196
209
}
197
210
@@ -205,9 +218,13 @@ class SentryFrameMetricsCollectorTest {
205
218
206
219
collector.onActivityStarted(fixture.activity)
207
220
collector.onActivityStarted(fixture.activity)
221
+ // Execute pending add operations
222
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
208
223
209
224
collector.onActivityStopped(fixture.activity)
210
225
collector.onActivityStopped(fixture.activity)
226
+ // Execute pending remove operations
227
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
211
228
212
229
assertEquals(1 , fixture.addOnFrameMetricsAvailableListenerCounter)
213
230
assertEquals(1 , fixture.removeOnFrameMetricsAvailableListenerCounter)
@@ -228,9 +245,13 @@ class SentryFrameMetricsCollectorTest {
228
245
collector.startCollection(mock())
229
246
collector.onActivityStarted(fixture.activity)
230
247
collector.onActivityStarted(fixture.activity2)
248
+ // Execute pending add operations
249
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
231
250
assertEquals(2 , fixture.addOnFrameMetricsAvailableListenerCounter)
232
251
collector.onActivityStopped(fixture.activity)
233
252
collector.onActivityStopped(fixture.activity2)
253
+ // Execute pending remove operations
254
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
234
255
assertEquals(2 , fixture.removeOnFrameMetricsAvailableListenerCounter)
235
256
}
236
257
@@ -240,10 +261,13 @@ class SentryFrameMetricsCollectorTest {
240
261
val id1 = collector.startCollection(mock())
241
262
val id2 = collector.startCollection(mock())
242
263
collector.onActivityStarted(fixture.activity)
264
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
243
265
assertEquals(1 , fixture.addOnFrameMetricsAvailableListenerCounter)
244
266
collector.stopCollection(id1)
267
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
245
268
assertEquals(0 , fixture.removeOnFrameMetricsAvailableListenerCounter)
246
269
collector.stopCollection(id2)
270
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
247
271
assertEquals(1 , fixture.removeOnFrameMetricsAvailableListenerCounter)
248
272
}
249
273
@@ -511,6 +535,48 @@ class SentryFrameMetricsCollectorTest {
511
535
)
512
536
}
513
537
538
+ @Test
539
+ fun `collector calls addOnFrameMetricsAvailableListener on main thread` () {
540
+ val collector = fixture.getSut(context)
541
+
542
+ collector.startCollection(mock())
543
+ collector.onActivityStarted(fixture.activity)
544
+
545
+ assertEquals(0 , fixture.addOnFrameMetricsAvailableListenerCounter)
546
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
547
+ assertEquals(1 , fixture.addOnFrameMetricsAvailableListenerCounter)
548
+ }
549
+
550
+ @Test
551
+ fun `collector calls removeOnFrameMetricsAvailableListener on main thread` () {
552
+ val collector = fixture.getSut(context)
553
+ collector.startCollection(mock())
554
+ collector.onActivityStarted(fixture.activity)
555
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
556
+
557
+ collector.onActivityStopped(fixture.activity)
558
+ assertEquals(0 , fixture.removeOnFrameMetricsAvailableListenerCounter)
559
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
560
+ assertEquals(1 , fixture.removeOnFrameMetricsAvailableListenerCounter)
561
+ }
562
+
563
+ @Test
564
+ fun `collector prevents race condition when stop is called immediately after start` () {
565
+ val collector = fixture.getSut(context)
566
+
567
+ collector.startCollection(mock())
568
+ collector.onActivityStarted(fixture.activity)
569
+ collector.onActivityStopped(fixture.activity)
570
+
571
+ // Now execute all pending operations
572
+ Shadows .shadowOf(Looper .getMainLooper()).idle()
573
+
574
+ // as the listeners are posted to the main thread, we expect an add followed by a remove
575
+ assertEquals(1 , fixture.addOnFrameMetricsAvailableListenerCounter)
576
+ assertEquals(1 , fixture.removeOnFrameMetricsAvailableListenerCounter)
577
+ assertEquals(0 , collector.getProperty<Set <Window >>(" trackedWindows" ).size)
578
+ }
579
+
514
580
private fun createMockWindow (refreshRate : Float = 60F): Window {
515
581
val mockWindow = mock<Window >()
516
582
val mockDisplay = mock<Display >()
0 commit comments