21
21
import static org .mockito .Mockito .spy ;
22
22
import static org .mockito .Mockito .times ;
23
23
import static org .mockito .Mockito .verify ;
24
+ import static org .mockito .Mockito .when ;
24
25
import static org .mockito .MockitoAnnotations .initMocks ;
25
26
26
27
import android .app .Activity ;
28
+ import android .util .SparseIntArray ;
27
29
import androidx .appcompat .app .AppCompatActivity ;
28
30
import androidx .core .app .FrameMetricsAggregator ;
29
31
import androidx .fragment .app .Fragment ;
30
32
import androidx .fragment .app .FragmentManager ;
31
33
import com .google .firebase .perf .FirebasePerformanceTestBase ;
32
34
import com .google .firebase .perf .config .ConfigResolver ;
33
35
import com .google .firebase .perf .config .DeviceCacheManager ;
36
+ import com .google .firebase .perf .metrics .FrameMetricsCalculator ;
34
37
import com .google .firebase .perf .metrics .Trace ;
35
38
import com .google .firebase .perf .transport .TransportManager ;
36
39
import com .google .firebase .perf .util .Clock ;
40
+ import com .google .firebase .perf .util .Constants ;
37
41
import com .google .firebase .perf .util .Timer ;
42
+ import com .google .firebase .perf .v1 .ApplicationProcessState ;
38
43
import com .google .firebase .perf .v1 .TraceMetric ;
39
44
import com .google .testing .timing .FakeDirectExecutorService ;
40
45
import java .util .WeakHashMap ;
@@ -66,10 +71,16 @@ public class FragmentStateMonitorTest extends FirebasePerformanceTestBase {
66
71
private long currentTime = 0 ;
67
72
private static final String longFragmentName =
68
73
"_st_NeverGonnaGiveYouUpNeverGonnaLetYouDownNeverGonnaRunAroundAndDesertYouNeverGonnaMakeYouCryNeverGonnaSayGoodbyeNeverGonnaTellALieAndHurtYou" ;
69
-
70
- private Activity activity1 ;
71
74
private ConfigResolver configResolver ;
72
75
76
+ /**
77
+ * Array of SparseIntArray to mock the return value from {@link
78
+ * FrameMetricsAggregator#getMetrics()}
79
+ */
80
+ private SparseIntArray [] fmaMetrics1 = new SparseIntArray [1 ];
81
+
82
+ private SparseIntArray [] fmaMetrics2 = new SparseIntArray [1 ];
83
+
73
84
@ Before
74
85
public void setUp () {
75
86
currentTime = 0 ;
@@ -84,27 +95,85 @@ public void setUp() {
84
95
ConfigResolver spyConfigResolver = spy (configResolver );
85
96
doReturn (true ).when (spyConfigResolver ).isPerformanceMonitoringEnabled ();
86
97
this .configResolver = spyConfigResolver ;
98
+
99
+ // fmaMetrics1 should have 1+3+1=5 total frames, 3+1=4 slow frames, and 1 frozen frames.
100
+ SparseIntArray sparseIntArray = new SparseIntArray ();
101
+ sparseIntArray .append (1 , 1 );
102
+ sparseIntArray .append (17 , 3 );
103
+ sparseIntArray .append (800 , 1 );
104
+ fmaMetrics1 [FrameMetricsAggregator .TOTAL_INDEX ] = sparseIntArray ;
105
+
106
+ // fmaMetrics2 should have 5+5+4=14 total frames, 5+4=9 slow frames, and 4 frozen frames.
107
+ sparseIntArray = new SparseIntArray ();
108
+ sparseIntArray .append (1 , 5 );
109
+ sparseIntArray .append (18 , 5 );
110
+ sparseIntArray .append (800 , 4 );
111
+ fmaMetrics2 [FrameMetricsAggregator .TOTAL_INDEX ] = sparseIntArray ;
87
112
}
88
113
89
114
/************ Trace Creation Tests ****************/
90
115
91
116
@ Test
92
- public void lifecycleCallbacks_logFragmentScreenTrace () {
117
+ public void lifecycleCallbacks_differentFrameMetricsCapturedByFma_logFragmentScreenTrace () {
93
118
FragmentStateMonitor monitor =
94
119
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , fma );
120
+ when (fma .getMetrics ()).thenReturn (fmaMetrics1 );
95
121
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
96
122
verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
97
123
124
+ when (fma .getMetrics ()).thenReturn (fmaMetrics2 );
98
125
monitor .onFragmentPaused (mockFragmentManager , mockFragment );
99
126
verify (mockTransportManager , times (1 )).log (any (TraceMetric .class ), any ());
100
127
128
+ when (fma .getMetrics ()).thenReturn (fmaMetrics1 );
101
129
monitor .onFragmentResumed (mockFragmentManager , mockFragment );
102
130
verify (mockTransportManager , times (1 )).log (any (TraceMetric .class ), any ());
103
131
132
+ when (fma .getMetrics ()).thenReturn (fmaMetrics2 );
104
133
monitor .onFragmentPaused (mockFragmentManager , mockFragment );
105
134
verify (mockTransportManager , times (2 )).log (any (TraceMetric .class ), any ());
106
135
}
107
136
137
+ @ Test
138
+ public void lifecycleCallbacks_sameFrameMetricsCapturedByFma_dropFragmentScreenTrace () {
139
+ FragmentStateMonitor monitor =
140
+ new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , fma );
141
+ when (fma .getMetrics ()).thenReturn (fmaMetrics1 );
142
+ monitor .onFragmentResumed (mockFragmentManager , mockFragment );
143
+ verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
144
+
145
+ when (fma .getMetrics ()).thenReturn (fmaMetrics1 );
146
+ monitor .onFragmentPaused (mockFragmentManager , mockFragment );
147
+ verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
148
+ }
149
+
150
+ @ Test
151
+ public void
152
+ lifecycleCallbacks_differentFrameMetricsCapturedByFma_logFragmentScreenTraceWithCorrectFrames () {
153
+ FragmentStateMonitor monitor =
154
+ new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , fma );
155
+ when (fma .getMetrics ()).thenReturn (fmaMetrics1 );
156
+ monitor .onFragmentResumed (mockFragmentManager , mockFragment );
157
+ verify (mockTransportManager , times (0 )).log (any (TraceMetric .class ), any ());
158
+
159
+ when (fma .getMetrics ()).thenReturn (fmaMetrics2 );
160
+ monitor .onFragmentPaused (mockFragmentManager , mockFragment );
161
+
162
+ // fmaMetrics1 has 1+3+1=5 total frames, 3+1=4 slow frames, and 1 frozen frames
163
+ // fmaMetrics2 has 5+5+4=14 total frames, 5+4=9 slow frames, and 4 frozen frames
164
+ // we expect the trace to have 14-5=9 total frames, 9-4=5 slow frames, and 4-1=3 frozen
165
+ // frames.
166
+ verify (mockTransportManager , times (1 ))
167
+ .log (argTraceMetric .capture (), nullable (ApplicationProcessState .class ));
168
+ TraceMetric metric = argTraceMetric .getValue ();
169
+ Assert .assertEquals (
170
+ 9 , (long ) metric .getCountersMap ().get (Constants .CounterNames .FRAMES_TOTAL .toString ()));
171
+ Assert .assertEquals (
172
+ 5 , (long ) metric .getCountersMap ().get (Constants .CounterNames .FRAMES_SLOW .toString ()));
173
+ Assert .assertEquals (
174
+ 3 , (long ) metric .getCountersMap ().get (Constants .CounterNames .FRAMES_FROZEN .toString ()));
175
+ }
176
+
108
177
@ Test
109
178
public void lifecycleCallbacks_cleansUpMap_duringActivityTransitions () {
110
179
// Simulate call order of activity + fragment lifecycle events
@@ -113,23 +182,29 @@ public void lifecycleCallbacks_cleansUpMap_duringActivityTransitions() {
113
182
FragmentStateMonitor fragmentMonitor =
114
183
new FragmentStateMonitor (clock , mockTransportManager , appStateMonitor , fma );
115
184
doReturn (true ).when (appStateMonitor ).isScreenTraceSupported ();
116
- WeakHashMap <Fragment , Trace > map = fragmentMonitor .getFragmentToTraceMap ();
185
+ WeakHashMap <Fragment , Trace > fragmentToTraceMap = fragmentMonitor .getFragmentToTraceMap ();
186
+ WeakHashMap <Fragment , FrameMetricsCalculator .FrameMetrics > fragmentToMetricsMap =
187
+ fragmentMonitor .getFragmentToMetricsMap ();
117
188
// Activity_A onCreate registers FragmentStateMonitor, then:
118
189
appStateMonitor .onActivityStarted (mockActivity );
119
- Assert .assertEquals (0 , map .size ());
190
+ Assert .assertEquals (0 , fragmentToTraceMap .size ());
191
+ Assert .assertEquals (0 , fragmentToMetricsMap .size ());
120
192
appStateMonitor .onActivityResumed (mockActivity );
121
193
fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment );
122
- Assert .assertEquals (1 , map .size ());
194
+ Assert .assertEquals (1 , fragmentToTraceMap .size ());
195
+ Assert .assertEquals (1 , fragmentToMetricsMap .size ());
123
196
appStateMonitor .onActivityPaused (mockActivity );
124
197
fragmentMonitor .onFragmentPaused (mockFragmentManager , mockFragment );
125
- Assert .assertEquals (0 , map .size ());
198
+ Assert .assertEquals (0 , fragmentToTraceMap .size ());
199
+ Assert .assertEquals (0 , fragmentToMetricsMap .size ());
126
200
appStateMonitor .onActivityPostPaused (mockActivity );
127
201
// Activity_B onCreate registers FragmentStateMonitor, then:
128
202
appStateMonitor .onActivityStarted (mockActivityB );
129
203
appStateMonitor .onActivityResumed (mockActivityB );
130
204
fragmentMonitor .onFragmentResumed (mockFragmentManager , mockFragment );
131
205
appStateMonitor .onActivityStopped (mockActivity );
132
- Assert .assertEquals (1 , map .size ());
206
+ Assert .assertEquals (1 , fragmentToTraceMap .size ());
207
+ Assert .assertEquals (1 , fragmentToMetricsMap .size ());
133
208
}
134
209
135
210
@ Test
0 commit comments