Skip to content

Commit b4fc4e8

Browse files
committed
add tests
1 parent 486875a commit b4fc4e8

File tree

3 files changed

+117
-16
lines changed

3 files changed

+117
-16
lines changed

firebase-perf/src/main/java/com/google/firebase/perf/application/AppStateMonitor.java

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,22 @@ public static AppStateMonitor getInstance() {
9090
}
9191

9292
AppStateMonitor(TransportManager transportManager, Clock clock) {
93+
this(
94+
transportManager,
95+
clock,
96+
ConfigResolver.getInstance(),
97+
hasFrameMetricsAggregatorClass() ? new FrameMetricsAggregator() : null);
98+
}
99+
100+
AppStateMonitor(
101+
TransportManager transportManager,
102+
Clock clock,
103+
ConfigResolver configResolver,
104+
FrameMetricsAggregator frameMetricsAggregator) {
93105
this.transportManager = transportManager;
94106
this.clock = clock;
95-
configResolver = ConfigResolver.getInstance();
96-
hasFrameMetricsAggregator = hasFrameMetricsAggregatorClass();
97-
if (hasFrameMetricsAggregator) {
98-
frameMetricsAggregator = new FrameMetricsAggregator();
99-
}
107+
this.configResolver = configResolver;
108+
this.frameMetricsAggregator = frameMetricsAggregator;
100109
}
101110

102111
public synchronized void registerActivityLifecycleCallbacks(Context context) {
@@ -142,7 +151,7 @@ public void incrementTsnsCount(int value) {
142151

143152
@Override
144153
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
145-
if (isScreenTraceSupported(activity) && configResolver.isPerformanceMonitoringEnabled()) {
154+
if (isScreenTraceSupported() && configResolver.isPerformanceMonitoringEnabled()) {
146155
if (activity instanceof FragmentActivity) {
147156
FragmentActivity fragmentActivity = (FragmentActivity) activity;
148157
fragmentActivity
@@ -159,7 +168,7 @@ public void onActivityDestroyed(Activity activity) {}
159168

160169
@Override
161170
public synchronized void onActivityStarted(Activity activity) {
162-
if (isScreenTraceSupported(activity) && configResolver.isPerformanceMonitoringEnabled()) {
171+
if (isScreenTraceSupported() && configResolver.isPerformanceMonitoringEnabled()) {
163172
// Starts recording frame metrics for this activity.
164173
/**
165174
* TODO: Only add activities that are hardware acceleration enabled so that calling {@link
@@ -306,7 +315,7 @@ public void onActivityPaused(Activity activity) {}
306315
/** Stops screen trace right after onPause because of b/210055697 */
307316
@Override
308317
public void onActivityPostPaused(@NonNull Activity activity) {
309-
if (isScreenTraceSupported(activity)) {
318+
if (isScreenTraceSupported()) {
310319
sendScreenTrace(activity);
311320
}
312321
}
@@ -427,10 +436,9 @@ private void sendSessionLog(String name, Timer startTime, Timer endTime) {
427436
/**
428437
* Only send screen trace if FrameMetricsAggregator exists.
429438
*
430-
* @param activity The Activity for which we're monitoring the screen rendering performance.
431439
* @return true if supported, false if not.
432440
*/
433-
private boolean isScreenTraceSupported(Activity activity) {
441+
protected boolean isScreenTraceSupported() {
434442
return hasFrameMetricsAggregator;
435443
}
436444

@@ -439,7 +447,7 @@ private boolean isScreenTraceSupported(Activity activity) {
439447
* updated to 26.1.0 (b/69954793), there will be ClassNotFoundException. This method is to check
440448
* if FrameMetricsAggregator exists to avoid ClassNotFoundException.
441449
*/
442-
private boolean hasFrameMetricsAggregatorClass() {
450+
private static boolean hasFrameMetricsAggregatorClass() {
443451
try {
444452
Class<?> initializerClass = Class.forName(FRAME_METRICS_AGGREGATOR_CLASSNAME);
445453
return true;

firebase-perf/src/main/java/com/google/firebase/perf/application/FragmentStateMonitor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import androidx.core.app.FrameMetricsAggregator;
1919
import androidx.fragment.app.Fragment;
2020
import androidx.fragment.app.FragmentManager;
21+
import com.google.android.gms.common.util.VisibleForTesting;
2122
import com.google.firebase.perf.logging.AndroidLogger;
2223
import com.google.firebase.perf.metrics.Trace;
2324
import com.google.firebase.perf.transport.TransportManager;
@@ -50,7 +51,7 @@ public FragmentStateMonitor(
5051
* @param fragment fragment object.
5152
* @return Fragment screen trace name.
5253
*/
53-
public static String getFragmentScreenTraceName(Fragment fragment) {
54+
public String getFragmentScreenTraceName(Fragment fragment) {
5455
return Constants.SCREEN_TRACE_PREFIX + fragment.getClass().getSimpleName();
5556
}
5657

@@ -94,4 +95,9 @@ public void onFragmentPaused(@NonNull FragmentManager fm, @NonNull Fragment f) {
9495

9596
fragmentTrace.stop();
9697
}
98+
99+
@VisibleForTesting
100+
WeakHashMap<Fragment, Trace> getFragmentToTraceMap() {
101+
return fragmentToTraceMap;
102+
}
97103
}

firebase-perf/src/test/java/com/google/firebase/perf/application/FragmentStateMonitorTest.java

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
package com.google.firebase.perf.application;
1616

1717
import static org.mockito.ArgumentMatchers.any;
18+
import static org.mockito.ArgumentMatchers.nullable;
1819
import static org.mockito.Mockito.doAnswer;
20+
import static org.mockito.Mockito.doReturn;
21+
import static org.mockito.Mockito.spy;
1922
import static org.mockito.Mockito.times;
2023
import static org.mockito.Mockito.verify;
2124
import static org.mockito.MockitoAnnotations.initMocks;
@@ -28,11 +31,14 @@
2831
import com.google.firebase.perf.FirebasePerformanceTestBase;
2932
import com.google.firebase.perf.config.ConfigResolver;
3033
import com.google.firebase.perf.config.DeviceCacheManager;
34+
import com.google.firebase.perf.metrics.Trace;
3135
import com.google.firebase.perf.transport.TransportManager;
3236
import com.google.firebase.perf.util.Clock;
3337
import com.google.firebase.perf.util.Timer;
3438
import com.google.firebase.perf.v1.TraceMetric;
3539
import com.google.testing.timing.FakeDirectExecutorService;
40+
import java.util.WeakHashMap;
41+
import org.junit.Assert;
3642
import org.junit.Before;
3743
import org.junit.Test;
3844
import org.junit.runner.RunWith;
@@ -48,17 +54,21 @@ public class FragmentStateMonitorTest extends FirebasePerformanceTestBase {
4854

4955
@Mock private Clock clock;
5056
@Mock private Fragment mockFragment;
51-
@Mock private FragmentManager mockfragmentManager;
57+
@Mock private FragmentManager mockFragmentManager;
5258
@Mock private TransportManager mockTransportManager;
5359
@Mock private AppCompatActivity mockActivity;
60+
@Mock private AppCompatActivity mockActivityB;
5461
@Mock private AppStateMonitor appStateMonitor;
5562
@Mock private FrameMetricsAggregator fma;
5663

5764
@Captor private ArgumentCaptor<TraceMetric> argTraceMetric;
5865

5966
private long currentTime = 0;
67+
private static final String longFragmentName =
68+
"_st_NeverGonnaGiveYouUpNeverGonnaLetYouDownNeverGonnaRunAroundAndDesertYouNeverGonnaMakeYouCryNeverGonnaSayGoodbyeNeverGonnaTellALieAndHurtYou";
6069

6170
private Activity activity1;
71+
private ConfigResolver configResolver;
6272

6373
@Before
6474
public void setUp() {
@@ -71,16 +81,93 @@ public void setUp() {
7181

7282
ConfigResolver configResolver = ConfigResolver.getInstance();
7383
configResolver.setDeviceCacheManager(new DeviceCacheManager(new FakeDirectExecutorService()));
84+
ConfigResolver spyConfigResolver = spy(configResolver);
85+
doReturn(true).when(spyConfigResolver).isPerformanceMonitoringEnabled();
86+
this.configResolver = spyConfigResolver;
7487
}
7588

89+
/************ Trace Creation Tests ****************/
90+
7691
@Test
77-
public void fragmentLifecycleCallbacks_logFragmentScreenTrace() {
92+
public void lifecycleCallbacks_logFragmentScreenTrace() {
7893
FragmentStateMonitor monitor =
7994
new FragmentStateMonitor(clock, mockTransportManager, appStateMonitor, fma);
80-
monitor.onFragmentResumed(mockfragmentManager, mockFragment);
95+
monitor.onFragmentResumed(mockFragmentManager, mockFragment);
8196
verify(mockTransportManager, times(0)).log(any(TraceMetric.class), any());
8297

83-
monitor.onFragmentPaused(mockfragmentManager, mockFragment);
98+
monitor.onFragmentPaused(mockFragmentManager, mockFragment);
99+
verify(mockTransportManager, times(1)).log(any(TraceMetric.class), any());
100+
101+
monitor.onFragmentResumed(mockFragmentManager, mockFragment);
84102
verify(mockTransportManager, times(1)).log(any(TraceMetric.class), any());
103+
104+
monitor.onFragmentResumed(mockFragmentManager, mockFragment);
105+
verify(mockTransportManager, times(2)).log(any(TraceMetric.class), any());
106+
}
107+
108+
@Test
109+
public void lifecycleCallbacks_cleansUpMap_duringActivityTransitions() {
110+
// Simulate call order of activity + fragment lifecycle events
111+
AppStateMonitor appStateMonitor =
112+
spy(new AppStateMonitor(mockTransportManager, clock, configResolver, fma));
113+
FragmentStateMonitor fragmentMonitor =
114+
new FragmentStateMonitor(clock, mockTransportManager, appStateMonitor, fma);
115+
doReturn(true).when(appStateMonitor).isScreenTraceSupported();
116+
WeakHashMap<Fragment, Trace> map = fragmentMonitor.getFragmentToTraceMap();
117+
// Activity_A onCreate registers FragmentStateMonitor, then:
118+
appStateMonitor.onActivityStarted(mockActivity);
119+
Assert.assertEquals(0, map.size());
120+
appStateMonitor.onActivityResumed(mockActivity);
121+
fragmentMonitor.onFragmentResumed(mockFragmentManager, mockFragment);
122+
Assert.assertEquals(1, map.size());
123+
appStateMonitor.onActivityPaused(mockActivity);
124+
fragmentMonitor.onFragmentPaused(mockFragmentManager, mockFragment);
125+
Assert.assertEquals(0, map.size());
126+
appStateMonitor.onActivityPostPaused(mockActivity);
127+
// Activity_B onCreate registers FragmentStateMonitor, then:
128+
appStateMonitor.onActivityStarted(mockActivityB);
129+
appStateMonitor.onActivityResumed(mockActivityB);
130+
fragmentMonitor.onFragmentResumed(mockFragmentManager, mockFragment);
131+
appStateMonitor.onActivityStopped(mockActivity);
132+
Assert.assertEquals(1, map.size());
133+
}
134+
135+
@Test
136+
public void fragmentTraceCreation_truncatesName_whenFragmentNameTooLong() {
137+
AppStateMonitor appStateMonitor =
138+
spy(new AppStateMonitor(mockTransportManager, clock, configResolver, fma));
139+
FragmentStateMonitor fragmentMonitor =
140+
spy(new FragmentStateMonitor(clock, mockTransportManager, appStateMonitor, fma));
141+
doReturn(true).when(appStateMonitor).isScreenTraceSupported();
142+
doReturn(longFragmentName)
143+
.when(fragmentMonitor)
144+
.getFragmentScreenTraceName(nullable(Fragment.class));
145+
146+
fragmentMonitor.onFragmentResumed(mockFragmentManager, mockFragment);
147+
fragmentMonitor.onFragmentPaused(mockFragmentManager, mockFragment);
148+
}
149+
150+
/************ FrameMetrics Collection Tests ****************/
151+
152+
@Test
153+
public void onFragmentPaused_processFrameMetrics_beforeReset() {
154+
// Simulate call order of activity + fragment lifecycle events
155+
AppStateMonitor appStateMonitor =
156+
spy(new AppStateMonitor(mockTransportManager, clock, configResolver, fma));
157+
FragmentStateMonitor fragmentMonitor =
158+
new FragmentStateMonitor(clock, mockTransportManager, appStateMonitor, fma);
159+
doReturn(true).when(appStateMonitor).isScreenTraceSupported();
160+
// Activity_A onCreate registers FragmentStateMonitor, then:
161+
appStateMonitor.onActivityStarted(mockActivity);
162+
appStateMonitor.onActivityResumed(mockActivity);
163+
fragmentMonitor.onFragmentResumed(mockFragmentManager, mockFragment);
164+
appStateMonitor.onActivityPaused(mockActivity);
165+
// reset() was not called at the time of fragments collecting its frame metrics
166+
verify(fma, times(0)).reset();
167+
fragmentMonitor.onFragmentPaused(mockFragmentManager, mockFragment);
168+
verify(fma, times(0)).reset();
169+
// reset() is only called after fragment is done collecting its metrics
170+
appStateMonitor.onActivityPostPaused(mockActivity);
171+
verify(fma, times(1)).reset();
85172
}
86173
}

0 commit comments

Comments
 (0)