#!/usr/bin/env python # Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import re import time import pyauto_functional import pyauto import pyauto_errors import test_utils class YoutubeTestHelper(): """Helper functions for Youtube tests. For sample usage, look at class YoutubeTest. """ # YouTube player states is_unstarted = '-1' is_playing = '1' is_paused = '2' has_ended = '0' _pyauto = None def __init__(self, pyauto): self._pyauto = pyauto def IsFlashPluginEnabled(self): """Verify flash plugin availability and its state.""" return [x for x in self._pyauto.GetPluginsInfo().Plugins() \ if x['name'] == 'Shockwave Flash' and x['enabled']] def AssertPlayerState(self, state, msg): expected_regex = '^%s$' % state self.WaitForDomNode('id("playerState")', expected_value=expected_regex, msg=msg) def WaitUntilPlayerReady(self): """Verify that player is ready.""" self.AssertPlayerState(state=self.is_unstarted, msg='Failed to load youtube player.') def GetPlayerState(self): """Returns a player state.""" js = """ var val = ytplayer.getPlayerState(); window.domAutomationController.send(val + ''); """ return self._pyauto.ExecuteJavascript(js) def GetVideoInfo(self): """Returns Youtube video info.""" youtube_apis = self._pyauto.GetPrivateInfo()['youtube_api'] youtube_debug_text = youtube_apis['GetDebugText'] return self._pyauto.ExecuteJavascript( 'window.domAutomationController.send(%s);' % youtube_debug_text) def GetVideoDroppedFrames(self): """Returns total Youtube video dropped frames. Returns: -1 if failed to get video frames from the video data """ video_data = self._pyauto.GetVideoInfo() matched = re.search('droppedFrames=([\d\.]+)', video_data) if matched: return int(matched.group(1)) else: return -1 def GetVideoFrames(self): """Returns Youtube video frames/second. Returns: -1 if failed to get droppd frames from the video data. """ video_data = self._pyauto.GetVideoInfo() matched = re.search('videoFps=([\d\.]+)', video_data) if matched: return int(matched.group(1)) else: return -1 def GetVideoTotalBytes(self): """Returns video total size in bytes. To call this function, video must be in the paying state, or this returns 0. """ total_bytes = 0 total_bytes = self._pyauto.ExecuteJavascript(""" bytesTotal = document.getElementById("bytesTotal"); window.domAutomationController.send(bytesTotal.innerHTML); """) return int(total_bytes) def GetVideoLoadedBytes(self): """Returns video size in bytes.""" loaded_bytes = 0 loaded_bytes = self.ExecuteJavascript(""" bytesLoaded = document.getElementById("bytesLoaded"); window.domAutomationController.send(bytesLoaded.innerHTML); """) return int(loaded_bytes) def GetCurrentVideoTime(self): """Returns the current time of the video in seconds.""" current_time = 0 current_time = self.ExecuteJavascript(""" videoCurrentTime = document.getElementById("videoCurrentTime"); window.domAutomationController.send(videoCurrentTime.innerHTML); """) return int(current_time) def PlayVideo(self): """Plays the loaded video.""" self._pyauto.ExecuteJavascript(""" ytplayer.playVideo(); window.domAutomationController.send(''); """) def StopVideo(self): """Stops the video and cancels loading.""" self._pyauto.ExecuteJavascript(""" ytplayer.stopVideo(); window.domAutomationController.send(''); """) def PauseVideo(self): """Pause the video.""" self.ExecuteJavascript(""" ytplayer.pauseVideo(); window.domAutomationController.send(''); """) def PlayVideoAndAssert(self, youtube_video='zuzaxlddWbk', ignore_assert=False): """Start video and assert the playing state. By default test uses http://www.youtube.com/watch?v=zuzaxlddWbki. Args: youtube_video: The string ID of the youtube video to play. ignore_assert: flag to ignore the assertion and continue the test. """ self._pyauto.assertTrue(self._pyauto.IsFlashPluginEnabled(), msg='From here Flash plugin is disabled or not available.') url = self._pyauto.GetHttpURLForDataPath( 'media', 'youtube.html?video=' + youtube_video) self._pyauto.NavigateToURL(url) self.WaitUntilPlayerReady() i = 0 # The YouTube player will get in a state where it does not return the # number of loaded bytes. When this happens we need to reload the page # before starting the test. while self.GetVideoLoadedBytes() == 1 and i < 30: self._pyauto.NavigateToURL(url) self.WaitUntilPlayerReady() i = i + 1 self.PlayVideo() if ignore_assert: return self.is_playing self.AssertPlayerState(state=self.is_playing, msg='Player did not enter the playing state.') def VideoBytesLoadingAndAssert(self): """Assert the video loading.""" total_bytes = self.GetVideoTotalBytes() prev_loaded_bytes = 0 loaded_bytes = 0 count = 0 while loaded_bytes < total_bytes: # We want to test bytes loading only twice count = count + 1 if count == 2: break loaded_bytes = self.GetVideoLoadedBytes() self.assertTrue(prev_loaded_bytes <= loaded_bytes) prev_loaded_bytes = loaded_bytes # Give some time to load a video time.sleep(1) def PlayFAVideo(self): """Play and assert FA video playing. We are using multiple test videos in case any FA video playback fails becuase other tests are palying the same video and the test gets the simultaneous playback error. """ fa_videos = ('APRpcscmbY0', 'yQqvrED-np0', 'KJuFw6hQdNY', 'BeFQbgxr_9g', 'L6JwlOudqA4') credentials = self.GetPrivateInfo()['test_fa_account'] test_utils.GoogleAccountsLogin(self, credentials['username'], credentials['password']) for video in fa_videos: result = self.PlayVideoAndAssert(video, ignore_assert=True) if result is self.is_playing: return self.assertTrue(False, msg='Player did not enter the playing state.') class YoutubeTest(pyauto.PyUITest, YoutubeTestHelper): """Test case for Youtube videos.""" def __init__(self, methodName='runTest', **kwargs): pyauto.PyUITest.__init__(self, methodName, **kwargs) YoutubeTestHelper.__init__(self, self) def testPlayerStatus(self): """Test that YouTube loads a player and changes player states. Test verifies various player states like unstarted, playing, paused and ended. """ # Navigating to Youtube video. This video is 122 seconds long. # During tests, we are not goinig to play this video full. self.PlayVideoAndAssert() self.PauseVideo() self.AssertPlayerState(state=self.is_paused, msg='Player did not enter the paused state.') # Seek to the end of video self.ExecuteJavascript(""" val = ytplayer.getDuration(); ytplayer.seekTo(val, true); window.domAutomationController.send(''); """) self.PlayVideo() # We've seeked to almost the end of the video but not quite. # Wait until the end. self.AssertPlayerState(state=self.has_ended, msg='Player did not reach the stopped state.') def testPlayerResolution(self): """Test various video resolutions.""" self.PlayVideoAndAssert() resolutions = self.ExecuteJavascript(""" res = ytplayer.getAvailableQualityLevels(); window.domAutomationController.send(res.toString()); """) resolutions = resolutions.split(',') for res in resolutions: self.ExecuteJavascript(""" ytplayer.setPlaybackQuality('%s'); window.domAutomationController.send(''); """ % res) curr_res = self.ExecuteJavascript(""" res = ytplayer.getPlaybackQuality(); window.domAutomationController.send(res + ''); """) self.assertEqual(res, curr_res, msg='Resolution is not set to %s.' % res) def testPlayerBytes(self): """Test that player downloads video bytes.""" self.PlayVideoAndAssert() self.VideoBytesLoadingAndAssert() def testFAVideo(self): """Test that FlashAccess/DRM video plays.""" self.PlayFAVideo() self.StopVideo() def testFAVideoBytes(self): """Test FlashAccess/DRM video bytes loading.""" self.PlayFAVideo() self.VideoBytesLoadingAndAssert() self.StopVideo() if __name__ == '__main__': pyauto_functional.Main()