1# Copyright (c) 2013 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 5import logging 6import operator 7import os 8import time 9 10from autotest_lib.client.bin import test 11from autotest_lib.client.common_lib import error 12from autotest_lib.client.common_lib.cros import chrome 13 14 15class video_YouTubePage(test.test): 16 """The main test class of this test. 17 18 """ 19 20 21 version = 1 22 23 PSEUDO_RANDOM_TIME_1 = 20.25 24 PSEUDO_RANDOM_TIME_2 = 5.47 25 26 # Minimum number of timeupdates required to fire in the last second. 27 MIN_LAST_SECOND_UPDATES = 3 28 29 NO_DELAY = 0 30 MINIMAL_DELAY = 1 31 MAX_REBUFFER_DELAY = 10 32 33 PLAYING_STATE = 'playing' 34 PAUSED_STATE = 'paused' 35 ENDED_STATE = 'ended' 36 TEST_PAGE = 'http://web-release-qa.youtube.com/watch?v=zuzaxlddWbk&html5=1' 37 38 DISABLE_COOKIES = False 39 40 tab = None 41 42 43 def initialize_test(self, chrome, player_page): 44 """Initializes the test. 45 46 @param chrome: An Autotest Chrome instance. 47 @param player_page: The URL (string) of the YouTube player page to test. 48 49 """ 50 self.tab = chrome.browser.tabs[0] 51 52 self.tab.Navigate(player_page) 53 self.tab.WaitForDocumentReadyStateToBeComplete() 54 time.sleep(2) 55 56 with open( 57 os.path.join(os.path.dirname(__file__), 58 'files/video_YouTubePageCommon.js')) as f: 59 js = f.read() 60 if not self.tab.EvaluateJavaScript(js): 61 raise error.TestFail('YouTube page failed to load.') 62 logging.info('Loaded accompanying .js script.') 63 64 65 def get_player_state(self): 66 """Simple wrapper to get the JS player state. 67 68 @returns: The state of the player (string). 69 70 """ 71 return self.tab.EvaluateJavaScript('window.__getVideoState();') 72 73 74 def play_video(self): 75 """Simple wrapper to play the video. 76 77 """ 78 self.tab.ExecuteJavaScript('window.__playVideo();') 79 80 81 def pause_video(self): 82 """Simple wrapper to pause the video. 83 84 """ 85 self.tab.ExecuteJavaScript('window.__pauseVideo();') 86 87 88 def seek_video(self, new_time): 89 """Simple wrapper to seek the video to a new time. 90 91 @param new_time: Time to seek to. 92 93 """ 94 self.tab.ExecuteJavaScript('window.__seek(%f);' % new_time) 95 96 97 def seek_to_almost_end(self, seconds_before_end): 98 """Simple wrapper to seek to almost the end of the video. 99 100 @param seconds_before_end: How many seconds (a float, not integer) 101 before end of video. 102 103 """ 104 self.tab.ExecuteJavaScript( 105 'window.__seekToAlmostEnd(%f);' % seconds_before_end) 106 107 108 def get_current_time(self): 109 """Simple wrapper to get the current time in the video. 110 111 @returns: The current time (float). 112 113 """ 114 return self.tab.EvaluateJavaScript('window.__getCurrentTime();') 115 116 117 def assert_event_state(self, event, op, error_str): 118 """Simple wrapper to get the status of a state in the video. 119 120 @param event: A string denoting the event. Check the accompanying JS 121 file for the possible values. 122 @param op: truth or not_ operator from the standard Python operator 123 module. 124 @param error_str: A string for the error output. 125 126 @returns: Whether or not the input event has fired. 127 128 """ 129 result = self.tab.EvaluateJavaScript( 130 'window.__getEventHappened("%s");' % event) 131 if not op(result): 132 raise error.TestError(error) 133 134 135 def clear_event_state(self, event): 136 """Simple wrapper to clear the status of a state in the video. 137 138 @param event: A string denoting the event. Check the accompanying JS 139 file for the possible vlaues. 140 141 """ 142 self.tab.ExecuteJavaScript('window.__clearEventHappened("%s");' % event) 143 144 145 def verify_last_second_playback(self): 146 """Simple wrapper to check the playback of the last second. 147 148 """ 149 result = self.tab.EvaluateJavaScript( 150 'window.__getLastSecondTimeupdates()') 151 if result < self.MIN_LAST_SECOND_UPDATES: 152 raise error.TestError( 153 'Last second did not play back correctly (%d events).' % 154 result) 155 156 157 def assert_player_state(self, state, max_wait_secs): 158 """Simple wrapper to busy wait and test the current state of the player. 159 160 @param state: A string denoting the expected state of the player. 161 @param max_wait_secs: Maximum amount of time to wait before failing. 162 163 @raises: A error.TestError if the state is not as expected. 164 165 """ 166 start_time = time.time() 167 while True: 168 current_state = self.get_player_state() 169 if current_state == state: 170 return 171 elif time.time() < start_time + max_wait_secs: 172 time.sleep(0.5) 173 else: 174 raise error.TestError( 175 'Current player state "%s" is not the expected state ' 176 '"%s".' % (current_state, state)) 177 178 179 def perform_test(self): 180 """Base method for derived classes to run their test. 181 182 """ 183 raise error.TestFail('Derived class did not specify a perform_test.') 184 185 186 def perform_playing_test(self): 187 """Test to check if the YT page starts off playing. 188 189 """ 190 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 191 if self.get_current_time() <= 0.0: 192 raise error.TestError('perform_playing_test failed.') 193 194 195 def perform_pausing_test(self): 196 """Test to check if the video is in the 'paused' state. 197 198 """ 199 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 200 self.pause_video() 201 self.assert_player_state(self.PAUSED_STATE, self.MINIMAL_DELAY) 202 203 204 def perform_resuming_test(self): 205 """Test to check if the video responds to resumption. 206 207 """ 208 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 209 self.pause_video() 210 self.assert_player_state(self.PAUSED_STATE, self.MINIMAL_DELAY) 211 self.play_video() 212 self.assert_player_state(self.PLAYING_STATE, self.MINIMAL_DELAY) 213 214 215 def perform_seeking_test(self): 216 """Test to check if seeking works. 217 218 """ 219 # Test seeking while playing. 220 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 221 self.seek_video(self.PSEUDO_RANDOM_TIME_1) 222 time.sleep(self.MINIMAL_DELAY) 223 if not self.tab.EvaluateJavaScript( 224 'window.__getCurrentTime() >= %f;' % self.PSEUDO_RANDOM_TIME_1): 225 raise error.TestError( 226 'perform_seeking_test failed because player time is not ' 227 'the expected time during playing seeking.') 228 self.assert_event_state( 229 'seeking', operator.truth, 230 'perform_seeking_test failed: "seeking" state did not fire.') 231 self.assert_event_state( 232 'seeked', operator.truth, 233 'perform_seeking_test failed: "seeked" state did not fire.') 234 235 # Now make sure the video is still playing. 236 237 # Let it buffer/play for at most 10 seconds before continuing. 238 self.assert_player_state(self.PLAYING_STATE, self.MAX_REBUFFER_DELAY) 239 240 self.clear_event_state('seeking'); 241 self.clear_event_state('seeked'); 242 self.assert_event_state( 243 'seeking', operator.not_, 244 'perform_seeking_test failed: ' 245 '"seeking" state did not get cleared.') 246 self.assert_event_state( 247 'seeked', operator.not_, 248 'perform_seeking_test failed: ' 249 '"seeked" state did not get cleared.') 250 251 # Test seeking while paused. 252 self.pause_video() 253 self.assert_player_state(self.PAUSED_STATE, self.MINIMAL_DELAY) 254 255 self.seek_video(self.PSEUDO_RANDOM_TIME_2) 256 time.sleep(self.MINIMAL_DELAY) 257 if not self.tab.EvaluateJavaScript( 258 'window.__getCurrentTime() === %f;' % 259 self.PSEUDO_RANDOM_TIME_2): 260 raise error.TestError( 261 'perform_seeking_test failed because player time is not ' 262 'the expected time.') 263 self.assert_event_state( 264 'seeking', operator.truth, 265 'perform_seeking_test failed: "seeking" state did not fire ' 266 'again.') 267 self.assert_event_state( 268 'seeked', operator.truth, 269 'perform_seeking_test failed: "seeked" state did not fire ' 270 'again.') 271 272 # Make sure the video is paused. 273 self.assert_player_state(self.PAUSED_STATE, self.NO_DELAY) 274 275 276 def perform_frame_drop_test(self): 277 """Test to check if there are too many dropped frames. 278 279 """ 280 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 281 time.sleep(15) 282 dropped_frames_percentage = self.tab.EvaluateJavaScript( 283 'window.__videoElement.webkitDroppedFrameCount /' 284 'window.__videoElement.webkitDecodedFrameCount') 285 if dropped_frames_percentage > 0.01: 286 raise error.TestError(( 287 'perform_frame_drop_test failed due to too many dropped ' 288 'frames (%f%%)') % (dropped_frames_percentage * 100)) 289 290 291 def perform_ending_test(self): 292 """Test to check if the state is 'ended' at the end of a video. 293 294 """ 295 ALMOST_END = 0.1 296 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 297 self.seek_to_almost_end(ALMOST_END) 298 self.assert_player_state(self.ENDED_STATE, self.MAX_REBUFFER_DELAY) 299 300 301 def perform_last_second_test(self): 302 """Test to check if the last second is played. 303 304 """ 305 NEAR_END = 2.0 306 self.assert_player_state(self.PLAYING_STATE, self.NO_DELAY) 307 self.seek_to_almost_end(NEAR_END) 308 self.assert_player_state( 309 self.ENDED_STATE, self.MAX_REBUFFER_DELAY + NEAR_END) 310 self.verify_last_second_playback() 311 312 313 def run_once(self, subtest_name): 314 """Main runner for the test. 315 316 @param subtest_name: The name of the test to run, given below. 317 318 """ 319 extension_paths = [] 320 if self.DISABLE_COOKIES: 321 # To stop the system from erasing the previous profile, enable: 322 # options.dont_override_profile = True 323 extension_path = os.path.join( 324 os.path.dirname(__file__), 325 'files/cookie-disabler') 326 extension_paths.append(extension_path) 327 328 329 with chrome.Chrome(extension_paths=extension_paths) as cr: 330 self.initialize_test(cr, self.TEST_PAGE) 331 332 if subtest_name is 'playing': 333 self.perform_playing_test() 334 elif subtest_name is 'pausing': 335 self.perform_pausing_test() 336 elif subtest_name is 'resuming': 337 self.perform_resuming_test() 338 elif subtest_name is 'seeking': 339 self.perform_seeking_test() 340 elif subtest_name is 'frame_drop': 341 self.perform_frame_drop_test() 342 elif subtest_name is 'ending': 343 self.perform_ending_test() 344 elif subtest_name is 'last_second': 345 self.perform_last_second_test() 346