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.Mockito.verify; 8 9 import org.junit.Assert; 10 import org.junit.Before; 11 import org.junit.Test; 12 import org.junit.runner.RunWith; 13 import org.mockito.InOrder; 14 import org.mockito.Mock; 15 import org.mockito.Mockito; 16 import org.mockito.MockitoAnnotations; 17 import org.robolectric.annotation.LooperMode; 18 import org.robolectric.shadow.api.Shadow; 19 import org.robolectric.shadows.ShadowLooper; 20 21 import org.chromium.base.test.BaseRobolectricTestRunner; 22 23 /** Tests for JankReportingScheduler. */ 24 @RunWith(BaseRobolectricTestRunner.class) 25 @LooperMode(LooperMode.Mode.LEGACY) 26 public class JankReportingSchedulerTest { 27 ShadowLooper mShadowLooper; 28 29 @Mock private FrameMetricsStore mFrameMetricsStore; 30 createJankReportingScheduler()31 JankReportingScheduler createJankReportingScheduler() { 32 JankReportingScheduler scheduler = new JankReportingScheduler(mFrameMetricsStore); 33 mShadowLooper = Shadow.extract(scheduler.getOrCreateHandler().getLooper()); 34 35 return scheduler; 36 } 37 38 @Before setUp()39 public void setUp() { 40 MockitoAnnotations.initMocks(this); 41 } 42 43 @Test jankScenarioTracking_startTracking()44 public void jankScenarioTracking_startTracking() { 45 JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); 46 47 jankReportingScheduler.startTrackingScenario(JankScenario.NEW_TAB_PAGE); 48 49 // When first getting the handler we need to run the initialize on the handler. 50 mShadowLooper.runOneTask(); 51 // Starting tracking posts a task to begin recording metrics in FrameMetricsStore. 52 mShadowLooper.runOneTask(); 53 54 verify(mFrameMetricsStore).initialize(); 55 verify(mFrameMetricsStore).startTrackingScenario(JankScenario.NEW_TAB_PAGE); 56 } 57 58 @Test jankScenarioTracking_startAndStopTracking()59 public void jankScenarioTracking_startAndStopTracking() { 60 JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); 61 62 jankReportingScheduler.startTrackingScenario(JankScenario.NEW_TAB_PAGE); 63 jankReportingScheduler.finishTrackingScenario(JankScenario.NEW_TAB_PAGE); 64 65 // When first getting the handler we need to run the initialize on the handler. 66 mShadowLooper.runOneTask(); 67 // Starting tracking posts a task to begin recording metrics in FrameMetricsStore. 68 mShadowLooper.runOneTask(); 69 // Stopping tracking posts a task to finish tracking and upload the calculated metrics. 70 mShadowLooper.runOneTask(); 71 72 InOrder orderVerifier = Mockito.inOrder(mFrameMetricsStore); 73 74 // After both tasks we should have started and stopped tracking the periodic reporting 75 // scenario. 76 orderVerifier.verify(mFrameMetricsStore).initialize(); 77 orderVerifier.verify(mFrameMetricsStore).startTrackingScenario(JankScenario.NEW_TAB_PAGE); 78 orderVerifier.verify(mFrameMetricsStore).stopTrackingScenario(JankScenario.NEW_TAB_PAGE); 79 80 Assert.assertFalse(mShadowLooper.getScheduler().areAnyRunnable()); 81 } 82 83 @Test jankReportingSchedulerTest_StartPeriodicReporting()84 public void jankReportingSchedulerTest_StartPeriodicReporting() { 85 JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); 86 87 jankReportingScheduler.startReportingPeriodicMetrics(); 88 89 // When first getting the handler we need to run the initialize on the handler. 90 mShadowLooper.runOneTask(); 91 // When periodic reporting is enabled a task is immediately posted to begin tracking. 92 mShadowLooper.runOneTask(); 93 // Then a delayed task is posted for the reporting loop. 94 mShadowLooper.runOneTask(); 95 // The reporting loop task posts an immediate task to stop tracking and record the data. 96 mShadowLooper.runOneTask(); 97 98 InOrder orderVerifier = Mockito.inOrder(mFrameMetricsStore); 99 100 // After both tasks we should have started and stopped tracking the periodic reporting 101 // scenario. 102 orderVerifier.verify(mFrameMetricsStore).initialize(); 103 orderVerifier 104 .verify(mFrameMetricsStore) 105 .startTrackingScenario(JankScenario.PERIODIC_REPORTING); 106 orderVerifier 107 .verify(mFrameMetricsStore) 108 .stopTrackingScenario(JankScenario.PERIODIC_REPORTING); 109 110 // There should be another task posted to continue the loop. 111 Assert.assertTrue(mShadowLooper.getScheduler().areAnyRunnable()); 112 } 113 114 @Test jankReportingSchedulerTest_StopPeriodicReporting()115 public void jankReportingSchedulerTest_StopPeriodicReporting() { 116 JankReportingScheduler jankReportingScheduler = createJankReportingScheduler(); 117 118 jankReportingScheduler.startReportingPeriodicMetrics(); 119 120 // When first getting the handler we need to run the initialize on the handler. 121 mShadowLooper.runOneTask(); 122 // Run tracking initialization task. 123 mShadowLooper.runOneTask(); 124 // Run the first reporting loop (delayed 30s). 125 mShadowLooper.runOneTask(); 126 // Run task to stop tracking 1st loop and record data. 127 mShadowLooper.runOneTask(); 128 // Run task to start tracking the 2nd reporting loop. 129 mShadowLooper.runOneTask(); 130 131 jankReportingScheduler.stopReportingPeriodicMetrics(); 132 133 // Stopping periodic metric recording posts a reporting loop task immediately to stop 134 // tracking and record results. 135 mShadowLooper.runOneTask(); 136 // The reporting loop task posts another immediate task to stop tracking and report data. 137 mShadowLooper.runOneTask(); 138 139 InOrder orderVerifier = Mockito.inOrder(mFrameMetricsStore); 140 141 // This start/stop pair corresponds to the first reporting period. 142 orderVerifier.verify(mFrameMetricsStore).initialize(); 143 orderVerifier 144 .verify(mFrameMetricsStore) 145 .startTrackingScenario(JankScenario.PERIODIC_REPORTING); 146 orderVerifier 147 .verify(mFrameMetricsStore) 148 .stopTrackingScenario(JankScenario.PERIODIC_REPORTING); 149 150 // Stopping reporting forces an immediate report of recorded frames, if any. 151 orderVerifier 152 .verify(mFrameMetricsStore) 153 .startTrackingScenario(JankScenario.PERIODIC_REPORTING); 154 orderVerifier 155 .verify(mFrameMetricsStore) 156 .stopTrackingScenario(JankScenario.PERIODIC_REPORTING); 157 158 // There should not be another task posted to continue the loop. 159 Assert.assertFalse(mShadowLooper.getScheduler().areAnyRunnable()); 160 } 161 } 162