1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import re 7import time 8 9import pyauto_functional 10import pyauto 11import pyauto_errors 12import test_utils 13 14 15class YoutubeTestHelper(): 16 """Helper functions for Youtube tests. 17 18 For sample usage, look at class YoutubeTest. 19 """ 20 21 # YouTube player states 22 is_unstarted = '-1' 23 is_playing = '1' 24 is_paused = '2' 25 has_ended = '0' 26 _pyauto = None 27 28 def __init__(self, pyauto): 29 self._pyauto = pyauto 30 31 def IsFlashPluginEnabled(self): 32 """Verify flash plugin availability and its state.""" 33 return [x for x in self._pyauto.GetPluginsInfo().Plugins() \ 34 if x['name'] == 'Shockwave Flash' and x['enabled']] 35 36 def AssertPlayerState(self, state, msg): 37 expected_regex = '^%s$' % state 38 self.WaitForDomNode('id("playerState")', expected_value=expected_regex, 39 msg=msg) 40 41 def WaitUntilPlayerReady(self): 42 """Verify that player is ready.""" 43 self.AssertPlayerState(state=self.is_unstarted, 44 msg='Failed to load youtube player.') 45 46 def GetPlayerState(self): 47 """Returns a player state.""" 48 js = """ 49 var val = ytplayer.getPlayerState(); 50 window.domAutomationController.send(val + ''); 51 """ 52 return self._pyauto.ExecuteJavascript(js) 53 54 def GetVideoInfo(self): 55 """Returns Youtube video info.""" 56 youtube_apis = self._pyauto.GetPrivateInfo()['youtube_api'] 57 youtube_debug_text = youtube_apis['GetDebugText'] 58 return self._pyauto.ExecuteJavascript( 59 'window.domAutomationController.send(%s);' % youtube_debug_text) 60 61 def GetVideoDroppedFrames(self): 62 """Returns total Youtube video dropped frames. 63 64 Returns: 65 -1 if failed to get video frames from the video data 66 """ 67 video_data = self._pyauto.GetVideoInfo() 68 matched = re.search('droppedFrames=([\d\.]+)', video_data) 69 if matched: 70 return int(matched.group(1)) 71 else: 72 return -1 73 74 def GetVideoFrames(self): 75 """Returns Youtube video frames/second. 76 77 Returns: 78 -1 if failed to get droppd frames from the video data. 79 """ 80 video_data = self._pyauto.GetVideoInfo() 81 matched = re.search('videoFps=([\d\.]+)', video_data) 82 if matched: 83 return int(matched.group(1)) 84 else: 85 return -1 86 87 def GetVideoTotalBytes(self): 88 """Returns video total size in bytes. 89 90 To call this function, video must be in the paying state, 91 or this returns 0. 92 """ 93 total_bytes = 0 94 total_bytes = self._pyauto.ExecuteJavascript(""" 95 bytesTotal = document.getElementById("bytesTotal"); 96 window.domAutomationController.send(bytesTotal.innerHTML); 97 """) 98 return int(total_bytes) 99 100 def GetVideoLoadedBytes(self): 101 """Returns video size in bytes.""" 102 loaded_bytes = 0 103 loaded_bytes = self.ExecuteJavascript(""" 104 bytesLoaded = document.getElementById("bytesLoaded"); 105 window.domAutomationController.send(bytesLoaded.innerHTML); 106 """) 107 return int(loaded_bytes) 108 109 def GetCurrentVideoTime(self): 110 """Returns the current time of the video in seconds.""" 111 current_time = 0 112 current_time = self.ExecuteJavascript(""" 113 videoCurrentTime = document.getElementById("videoCurrentTime"); 114 window.domAutomationController.send(videoCurrentTime.innerHTML); 115 """) 116 return int(current_time) 117 118 def PlayVideo(self): 119 """Plays the loaded video.""" 120 self._pyauto.ExecuteJavascript(""" 121 ytplayer.playVideo(); 122 window.domAutomationController.send(''); 123 """) 124 125 def StopVideo(self): 126 """Stops the video and cancels loading.""" 127 self._pyauto.ExecuteJavascript(""" 128 ytplayer.stopVideo(); 129 window.domAutomationController.send(''); 130 """) 131 132 def PauseVideo(self): 133 """Pause the video.""" 134 self.ExecuteJavascript(""" 135 ytplayer.pauseVideo(); 136 window.domAutomationController.send(''); 137 """) 138 139 def PlayVideoAndAssert(self, youtube_video='zuzaxlddWbk', 140 ignore_assert=False): 141 """Start video and assert the playing state. 142 143 By default test uses http://www.youtube.com/watch?v=zuzaxlddWbki. 144 145 Args: 146 youtube_video: The string ID of the youtube video to play. 147 ignore_assert: flag to ignore the assertion and continue the test. 148 """ 149 self._pyauto.assertTrue(self._pyauto.IsFlashPluginEnabled(), 150 msg='From here Flash plugin is disabled or not available.') 151 url = self._pyauto.GetHttpURLForDataPath( 152 'media', 'youtube.html?video=' + youtube_video) 153 self._pyauto.NavigateToURL(url) 154 self.WaitUntilPlayerReady() 155 i = 0 156 # The YouTube player will get in a state where it does not return the 157 # number of loaded bytes. When this happens we need to reload the page 158 # before starting the test. 159 while self.GetVideoLoadedBytes() == 1 and i < 30: 160 self._pyauto.NavigateToURL(url) 161 self.WaitUntilPlayerReady() 162 i = i + 1 163 self.PlayVideo() 164 if ignore_assert: 165 return self.is_playing 166 self.AssertPlayerState(state=self.is_playing, 167 msg='Player did not enter the playing state.') 168 169 def VideoBytesLoadingAndAssert(self): 170 """Assert the video loading.""" 171 total_bytes = self.GetVideoTotalBytes() 172 prev_loaded_bytes = 0 173 loaded_bytes = 0 174 count = 0 175 while loaded_bytes < total_bytes: 176 # We want to test bytes loading only twice 177 count = count + 1 178 if count == 2: 179 break 180 loaded_bytes = self.GetVideoLoadedBytes() 181 self.assertTrue(prev_loaded_bytes <= loaded_bytes) 182 prev_loaded_bytes = loaded_bytes 183 # Give some time to load a video 184 time.sleep(1) 185 186 def PlayFAVideo(self): 187 """Play and assert FA video playing. 188 189 We are using multiple test videos in case any FA video playback fails 190 becuase other tests are palying the same video and the test gets the 191 simultaneous playback error. 192 """ 193 fa_videos = ('APRpcscmbY0', 'yQqvrED-np0', 'KJuFw6hQdNY', 194 'BeFQbgxr_9g', 'L6JwlOudqA4') 195 credentials = self.GetPrivateInfo()['test_fa_account'] 196 test_utils.GoogleAccountsLogin(self, 197 credentials['username'], credentials['password']) 198 for video in fa_videos: 199 result = self.PlayVideoAndAssert(video, ignore_assert=True) 200 if result is self.is_playing: 201 return 202 self.assertTrue(False, msg='Player did not enter the playing state.') 203 204 205class YoutubeTest(pyauto.PyUITest, YoutubeTestHelper): 206 """Test case for Youtube videos.""" 207 208 def __init__(self, methodName='runTest', **kwargs): 209 pyauto.PyUITest.__init__(self, methodName, **kwargs) 210 YoutubeTestHelper.__init__(self, self) 211 212 def testPlayerStatus(self): 213 """Test that YouTube loads a player and changes player states. 214 215 Test verifies various player states like unstarted, playing, paused 216 and ended. 217 """ 218 # Navigating to Youtube video. This video is 122 seconds long. 219 # During tests, we are not goinig to play this video full. 220 self.PlayVideoAndAssert() 221 self.PauseVideo() 222 self.AssertPlayerState(state=self.is_paused, 223 msg='Player did not enter the paused state.') 224 # Seek to the end of video 225 self.ExecuteJavascript(""" 226 val = ytplayer.getDuration(); 227 ytplayer.seekTo(val, true); 228 window.domAutomationController.send(''); 229 """) 230 self.PlayVideo() 231 # We've seeked to almost the end of the video but not quite. 232 # Wait until the end. 233 self.AssertPlayerState(state=self.has_ended, 234 msg='Player did not reach the stopped state.') 235 236 def testPlayerResolution(self): 237 """Test various video resolutions.""" 238 self.PlayVideoAndAssert() 239 resolutions = self.ExecuteJavascript(""" 240 res = ytplayer.getAvailableQualityLevels(); 241 window.domAutomationController.send(res.toString()); 242 """) 243 resolutions = resolutions.split(',') 244 for res in resolutions: 245 self.ExecuteJavascript(""" 246 ytplayer.setPlaybackQuality('%s'); 247 window.domAutomationController.send(''); 248 """ % res) 249 curr_res = self.ExecuteJavascript(""" 250 res = ytplayer.getPlaybackQuality(); 251 window.domAutomationController.send(res + ''); 252 """) 253 self.assertEqual(res, curr_res, msg='Resolution is not set to %s.' % res) 254 255 def testPlayerBytes(self): 256 """Test that player downloads video bytes.""" 257 self.PlayVideoAndAssert() 258 self.VideoBytesLoadingAndAssert() 259 260 def testFAVideo(self): 261 """Test that FlashAccess/DRM video plays.""" 262 self.PlayFAVideo() 263 self.StopVideo() 264 265 def testFAVideoBytes(self): 266 """Test FlashAccess/DRM video bytes loading.""" 267 self.PlayFAVideo() 268 self.VideoBytesLoadingAndAssert() 269 self.StopVideo() 270 271 272if __name__ == '__main__': 273 pyauto_functional.Main() 274