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. 4import time 5import unittest 6 7from telemetry import decorators 8from telemetry.page import page as page_module 9from telemetry.page import legacy_page_test 10from telemetry.testing import page_test_test_case 11from telemetry.timeline import async_slice 12from telemetry.timeline import model as model_module 13from telemetry.timeline import tracing_config 14from telemetry.web_perf import smooth_gesture_util as sg_util 15from telemetry.web_perf import timeline_interaction_record as tir_module 16 17 18class 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 99class 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 RunPageInteractions(self, action_runner): 104 with action_runner.CreateGestureInteraction('ScrollAction'): 105 # Add 0.5s gap between when Gesture records are issued to when we actually 106 # scroll the page. 107 time.sleep(0.5) 108 action_runner.ScrollPage() 109 time.sleep(0.5) 110 111 112class SmoothGestureTest(page_test_test_case.PageTestTestCase): 113 114 @decorators.Disabled('chromeos') # crbug.com/483212 115 @decorators.Isolated # Needed because of py_trace_event 116 def testSmoothGestureAdjusted(self): 117 ps = self.CreateEmptyPageSet() 118 ps.AddStory(ScrollingPage( 119 'file://scrollable_page.html', ps, base_dir=ps.base_dir)) 120 models = [] 121 tab_ids = [] 122 class ScrollingGestureTestMeasurement(legacy_page_test.LegacyPageTest): 123 def __init__(self): 124 # pylint: disable=bad-super-call 125 super(ScrollingGestureTestMeasurement, self).__init__() 126 127 def WillNavigateToPage(self, page, tab): 128 del page # unused 129 config = tracing_config.TracingConfig() 130 config.enable_chrome_trace = True 131 tab.browser.platform.tracing_controller.StartTracing(config) 132 133 def ValidateAndMeasurePage(self, page, tab, results): 134 del page, results # unused 135 models.append(model_module.TimelineModel( 136 tab.browser.platform.tracing_controller.StopTracing())) 137 tab_ids.append(tab.id) 138 139 self.RunMeasurement(ScrollingGestureTestMeasurement(), ps) 140 timeline_model = models[0] 141 renderer_thread = timeline_model.GetRendererThreadFromTabId( 142 tab_ids[0]) 143 smooth_record = None 144 for e in renderer_thread.async_slices: 145 if tir_module.IsTimelineInteractionRecord(e.name): 146 smooth_record = tir_module.TimelineInteractionRecord.FromAsyncEvent(e) 147 self.assertIsNotNone(smooth_record) 148 adjusted_smooth_gesture = ( 149 sg_util.GetAdjustedInteractionIfContainGesture( 150 timeline_model, smooth_record)) 151 # Test that the scroll gesture starts at at least 500ms after the start of 152 # the interaction record and ends at at least 500ms before the end of 153 # interaction record. 154 self.assertLessEqual( 155 500, adjusted_smooth_gesture.start - smooth_record.start) 156 self.assertLessEqual( 157 500, smooth_record.end - adjusted_smooth_gesture.end) 158