1 // Copyright 2023 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base.jank_tracker; 6 7 import static org.mockito.ArgumentMatchers.any; 8 import static org.mockito.Mockito.atLeastOnce; 9 import static org.mockito.Mockito.never; 10 import static org.mockito.Mockito.verify; 11 import static org.mockito.Mockito.when; 12 13 import android.app.Activity; 14 import android.view.Window; 15 16 import org.junit.Before; 17 import org.junit.Test; 18 import org.junit.runner.RunWith; 19 import org.mockito.InOrder; 20 import org.mockito.Mock; 21 import org.mockito.Mockito; 22 import org.mockito.MockitoAnnotations; 23 24 import org.chromium.base.ActivityState; 25 import org.chromium.base.ApplicationStatus; 26 import org.chromium.base.test.BaseRobolectricTestRunner; 27 28 /** Tests for JankActivityTracker. */ 29 @RunWith(BaseRobolectricTestRunner.class) 30 public class JankActivityTrackerTest { 31 @Mock private Activity mActivity; 32 33 @Mock private Window mWindow; 34 35 @Mock private FrameMetricsListener mFrameMetricsListener; 36 37 @Mock private JankReportingScheduler mJankReportingScheduler; 38 createJankActivityTracker(Activity activity)39 JankActivityTracker createJankActivityTracker(Activity activity) { 40 JankActivityTracker tracker = 41 new JankActivityTracker(activity, mFrameMetricsListener, mJankReportingScheduler); 42 43 return tracker; 44 } 45 46 @Before setUp()47 public void setUp() { 48 MockitoAnnotations.initMocks(this); 49 50 when(mActivity.getWindow()).thenReturn(mWindow); 51 52 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.CREATED); 53 } 54 55 @Test jankTrackerTest_TestInitialize()56 public void jankTrackerTest_TestInitialize() { 57 JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); 58 jankActivityTracker.initialize(); 59 60 // Verify that we are listening to frame metrics. 61 // Initialize also starts listening to activity lifecycle events, but that's harder to 62 // verify. 63 verify(mWindow).addOnFrameMetricsAvailableListener(any(), any()); 64 } 65 66 @Test jankTrackerTest_TestActivityResume()67 public void jankTrackerTest_TestActivityResume() { 68 JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); 69 jankActivityTracker.initialize(); 70 71 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); 72 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); 73 74 // When an activity resumes we start reporting periodic metrics. 75 verify(mJankReportingScheduler, atLeastOnce()).startReportingPeriodicMetrics(); 76 verify(mJankReportingScheduler, never()).stopReportingPeriodicMetrics(); 77 78 // When an activity resumes we start recording metrics. 79 verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(true); 80 } 81 82 @Test jankTrackerTest_TestActivityPause()83 public void jankTrackerTest_TestActivityPause() { 84 JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); 85 jankActivityTracker.initialize(); 86 87 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); 88 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); 89 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED); 90 91 // When an activity pauses the reporting task should still be looping. 92 verify(mJankReportingScheduler, atLeastOnce()).startReportingPeriodicMetrics(); 93 verify(mJankReportingScheduler, never()).stopReportingPeriodicMetrics(); 94 95 InOrder orderVerifier = Mockito.inOrder(mFrameMetricsListener); 96 97 orderVerifier.verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(true); 98 // When an activity pauses we stop recording metrics. 99 orderVerifier.verify(mFrameMetricsListener).setIsListenerRecording(false); 100 } 101 102 @Test jankTrackerTest_TestActivityStop()103 public void jankTrackerTest_TestActivityStop() { 104 JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); 105 jankActivityTracker.initialize(); 106 107 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); 108 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); 109 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.PAUSED); 110 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED); 111 112 // When an activity stops we stop reporting periodic metrics. 113 InOrder schedulerOrderVerifier = Mockito.inOrder(mJankReportingScheduler); 114 schedulerOrderVerifier 115 .verify(mJankReportingScheduler, atLeastOnce()) 116 .startReportingPeriodicMetrics(); 117 schedulerOrderVerifier.verify(mJankReportingScheduler).stopReportingPeriodicMetrics(); 118 } 119 120 @Test jankTrackerTest_TestAttachTrackerOnResumedActivity()121 public void jankTrackerTest_TestAttachTrackerOnResumedActivity() { 122 // Modify the activity's state before attaching JankActivityTracker. 123 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STARTED); 124 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); 125 126 JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); 127 jankActivityTracker.initialize(); 128 129 // Verify that JankActivityTracker is running as expected for the Resumed state. 130 // Periodic metric reporting should be enabled. 131 verify(mJankReportingScheduler).startReportingPeriodicMetrics(); 132 // Metric recording should be enabled. 133 verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(true); 134 } 135 136 @Test jankTrackerTest_TestOutOfOrderStateChange()137 public void jankTrackerTest_TestOutOfOrderStateChange() { 138 JankActivityTracker jankActivityTracker = createJankActivityTracker(mActivity); 139 jankActivityTracker.initialize(); 140 141 // Move the activity from STOPPED to RESUMED without calling STARTED. 142 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.STOPPED); 143 ApplicationStatus.onStateChangeForTesting(mActivity, ActivityState.RESUMED); 144 145 // Verify that JankActivityTracker is running as expected for the Resumed state. 146 // Reporting task should be running and looping. 147 verify(mJankReportingScheduler).startReportingPeriodicMetrics(); 148 // Metric recording should be enabled. 149 verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(true); 150 verify(mFrameMetricsListener, atLeastOnce()).setIsListenerRecording(false); 151 } 152 } 153