14
14
15
15
package com .google .firebase .perf .metrics ;
16
16
17
+ import static com .google .common .truth .Truth .assertThat ;
17
18
import static com .google .firebase .perf .util .TimerTest .getElapsedRealtimeMicros ;
19
+ import static org .mockito .ArgumentMatchers .isA ;
18
20
import static org .mockito .Mockito .doAnswer ;
19
21
import static org .mockito .Mockito .mock ;
20
22
import static org .mockito .Mockito .times ;
21
23
import static org .mockito .Mockito .verify ;
22
24
import static org .mockito .Mockito .when ;
23
25
import static org .mockito .MockitoAnnotations .initMocks ;
26
+ import static org .robolectric .Shadows .shadowOf ;
24
27
25
28
import android .app .Activity ;
26
29
import android .content .pm .ProviderInfo ;
27
30
import android .os .Bundle ;
31
+ import android .os .Looper ;
32
+ import android .os .Process ;
33
+ import android .os .SystemClock ;
34
+ import android .view .View ;
28
35
import androidx .test .core .app .ApplicationProvider ;
29
36
import com .google .firebase .perf .FirebasePerformanceTestBase ;
37
+ import com .google .firebase .perf .config .ConfigResolver ;
30
38
import com .google .firebase .perf .provider .FirebasePerfProvider ;
31
39
import com .google .firebase .perf .session .SessionManager ;
32
40
import com .google .firebase .perf .transport .TransportManager ;
36
44
import com .google .firebase .perf .v1 .ApplicationProcessState ;
37
45
import com .google .firebase .perf .v1 .TraceMetric ;
38
46
import com .google .testing .timing .FakeScheduledExecutorService ;
47
+ import java .time .Duration ;
39
48
import java .util .concurrent .TimeUnit ;
40
49
import org .junit .After ;
41
50
import org .junit .Assert ;
48
57
import org .mockito .invocation .InvocationOnMock ;
49
58
import org .mockito .stubbing .Answer ;
50
59
import org .robolectric .RobolectricTestRunner ;
60
+ import org .robolectric .annotation .Config ;
61
+ import org .robolectric .annotation .LooperMode ;
62
+ import org .robolectric .shadows .ShadowSystemClock ;
51
63
52
64
/** Unit tests for {@link AppStartTrace}. */
53
65
@ RunWith (RobolectricTestRunner .class )
66
+ @ LooperMode (LooperMode .Mode .PAUSED )
54
67
public class AppStartTraceTest extends FirebasePerformanceTestBase {
55
68
56
69
@ Mock private Clock clock ;
57
70
@ Mock private TransportManager transportManager ;
71
+ @ Mock private ConfigResolver configResolver ;
58
72
@ Mock private Activity activity1 ;
59
73
@ Mock private Activity activity2 ;
60
74
@ Mock private Bundle bundle ;
@@ -94,7 +108,8 @@ public void reset() {
94
108
@ Test
95
109
public void testLaunchActivity () {
96
110
FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService ();
97
- AppStartTrace trace = new AppStartTrace (transportManager , clock , fakeExecutorService );
111
+ AppStartTrace trace =
112
+ new AppStartTrace (transportManager , clock , configResolver , fakeExecutorService );
98
113
// first activity goes through onCreate()->onStart()->onResume() state change.
99
114
currentTime = 1 ;
100
115
trace .onActivityCreated (activity1 , bundle );
@@ -171,7 +186,8 @@ private void verifyFinalState(
171
186
@ Test
172
187
public void testInterleavedActivity () {
173
188
FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService ();
174
- AppStartTrace trace = new AppStartTrace (transportManager , clock , fakeExecutorService );
189
+ AppStartTrace trace =
190
+ new AppStartTrace (transportManager , clock , configResolver , fakeExecutorService );
175
191
// first activity onCreate()
176
192
currentTime = 1 ;
177
193
trace .onActivityCreated (activity1 , bundle );
@@ -206,7 +222,8 @@ public void testInterleavedActivity() {
206
222
@ Test
207
223
public void testDelayedAppStart () {
208
224
FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService ();
209
- AppStartTrace trace = new AppStartTrace (transportManager , clock , fakeExecutorService );
225
+ AppStartTrace trace =
226
+ new AppStartTrace (transportManager , clock , configResolver , fakeExecutorService );
210
227
// Delays activity creation after 1 minute from app start time.
211
228
currentTime = appStart .getMicros () + TimeUnit .MINUTES .toMicros (1 ) + 1 ;
212
229
trace .onActivityCreated (activity1 , bundle );
@@ -227,7 +244,8 @@ public void testDelayedAppStart() {
227
244
@ Test
228
245
public void testStartFromBackground () {
229
246
FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService ();
230
- AppStartTrace trace = new AppStartTrace (transportManager , clock , fakeExecutorService );
247
+ AppStartTrace trace =
248
+ new AppStartTrace (transportManager , clock , configResolver , fakeExecutorService );
231
249
trace .setIsStartFromBackground ();
232
250
trace .onActivityCreated (activity1 , bundle );
233
251
Assert .assertNull (trace .getOnCreateTime ());
@@ -261,4 +279,38 @@ public void testFirebasePerfProviderOnAttachInfo_initializesGaugeCollection() {
261
279
Assert .assertEquals (oldSessionId , SessionManager .getInstance ().perfSession ().sessionId ());
262
280
verify (mockPerfSession , times (2 )).isGaugeAndEventCollectionEnabled ();
263
281
}
282
+
283
+ @ Test
284
+ @ Config (sdk = 26 )
285
+ public void timeToInitialDisplay_isLogged () {
286
+ when (clock .getTime ()).thenCallRealMethod (); // Use robolectric shadows to manipulate time
287
+ long appStartTime = TimeUnit .MILLISECONDS .toMicros (Process .getStartElapsedRealtime ());
288
+ View testView = new View (ApplicationProvider .getApplicationContext ());
289
+ when (activity1 .findViewById (android .R .id .content )).thenReturn (testView );
290
+ when (configResolver .getIsExperimentTTIDEnabled ()).thenReturn (true );
291
+ FakeScheduledExecutorService fakeExecutorService = new FakeScheduledExecutorService ();
292
+ AppStartTrace trace =
293
+ new AppStartTrace (transportManager , clock , configResolver , fakeExecutorService );
294
+
295
+ ShadowSystemClock .advanceBy (Duration .ofMillis (1000 ));
296
+ long resumeTime = TimeUnit .NANOSECONDS .toMicros (SystemClock .elapsedRealtimeNanos ());
297
+ trace .onActivityCreated (activity1 , bundle );
298
+ trace .onActivityStarted (activity1 );
299
+ trace .onActivityResumed (activity1 );
300
+ fakeExecutorService .runAll ();
301
+ verify (transportManager , times (1 ))
302
+ .log (isA (TraceMetric .class ), isA (ApplicationProcessState .class ));
303
+ ShadowSystemClock .advanceBy (Duration .ofMillis (1000 ));
304
+ long drawTime = TimeUnit .NANOSECONDS .toMicros (SystemClock .elapsedRealtimeNanos ());
305
+ testView .getViewTreeObserver ().dispatchOnDraw ();
306
+ shadowOf (Looper .getMainLooper ()).idle ();
307
+ fakeExecutorService .runNext ();
308
+ verify (transportManager , times (2 ))
309
+ .log (traceArgumentCaptor .capture (), isA (ApplicationProcessState .class ));
310
+
311
+ TraceMetric ttid = traceArgumentCaptor .getValue ();
312
+ assertThat (ttid .getName ()).isEqualTo ("_experiment_as_ttid" );
313
+ assertThat (ttid .getDurationUs ()).isNotEqualTo (resumeTime - appStartTime );
314
+ assertThat (ttid .getDurationUs ()).isEqualTo (drawTime - appStartTime );
315
+ }
264
316
}
0 commit comments