14
14
15
15
package com .google .firebase .perf .application ;
16
16
17
+ import static com .google .common .truth .Truth .assertThat ;
17
18
import static org .mockito .ArgumentMatchers .any ;
18
19
import static org .mockito .ArgumentMatchers .nullable ;
19
20
import static org .mockito .Mockito .doAnswer ;
21
+ import static org .mockito .Mockito .doNothing ;
20
22
import static org .mockito .Mockito .doReturn ;
21
23
import static org .mockito .Mockito .inOrder ;
22
24
import static org .mockito .Mockito .mock ;
25
27
import static org .mockito .Mockito .verify ;
26
28
import static org .mockito .MockitoAnnotations .initMocks ;
27
29
30
+ import android .app .Activity ;
28
31
import android .os .Bundle ;
29
32
import android .util .SparseIntArray ;
33
+ import android .view .WindowManager ;
34
+
30
35
import androidx .appcompat .app .AppCompatActivity ;
31
36
import androidx .core .app .FrameMetricsAggregator ;
32
37
import androidx .fragment .app .Fragment ;
53
58
import org .mockito .InOrder ;
54
59
import org .mockito .Mock ;
55
60
import org .mockito .stubbing .Answer ;
61
+ import org .robolectric .Robolectric ;
56
62
import org .robolectric .RobolectricTestRunner ;
63
+ import org .robolectric .android .controller .ActivityController ;
57
64
58
65
/** Unit tests for {@link com.google.firebase.perf.application.FragmentStateMonitor}. */
59
66
@ RunWith (RobolectricTestRunner .class )
@@ -64,7 +71,6 @@ public class FragmentStateMonitorTest extends FirebasePerformanceTestBase {
64
71
@ Mock private FragmentManager mockFragmentManager ;
65
72
@ Mock private TransportManager mockTransportManager ;
66
73
@ Mock private AppCompatActivity mockActivity ;
67
- @ Mock private AppCompatActivity mockActivityB ;
68
74
@ Mock private AppStateMonitor appStateMonitor ;
69
75
@ Mock private FrameMetricsRecorder recorder ;
70
76
@ Mock private PerfFrameMetrics frameCounts1 ;
@@ -73,6 +79,7 @@ public class FragmentStateMonitorTest extends FirebasePerformanceTestBase {
73
79
74
80
@ Captor private ArgumentCaptor <TraceMetric > argTraceMetric ;
75
81
82
+ private Activity activity ;
76
83
private long currentTime = 0 ;
77
84
private static final String longFragmentName =
78
85
"_st_NeverGonnaGiveYouUpNeverGonnaLetYouDownNeverGonnaRunAroundAndDesertYouNeverGonnaMakeYouCryNeverGonnaSayGoodbyeNeverGonnaTellALieAndHurtYou" ;
@@ -92,13 +99,14 @@ public void setUp() {
92
99
doAnswer ((Answer <Timer >) invocationOnMock -> new Timer (currentTime )).when (clock ).getTime ();
93
100
94
101
DeviceCacheManager .clearInstance ();
95
-
96
- // ConfigResolver configResolver = ConfigResolver.getInstance();
97
- // configResolver.setDeviceCacheManager(new DeviceCacheManager(new
98
- // FakeDirectExecutorService()));
99
- // ConfigResolver spyConfigResolver = spy(configResolver);
100
102
doReturn (true ).when (configResolver ).isPerformanceMonitoringEnabled ();
101
- // this.configResolver = spyConfigResolver;
103
+
104
+ doNothing ().when (recorder ).start ();
105
+ doNothing ().when (recorder ).startFragment (any ());
106
+ doReturn (Optional .of (frameCounts1 )).when (recorder ).stopFragment (any ());
107
+ doReturn (Optional .of (frameCounts2 )).when (recorder ).stopFragment (any ());
108
+
109
+ activity = createFakeActivity (true );
102
110
103
111
// fmaMetrics1 should have 1+3+1=5 total frames, 3+1=4 slow frames, and 1 frozen frames.
104
112
SparseIntArray sparseIntArray = new SparseIntArray ();
@@ -124,13 +132,13 @@ public void setUp() {
124
132
public void lifecycleCallbacks_differentFrameMetricsCapturedByFma_logFragmentScreenTrace () {
125
133
FragmentStateMonitor monitor =
126
134
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
127
- doReturn (Optional .of (frameCounts1 )).when (recorder ).stopSubTrace (any ());
135
+ doReturn (Optional .of (frameCounts1 )).when (recorder ).stopFragment (any ());
128
136
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
129
137
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
130
138
monitor .onFragmentPaused (mockFragmentManager , mockFragment );
131
139
verify (mockTransportManager , times (1 )).log (any (TraceMetric .class ), any ());
132
140
133
- doReturn (Optional .of (frameCounts2 )).when (recorder ).stopSubTrace (any ());
141
+ doReturn (Optional .of (frameCounts2 )).when (recorder ).stopFragment (any ());
134
142
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
135
143
verify (mockTransportManager , times (1 )).log (any (TraceMetric .class ), any ());
136
144
monitor .onFragmentPaused (mockFragmentManager , mockFragment );
@@ -141,7 +149,7 @@ public void lifecycleCallbacks_differentFrameMetricsCapturedByFma_logFragmentScr
141
149
public void lifecycleCallbacks_onPausedCalledTwice_logFragmentScreenTraceOnce () {
142
150
FragmentStateMonitor monitor =
143
151
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
144
- doReturn (Optional .of (frameCounts1 )).when (recorder ).stopSubTrace (any ());
152
+ doReturn (Optional .of (frameCounts1 )).when (recorder ).stopFragment (any ());
145
153
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
146
154
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
147
155
@@ -156,7 +164,7 @@ public void lifecycleCallbacks_onPausedCalledTwice_logFragmentScreenTraceOnce()
156
164
public void lifecycleCallbacks_onPausedCalledBeforeOnResume_doesNotLogFragmentScreenTrace () {
157
165
FragmentStateMonitor monitor =
158
166
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
159
- doReturn (Optional .of (frameCounts1 )).when (recorder ).stopSubTrace (any ());
167
+ doReturn (Optional .of (frameCounts1 )).when (recorder ).stopFragment (any ());
160
168
161
169
monitor .onFragmentPaused (mockFragmentManager , mockFragment );
162
170
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
@@ -170,7 +178,7 @@ public void lifecycleCallbacks_onPausedCalledBeforeOnResume_doesNotLogFragmentSc
170
178
lifecycleCallbacks_differentFrameMetricsCapturedByFma_logFragmentScreenTraceWithCorrectFrames () {
171
179
FragmentStateMonitor monitor =
172
180
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
173
- doReturn (Optional .of (frameCounts1 )).when (recorder ).stopSubTrace (any ());
181
+ doReturn (Optional .of (frameCounts1 )).when (recorder ).stopFragment (any ());
174
182
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
175
183
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
176
184
@@ -191,39 +199,42 @@ public void lifecycleCallbacks_onPausedCalledBeforeOnResume_doesNotLogFragmentSc
191
199
3 , (long ) metric .getCountersMap ().get (Constants .CounterNames .FRAMES_FROZEN .toString ()));
192
200
}
193
201
202
+ /**
203
+ * Simulate call order of activity + fragment lifecycle events
204
+ */
194
205
@ Test
195
206
public void lifecycleCallbacks_cleansUpMap_duringActivityTransitions () {
196
- // Simulate call order of activity + fragment lifecycle events
197
207
Bundle savedInstanceState = mock (Bundle .class );
198
- AppStateMonitor appStateMonitor =
199
- new AppStateMonitor (mockTransportManager , clock , configResolver , true );
208
+ AppStateMonitor appStateMonitor = mock (AppStateMonitor .class );
209
+ Fragment mockFragment1 = mock (Fragment .class );
210
+ Fragment mockFragment2 = mock (Fragment .class );
211
+ doNothing ().when (recorder ).startFragment (any ());
212
+ doReturn (mockFragmentManager ).when (mockActivity ).getSupportFragmentManager ();
213
+
200
214
FragmentStateMonitor fragmentMonitor =
201
215
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
202
- doReturn (true ).when (configResolver ).isPerformanceMonitoringEnabled ();
203
216
WeakHashMap <Fragment , Trace > fragmentToTraceMap = fragmentMonitor .getFragmentToTraceMap ();
204
- // Activity_A onCreate registers FragmentStateMonitor, then:
205
- appStateMonitor .onActivityCreated (mockActivity , savedInstanceState );
206
- appStateMonitor .onActivityStarted (mockActivity );
207
- Assert .assertEquals (0 , fragmentToTraceMap .size ());
208
- appStateMonitor .onActivityResumed (mockActivity );
209
- fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment );
210
- Assert .assertEquals (1 , fragmentToTraceMap .size ());
211
- appStateMonitor .onActivityPaused (mockActivity );
212
- fragmentMonitor .onFragmentPaused (mockFragmentManager , mockFragment );
213
- Assert .assertEquals (0 , fragmentToTraceMap .size ());
214
- // Activity_B onCreate registers FragmentStateMonitor, then:
215
- appStateMonitor .onActivityStarted (mockActivityB );
216
- appStateMonitor .onActivityResumed (mockActivityB );
217
- fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment );
218
- appStateMonitor .onActivityStopped (mockActivity );
219
- Assert .assertEquals (1 , fragmentToTraceMap .size ());
217
+
218
+ // Activity_A starts
219
+ fragmentMonitor .onFragmentCreated (mockFragmentManager , mockFragment1 , savedInstanceState );
220
+ fragmentMonitor .onFragmentStarted (mockFragmentManager , mockFragment1 );
221
+ assertThat (fragmentToTraceMap .size ()).isEqualTo (0 );
222
+ fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment1 );
223
+ assertThat (fragmentToTraceMap .size ()).isEqualTo (1 );
224
+ // Activity A is starting Activity B
225
+ fragmentMonitor .onFragmentPaused (mockFragmentManager , mockFragment1 );
226
+ assertThat (fragmentToTraceMap .size ()).isEqualTo (0 );
227
+ fragmentMonitor .onFragmentCreated (mockFragmentManager , mockFragment2 , savedInstanceState );
228
+ fragmentMonitor .onFragmentStarted (mockFragmentManager , mockFragment2 );
229
+ fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment2 );
230
+ assertThat (fragmentToTraceMap .size ()).isEqualTo (1 );
220
231
}
221
232
222
233
@ Test
223
234
public void fragmentTraceCreation_whenFrameMetricsIsAbsent_dropsTrace () {
224
235
FragmentStateMonitor monitor =
225
236
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
226
- doReturn (Optional .absent ()).when (recorder ).stopSubTrace (any ());
237
+ doReturn (Optional .absent ()).when (recorder ).stopFragment (any ());
227
238
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
228
239
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
229
240
@@ -241,7 +252,7 @@ public void fragmentTraceCreation_dropsTrace_whenFragmentNameTooLong() {
241
252
doReturn (longFragmentName )
242
253
.when (fragmentMonitor )
243
254
.getFragmentScreenTraceName (nullable (Fragment .class ));
244
- doReturn (Optional .of (frameCounts1 )).when (recorder ).stopSubTrace (any ());
255
+ doReturn (Optional .of (frameCounts1 )).when (recorder ).stopFragment (any ());
245
256
246
257
fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment );
247
258
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
@@ -258,20 +269,38 @@ public void onFragmentPaused_processFrameMetrics_beforeReset() {
258
269
spy (new AppStateMonitor (mockTransportManager , clock , configResolver , true ));
259
270
FragmentStateMonitor fragmentMonitor =
260
271
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , recorder );
272
+ doReturn (true ).when (configResolver ).isPerformanceMonitoringEnabled ();
261
273
doReturn (true ).when (appStateMonitor ).isScreenTraceSupported ();
262
- doReturn (Optional .of (frameCounts1 )).when (recorder ).stopSubTrace (any ());
263
274
// Activity_A onCreate registers FragmentStateMonitor, then:
264
- appStateMonitor .onActivityStarted (mockActivity );
275
+ appStateMonitor .onActivityStarted (activity );
265
276
fragmentMonitor .onFragmentStarted (mockFragmentManager , mockFragment );
266
- appStateMonitor .onActivityResumed (mockActivity );
277
+ appStateMonitor .onActivityResumed (activity );
267
278
fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment );
268
- appStateMonitor .onActivityPaused (mockActivity );
279
+ appStateMonitor .onActivityPaused (activity );
269
280
fragmentMonitor .onFragmentPaused (mockFragmentManager , mockFragment );
270
- appStateMonitor .onActivityStopped (mockActivity );
281
+ appStateMonitor .onActivityStopped (activity );
271
282
fragmentMonitor .onFragmentStopped (mockFragmentManager , mockFragment );
272
283
// reset() is only called after fragment is done collecting its metrics
273
284
InOrder orderVerifier = inOrder (recorder );
274
- orderVerifier .verify (recorder , times (1 )).stopSubTrace (any ());
285
+ orderVerifier .verify (recorder , times (1 )).stopFragment (any ());
275
286
orderVerifier .verify (recorder , times (1 )).stop ();
276
287
}
288
+
289
+ private static Activity createFakeActivity (boolean isHardwareAccelerated ) {
290
+ ActivityController <Activity > fakeActivityController = Robolectric .buildActivity (Activity .class );
291
+
292
+ if (isHardwareAccelerated ) {
293
+ fakeActivityController
294
+ .get ()
295
+ .getWindow ()
296
+ .addFlags (WindowManager .LayoutParams .FLAG_HARDWARE_ACCELERATED );
297
+ } else {
298
+ fakeActivityController
299
+ .get ()
300
+ .getWindow ()
301
+ .clearFlags (WindowManager .LayoutParams .FLAG_HARDWARE_ACCELERATED );
302
+ }
303
+
304
+ return fakeActivityController .start ().get ();
305
+ }
277
306
}
0 commit comments