1 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 import time 5 import unittest 6 7 from measurements import smooth_gesture_util as sg_util 8 from telemetry.core.platform import tracing_category_filter 9 from telemetry.core.platform import tracing_options 10 from telemetry.page import page as page_module 11 from telemetry.page import page_test 12 from telemetry.timeline import async_slice 13 from telemetry.timeline import model as model_module 14 from telemetry.unittest import page_test_test_case 15 from telemetry.web_perf import timeline_interaction_record as tir_module 16 17 18 class SmoothGestureUtilTest(unittest.TestCase): 19 def testGetAdjustedInteractionIfContainGesture(self): 20 model = model_module.TimelineModel() 21 renderer_main = model.GetOrCreateProcess(1).GetOrCreateThread(2) 22 renderer_main.name = 'CrRendererMain' 23 24 # [ X ] [ Y ] 25 # [ sub_async_slice_X ] 26 # [ record_1] 27 # [ record_6] 28 # [ record_2 ] [ record_3 ] 29 # [ record_4 ] 30 # [ record_5 ] 31 # 32 # Note: X and Y are async slice with name 33 # SyntheticGestureController::running 34 35 async_slice_X = async_slice.AsyncSlice( 36 'X', 'SyntheticGestureController::running', 10, duration=20, 37 start_thread=renderer_main, end_thread=renderer_main) 38 39 sub_async_slice_X = async_slice.AsyncSlice( 40 'X', 'SyntheticGestureController::running', 10, duration=20, 41 start_thread=renderer_main, end_thread=renderer_main) 42 sub_async_slice_X.parent_slice = async_slice_X 43 async_slice_X.AddSubSlice(sub_async_slice_X) 44 45 async_slice_Y = async_slice.AsyncSlice( 46 'X', 'SyntheticGestureController::running', 60, duration=20, 47 start_thread=renderer_main, end_thread=renderer_main) 48 49 renderer_main.AddAsyncSlice(async_slice_X) 50 renderer_main.AddAsyncSlice(async_slice_Y) 51 52 model.FinalizeImport(shift_world_to_zero=False) 53 54 record_1 = tir_module.TimelineInteractionRecord('Gesture_included', 15, 25) 55 record_2 = tir_module.TimelineInteractionRecord( 56 'Gesture_overlapped_left', 5, 25) 57 record_3 = tir_module.TimelineInteractionRecord( 58 'Gesture_overlapped_right', 25, 35) 59 record_4 = tir_module.TimelineInteractionRecord( 60 'Gesture_containing', 5, 35) 61 record_5 = tir_module.TimelineInteractionRecord( 62 'Gesture_non_overlapped', 35, 45) 63 record_6 = tir_module.TimelineInteractionRecord('Action_included', 15, 25) 64 65 adjusted_record_1 = sg_util.GetAdjustedInteractionIfContainGesture( 66 model, record_1) 67 self.assertEquals(adjusted_record_1.start, 10) 68 self.assertEquals(adjusted_record_1.end, 30) 69 self.assertTrue(adjusted_record_1 is not record_1) 70 71 adjusted_record_2 = sg_util.GetAdjustedInteractionIfContainGesture( 72 model, record_2) 73 self.assertEquals(adjusted_record_2.start, 10) 74 self.assertEquals(adjusted_record_2.end, 30) 75 76 adjusted_record_3 = sg_util.GetAdjustedInteractionIfContainGesture( 77 model, record_3) 78 self.assertEquals(adjusted_record_3.start, 10) 79 self.assertEquals(adjusted_record_3.end, 30) 80 81 adjusted_record_4 = sg_util.GetAdjustedInteractionIfContainGesture( 82 model, record_4) 83 self.assertEquals(adjusted_record_4.start, 10) 84 self.assertEquals(adjusted_record_4.end, 30) 85 86 adjusted_record_5 = sg_util.GetAdjustedInteractionIfContainGesture( 87 model, record_5) 88 self.assertEquals(adjusted_record_5.start, 35) 89 self.assertEquals(adjusted_record_5.end, 45) 90 self.assertTrue(adjusted_record_5 is not record_5) 91 92 adjusted_record_6 = sg_util.GetAdjustedInteractionIfContainGesture( 93 model, record_6) 94 self.assertEquals(adjusted_record_6.start, 15) 95 self.assertEquals(adjusted_record_6.end, 25) 96 self.assertTrue(adjusted_record_6 is not record_6) 97 98 99 class ScrollingPage(page_module.Page): 100 def __init__(self, url, page_set, base_dir): 101 super(ScrollingPage, self).__init__(url, page_set, base_dir) 102 103 def RunSmoothness(self, action_runner): 104 interaction = action_runner.BeginGestureInteraction( 105 'ScrollAction', is_smooth=True) 106 # Add 0.5s gap between when Gesture records are issued to when we actually 107 # scroll the page. 108 time.sleep(0.5) 109 action_runner.ScrollPage() 110 time.sleep(0.5) 111 interaction.End() 112 113 114 class SmoothGestureTest(page_test_test_case.PageTestTestCase): 115 def testSmoothGestureAdjusted(self): 116 ps = self.CreateEmptyPageSet() 117 ps.AddPage(ScrollingPage( 118 'file://scrollable_page.html', ps, base_dir=ps.base_dir)) 119 models = [] 120 tab_ids = [] 121 class ScrollingGestureTestMeasurement(page_test.PageTest): 122 def __init__(self): 123 super(ScrollingGestureTestMeasurement, self).__init__( 124 'RunSmoothness', False) 125 126 def WillRunActions(self, _page, tab): 127 options = tracing_options.TracingOptions() 128 options.enable_chrome_trace = True 129 tab.browser.platform.tracing_controller.Start( 130 options, tracing_category_filter.TracingCategoryFilter()) 131 132 def DidRunActions(self, _page, tab): 133 models.append(model_module.TimelineModel( 134 tab.browser.platform.tracing_controller.Stop())) 135 tab_ids.append(tab.id) 136 137 self.RunMeasurement(ScrollingGestureTestMeasurement(), ps) 138 timeline_model = models[0] 139 renderer_thread = timeline_model.GetRendererThreadFromTabId( 140 tab_ids[0]) 141 smooth_record = None 142 for e in renderer_thread.async_slices: 143 if tir_module.IsTimelineInteractionRecord(e.name): 144 smooth_record = tir_module.TimelineInteractionRecord.FromAsyncEvent(e) 145 self.assertIsNotNone(smooth_record) 146 adjusted_smooth_gesture = ( 147 sg_util.GetAdjustedInteractionIfContainGesture( 148 timeline_model, smooth_record)) 149 # Test that the scroll gesture starts at at least 500ms after the start of 150 # the interaction record and ends at at least 500ms before the end of 151 # interaction record. 152 self.assertLessEqual( 153 500, adjusted_smooth_gesture.start - smooth_record.start) 154 self.assertLessEqual( 155 500, smooth_record.end - adjusted_smooth_gesture.end) 156