Home | History | Annotate | Download | only in functional
      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 
      6 import os
      7 import platform
      8 import re
      9 import subprocess
     10 
     11 import pyauto
     12 
     13 
     14 class MissingRequiredBinaryException(Exception):
     15   pass
     16 
     17 
     18 class WebrtcTestBase(pyauto.PyUITest):
     19   """This base class provides helpers for WebRTC calls."""
     20 
     21   DEFAULT_TEST_PAGE = 'webrtc_jsep01_test.html'
     22 
     23   def ExtraChromeFlags(self):
     24     """Adds flags to the Chrome command line."""
     25     extra_flags = ['--enable-data-channels', '--enable-dcheck']
     26     return pyauto.PyUITest.ExtraChromeFlags(self) + extra_flags
     27 
     28   def LoadTestPageInTwoTabs(self, test_page=DEFAULT_TEST_PAGE):
     29     url = self.GetFileURLForDataPath('webrtc', test_page)
     30     self.NavigateToURL(url)
     31     self.AppendTab(pyauto.GURL(url))
     32 
     33   def LoadTestPageInOneTab(self, test_page=DEFAULT_TEST_PAGE):
     34     url = self.GetFileURLForDataPath('webrtc', test_page)
     35     self.NavigateToURL(url)
     36 
     37   def GetUserMedia(self, tab_index, action='accept',
     38                    request_video=True, request_audio=True):
     39     """Acquires webcam or mic for one tab and returns the result.
     40 
     41     Args:
     42       tab_index: The tab to request user media on.
     43       action: The action to take on the info bar. Can be 'accept', 'cancel' or
     44           'dismiss'.
     45       request_video: Whether to request video.
     46       request_audio: Whether to request audio.
     47 
     48     Returns:
     49       A string as specified by the getUserMedia javascript function.
     50     """
     51     constraints = '{ video: %s, audio: %s }' % (str(request_video).lower(),
     52                                                 str(request_audio).lower())
     53     self.assertEquals('ok-requested', self.ExecuteJavascript(
     54         'getUserMedia("%s")' % constraints, tab_index=tab_index))
     55 
     56     self.WaitForInfobarCount(1, tab_index=tab_index)
     57     self.PerformActionOnInfobar(action, infobar_index=0, tab_index=tab_index)
     58     self.WaitForGetUserMediaResult(tab_index=0)
     59 
     60     result = self.GetUserMediaResult(tab_index=0)
     61     self.AssertNoFailures(tab_index)
     62     return result
     63 
     64   def WaitForGetUserMediaResult(self, tab_index):
     65     """Waits until WebRTC has responded to a getUserMedia query.
     66 
     67     Fails an assert if WebRTC doesn't respond within the default timeout.
     68 
     69     Args:
     70       tab_index: the tab to query.
     71     """
     72     def HasResult():
     73       return self.GetUserMediaResult(tab_index) != 'not-called-yet'
     74     self.assertTrue(self.WaitUntil(HasResult),
     75                     msg='Timed out while waiting for getUserMedia callback.')
     76 
     77   def GetUserMediaResult(self, tab_index):
     78     """Retrieves WebRTC's answer to a user media query.
     79 
     80     Args:
     81       tab_index: the tab to query.
     82 
     83     Returns:
     84       Specified in obtainGetUserMediaResult() in getusermedia.js.
     85     """
     86     return self.ExecuteJavascript(
     87         'obtainGetUserMediaResult()', tab_index=tab_index)
     88 
     89   def AssertNoFailures(self, tab_index):
     90     """Ensures the javascript hasn't registered any asynchronous errors.
     91 
     92     Args:
     93       tab_index: The tab to check.
     94     """
     95     self.assertEquals('ok-no-errors', self.ExecuteJavascript(
     96         'getAnyTestFailures()', tab_index=tab_index))
     97 
     98   def Connect(self, user_name, tab_index):
     99     self.assertEquals('ok-connected', self.ExecuteJavascript(
    100         'connect("http://localhost:8888", "%s")' % user_name,
    101         tab_index=tab_index))
    102     self.AssertNoFailures(tab_index)
    103 
    104   def CreatePeerConnection(self, tab_index):
    105     self.assertEquals('ok-peerconnection-created', self.ExecuteJavascript(
    106         'preparePeerConnection()', tab_index=tab_index))
    107 
    108   def AddUserMediaLocalStream(self, tab_index):
    109     self.assertEquals('ok-added', self.ExecuteJavascript(
    110         'addLocalStream()', tab_index=tab_index))
    111 
    112   def AddWebAudioFile(self, tab_index, input_relative_path):
    113     """The path must be relative to where the javascript is.
    114 
    115     This call just loads and adds a file to a peer connection, but it doesn't
    116     start to play it until you call PlayWebAudioFile.
    117     """
    118     self.assertEquals('ok-added', self.ExecuteJavascript(
    119         'addAudioFile("%s")' % re.escape(input_relative_path),
    120         tab_index=tab_index))
    121 
    122   def PlayWebAudioFile(self, tab_index):
    123     """Plays a web audio file which was added earlier."""
    124     self.assertEquals('ok-playing', self.ExecuteJavascript(
    125         'playAudioFile()', tab_index=tab_index))
    126 
    127   def EstablishCall(self, from_tab_with_index, to_tab_with_index):
    128     self.WaitUntilPeerConnects(tab_index=from_tab_with_index)
    129 
    130     self.assertEquals('ok-negotiating', self.ExecuteJavascript(
    131         'negotiateCall()', tab_index=from_tab_with_index))
    132     self.AssertNoFailures(from_tab_with_index)
    133 
    134     self.WaitUntilReadyState(ready_state='active',
    135                              tab_index=from_tab_with_index)
    136 
    137     # Double-check the call reached the other side.
    138     self.WaitUntilReadyState(ready_state='active',
    139                              tab_index=to_tab_with_index)
    140 
    141   def HangUp(self, from_tab_with_index):
    142     self.assertEquals('ok-call-hung-up', self.ExecuteJavascript(
    143         'hangUp()', tab_index=from_tab_with_index))
    144     self.WaitUntilHangUpVerified(tab_index=from_tab_with_index)
    145     self.AssertNoFailures(tab_index=from_tab_with_index)
    146 
    147   def WaitUntilPeerConnects(self, tab_index):
    148     peer_connected = self.WaitUntil(
    149         function=lambda: self.ExecuteJavascript('remotePeerIsConnected()',
    150                                                 tab_index=tab_index),
    151         expect_retval='peer-connected')
    152     self.assertTrue(peer_connected,
    153                     msg='Timed out while waiting for peer to connect.')
    154 
    155   def WaitUntilReadyState(self, ready_state, tab_index):
    156     got_ready_state = self.WaitUntil(
    157         function=lambda: self.ExecuteJavascript('getPeerConnectionReadyState()',
    158                                                 tab_index=tab_index),
    159         expect_retval=ready_state)
    160     self.assertTrue(got_ready_state,
    161                     msg=('Timed out while waiting for peer connection ready '
    162                          'state to change to %s for tab %d.' % (ready_state,
    163                                                                 tab_index)))
    164 
    165   def WaitUntilHangUpVerified(self, tab_index):
    166     self.WaitUntilReadyState('no-peer-connection', tab_index=tab_index)
    167 
    168   def Disconnect(self, tab_index):
    169     self.assertEquals('ok-disconnected', self.ExecuteJavascript(
    170         'disconnect()', tab_index=tab_index))
    171 
    172   def BinPathForPlatform(self, path):
    173     """Form a platform specific path to a binary.
    174 
    175     Args:
    176       path(string): The path to the binary without an extension.
    177     Return:
    178       (string): The platform-specific bin path.
    179     """
    180     if self.IsWin():
    181       path += '.exe'
    182     return path
    183 
    184   def PlatformIsWinXP(self):
    185     """Check if the executing platform is Windows XP.
    186 
    187     Return:
    188       True if the platform is Windows XP.
    189     """
    190     return platform.system() == 'Windows' and platform.release() == 'XP'
    191 
    192   def StartPeerConnectionServer(self):
    193     """Starts peerconnection_server.
    194 
    195     Peerconnection_server is a custom binary allowing two WebRTC clients to find
    196     each other. For more details, see the source code which is available at the
    197     site http://code.google.com/p/libjingle/source/browse/ (make sure to browse
    198     to trunk/talk/examples/peerconnection/server).
    199     """
    200     # Start the peerconnection_server. It should be next to chrome.
    201     binary_path = os.path.join(self.BrowserPath(), 'peerconnection_server')
    202     binary_path = self.BinPathForPlatform(binary_path)
    203 
    204     if not os.path.exists(binary_path):
    205       raise MissingRequiredBinaryException(
    206         'Could not locate peerconnection_server. Have you built the '
    207         'peerconnection_server target? We expect to have a '
    208         'peerconnection_server binary next to the chrome binary.')
    209 
    210     self._server_process = subprocess.Popen(binary_path)
    211 
    212   def StopPeerConnectionServer(self):
    213     """Stops the peerconnection_server."""
    214     assert self._server_process
    215     self._server_process.kill()
    216