Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3165)

Unified Diff: chrome/test/pyautolib/chromotinglib.py

Issue 10821015: Initial checkin of the me2me pyauto automation: (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/test/pyautolib/chromoting_key.p12 ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/pyautolib/chromotinglib.py
===================================================================
--- chrome/test/pyautolib/chromotinglib.py (revision 0)
+++ chrome/test/pyautolib/chromotinglib.py (revision 0)
@@ -0,0 +1,534 @@
+# 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.
+
+"""Includes different methods to drive chromoting UI."""
+
+import os
+import subprocess
+import sys
+import time
+
+from pyauto_errors import JSONInterfaceError
+
+
+class ChromotingMixIn(object):
+ """MixIn for PyUITest that adds Chromoting-specific methods.
+
+ Prepend it as a base class of a test to enable Chromoting functionality.
+ This is a separate class from PyUITest to avoid namespace collisions.
+
+ Example usage:
+ class ChromotingExample(chromoting.ChromotingMixIn, pyauto.PyUITest):
+ def testShare(self):
+ app = self.InstallApp(self.GetWebappPath())
+ self.LaunchApp(app)
+ self.Authenticate()
+ self.assertTrue(self.Share())
+ """
+
+ def _ExecuteJavascript(self, command, tab_index, windex):
+ """Helper that returns immediately after running a Javascript command.
+ """
+ try:
+ self.ExecuteJavascript(
+ '%s; window.domAutomationController.send("done");' % command,
+ tab_index, windex)
+ return True
+ except JSONInterfaceError:
+ print '_ExecuteJavascript threw JSONInterfaceError'
+ return False
+
+ def _WaitForJavascriptCondition(self, condition, tab_index, windex):
+ """Waits until the Javascript condition is true.
+
+ This is different from a naive self.WaitUntil(lambda: self.GetDOMValue())
+ because it uses Javascript to check the condition instead of Python.
+
+ Returns: True if condition is satisfied or otherwise False.
+ """
+ try:
+ return self.WaitUntil(lambda: self.GetDOMValue(
+ '(%s) ? "1" : ""' % condition, tab_index, windex))
+ except JSONInterfaceError:
+ print '_WaitForJavascriptCondition threw JSONInterfaceError'
+ return False
+
+ def _ExecuteAndWaitForMode(self, command, mode, tab_index, windex):
+ """ Executes JavaScript and wait for remoting app mode equal to
+ the given mode.
+
+ Returns: True if condition is satisfied or otherwise False.
+ """
+ if not self._ExecuteJavascript(command, tab_index, windex):
+ return False
+ return self._WaitForJavascriptCondition(
+ 'remoting.currentMode == remoting.AppMode.%s' % mode,
+ tab_index, windex)
+
+ def _ExecuteAndWaitForMajorMode(self, command, mode, tab_index, windex):
+ """ Executes JavaScript and wait for remoting app major mode equal to
+ the given mode.
+
+ Returns: True if condition is satisfied or otherwise False.
+ """
+ if not self._ExecuteJavascript(command, tab_index, windex):
+ return False
+ return self._WaitForJavascriptCondition(
+ 'remoting.getMajorMode() == remoting.AppMode.%s' % mode,
+ tab_index, windex)
+
+ def GetWebappPath(self):
+ """Returns the path to the webapp.
+
+ Expects the webapp to be in the same place as the pyautolib binaries.
+ """
+ return os.path.join(self.BrowserPath(), 'remoting', 'remoting.webapp')
+
+ def _GetHelperRunner(self):
+ """Returns the python binary name that runs chromoting_helper.py."""
+ if sys.platform.startswith('win'):
+ return 'python'
+ else:
+ return 'suid-python'
+
+ def _GetHelper(self):
+ """Get chromoting_helper.py."""
+ return os.path.join('chrome', 'test', 'pyautolib', 'chromoting_helper.py')
+
+ def InstallHostDaemon(self):
+ """Installs the host daemon."""
+ subprocess.call([self._GetHelperRunner(), self._GetHelper(),
+ 'install', self.BrowserPath()])
+
+ def UninstallHostDaemon(self):
+ """Uninstalls the host daemon."""
+ subprocess.call([self._GetHelperRunner(), self._GetHelper(),
+ 'uninstall', self.BrowserPath()])
+
+ def ContinueAuth(self, tab_index=1, windex=0):
+ """Starts authentication."""
+ self.assertTrue(
+ self._WaitForJavascriptCondition('window.remoting && remoting.oauth2',
+ tab_index, windex),
+ msg='Timed out while waiting for remoting app to finish loading.')
+ self._ExecuteJavascript('remoting.oauth2.doAuthRedirect();',
+ tab_index, windex)
+
+ def SignIn(self, email=None, password=None, otp=None,
+ tab_index=1, windex=0):
+ """Logs a user in.
+
+ PyAuto tests start with a clean profile, so Chromoting tests should call
+ this for every run after launching the app. If email or password is
+ omitted, the user can type it into the browser window manually.
+ """
+ self.assertTrue(
+ self._WaitForJavascriptCondition('document.getElementById("signIn")',
+ tab_index, windex),
+ msg='Unable to redirect for authentication.')
+
+ if email:
+ self._ExecuteJavascript('document.getElementById("Email").value = "%s";'
+ 'document.getElementById("Passwd").focus();'
+ % email, tab_index, windex)
+
+ if password:
+ self._ExecuteJavascript('document.getElementById("Passwd").value = "%s";'
+ 'document.getElementById("signIn").click();'
+ % password, tab_index, windex)
+
+ if otp:
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("smsVerifyPin")',
+ tab_index, windex),
+ msg='Invalid username or password.')
+ self._ExecuteJavascript(
+ 'document.getElementById("smsUserPin").value = "%s";'
+ 'document.getElementById("smsVerifyPin").click();' % otp,
+ tab_index, windex)
+
+ # If the account adder screen appears, then skip it.
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("skip") || '
+ 'document.getElementById("submit_approve_access")',
+ tab_index, windex),
+ msg='No "skip adding account" or "approve access" link.')
+ self._ExecuteJavascript(
+ 'if (document.getElementById("skip")) '
+ '{ document.getElementById("skip").click(); }',
+ tab_index, windex)
+
+ def AllowAccess(self, tab_index=1, windex=0):
+ """Allows access to chromoting webapp."""
+ # Approve access.
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("submit_approve_access")',
+ tab_index, windex),
+ msg='Did not go to permission page.')
+ self._ExecuteJavascript(
+ 'document.getElementById("submit_approve_access").click();',
+ tab_index, windex)
+
+ # Wait for some things to be ready.
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'window.remoting && remoting.oauth2 && ' \
+ 'remoting.oauth2.isAuthenticated()',
+ tab_index, windex),
+ msg='OAuth2 authentication failed.')
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'window.localStorage.getItem("remoting-email")',
+ tab_index, windex),
+ msg='Chromoting app did not reload after authentication.')
+
+ def DenyAccess(self, tab_index=1, windex=0):
+ """Deny and then allow access to chromoting webapp."""
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("submit_deny_access")',
+ tab_index, windex),
+ msg='Did not go to permission page.')
+ self._ExecuteJavascript(
+ 'document.getElementById("submit_deny_access").click();',
+ tab_index, windex)
+
+ def SignOut(self, tab_index=1, windex=0):
+ """Signs out from chromoting and signs back in."""
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("sign-out").click();',
+ 'UNAUTHENTICATED', tab_index, windex)
+
+ def Authenticate(self, tab_index=1, windex=0):
+ """Finishes authentication flow for user."""
+ self.ContinueAuth(tab_index, windex)
+ account = self.GetPrivateInfo()['test_chromoting_account']
+ self.host.SignIn(account['username'], account['password'], None,
+ tab_index, windex)
+ self.host.AllowAccess(tab_index, windex)
+
+ def StartMe2Me(self, tab_index=1, windex=0):
+ """Starts Me2Me. """
+ self._ExecuteJavascript(
+ 'document.getElementById("get-started-me2me").click();',
+ tab_index, windex)
+
+ def Share(self, tab_index=1, windex=0):
+ """Generates an access code and waits for incoming connections.
+
+ Returns:
+ The access code on success; None otherwise.
+ """
+ self._ExecuteAndWaitForMode(
+ 'remoting.tryShare();',
+ 'HOST_WAITING_FOR_CONNECTION', tab_index, windex)
+ return self.GetDOMValue(
+ 'document.getElementById("access-code-display").innerText',
+ tab_index, windex)
+
+ def CancelShare(self, tab_index=1, windex=0):
+ """Stops sharing the desktop on the host side."""
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'remoting.cancelShare();',
+ 'HOST_SHARE_FINISHED', tab_index, windex),
+ msg='Stopping sharing from the host side failed')
+
+ def EnableConnectionsInstalled(self, pin_exercise=False,
+ tab_index=1, windex=0):
+ """Enables the remote connections on the host side."""
+ subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'enable'])
+
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("start-daemon").click();',
+ 'HOST_SETUP_ASK_PIN', tab_index, windex),
+ msg='Cannot start host setup')
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("ask-pin-form").hidden == false',
+ tab_index, windex),
+ msg='No ask pin dialog')
+
+ if pin_exercise:
+ # Cancels the pin prompt
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-cancel").click();',
+ tab_index, windex)
+
+ # Enables again
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("start-daemon").click();',
+ 'HOST_SETUP_ASK_PIN', tab_index, windex),
+ msg='Cannot start host setup')
+
+ # Click ok without typing in pins
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-ok").click();',
+ tab_index, windex)
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("daemon-pin-error-message")',
+ tab_index, windex),
+ msg='No pin error message')
+
+ # Mis-matching pins
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-entry").value = "111111";',
+ tab_index, windex)
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-confirm").value = "123456";',
+ tab_index, windex)
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("daemon-pin-error-message")',
+ tab_index, windex),
+ msg='No pin error message')
+
+ # Types in correct pins
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-entry").value = "111111";',
+ tab_index, windex)
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-confirm").value = "111111";',
+ tab_index, windex)
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("daemon-pin-ok").click();',
+ 'HOST_SETUP_PROCESSING', tab_index, windex),
+ msg='Host setup was not started')
+
+ # Handles preference panes
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'remoting.currentMode == remoting.AppMode.HOST_SETUP_DONE',
+ tab_index, windex),
+ msg='Host setup was not done')
+
+ # Dismisses the host config done dialog
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("host-setup-dialog")'
+ '.childNodes[5].hidden == false',
+ tab_index, windex),
+ msg='No host setup done dialog')
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("host-config-done-dismiss").click();',
+ 'HOME', tab_index, windex),
+ msg='Failed to dismiss host setup confirmation dialog')
+
+ def EnableConnectionsUninstalledAndCancel(self, tab_index=1, windex=0):
+ """Enables remote connections while host is not installed yet."""
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("start-daemon").click();',
+ 'HOST_SETUP_INSTALL', tab_index, windex),
+ msg='Cannot start host install')
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("host-config-install-dismiss").click();',
+ 'HOME', tab_index, windex),
+ msg='Failed to dismiss host install dialog')
+
+ def DisableConnections(self, tab_index=1, windex=0):
+ """Disables the remote connections on the host side."""
+ subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'disable'])
+
+ self._ExecuteJavascript(
+ 'document.getElementById("stop-daemon").click();',
+ tab_index, windex)
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("host-config-done-dismiss").click();',
+ 'HOME', tab_index, windex),
+ msg='Failed to dismiss host setup confirmation dialog')
+
+ def Connect(self, access_code, tab_index=1, windex=0):
+ """Connects to a Chromoting host and starts the session."""
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("access-code-entry").value = "%s";'
+ 'remoting.connectIt2Me();' % access_code,
+ 'IN_SESSION', tab_index, windex),
+ msg='Cannot connect it2me session')
+
+ def ChangePin(self, pin='222222', tab_index=1, windex=0):
+ """Changes pin for enabled host."""
+ subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'changepin'])
+
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("change-daemon-pin").click();',
+ 'HOST_SETUP_ASK_PIN', tab_index, windex),
+ msg='Cannot change daemon pin')
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("ask-pin-form").hidden == false',
+ tab_index, windex),
+ msg='No ask pin dialog')
+
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-entry").value = "' + pin + '";',
+ tab_index, windex)
+ self._ExecuteJavascript(
+ 'document.getElementById("daemon-pin-confirm").value = "' +
+ pin + '";', tab_index, windex)
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("daemon-pin-ok").click();',
+ 'HOST_SETUP_PROCESSING', tab_index, windex),
+ msg='Host setup was not started')
+
+ # Handles preference panes
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'remoting.currentMode == remoting.AppMode.HOST_SETUP_DONE',
+ tab_index, windex),
+ msg='Host setup was not done')
+
+ # Dismisses the host config done dialog
+ self.assertTrue(
+ self._WaitForJavascriptCondition(
+ 'document.getElementById("host-setup-dialog")'
+ '.childNodes[5].hidden == false',
+ tab_index, windex),
+ msg='No host setup done dialog')
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("host-config-done-dismiss").click();',
+ 'HOME', tab_index, windex),
+ msg='Failed to dismiss host setup confirmation dialog')
+
+ def ChangeName(self, new_name='Changed', tab_index=1, windex=0):
+ """Changes the host name."""
+ self._ExecuteJavascript(
+ 'document.getElementById("this-host-rename").click();',
+ tab_index, windex)
+ self._ExecuteJavascript(
+ 'document.getElementById("this-host-name").childNodes[0].value = "' +
+ new_name + '";', tab_index, windex)
+ self._ExecuteJavascript(
+ 'document.getElementById("this-host-rename").click();',
+ tab_index, windex)
+
+ def ConnectMe2Me(self, pin='111111', mode='IN_SESSION',
+ tab_index=1, windex=0):
+ """Connects to a Chromoting host and starts the session."""
+
+ # There is delay from the enabling remote connections to the host
+ # showing up in the host list. We need to reload the web app to get
+ # the host to show up. We will repeat this a few times to make sure
+ # eventually host appears.
+ for _ in range(1, 3):
+ self._ExecuteJavascript(
+ 'window.location.reload();',
+ tab_index, windex)
+
+ # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
+ # ~60 seconds if ExecuteJavascript is called right after reload.
+ # Waiting 2s here can avoid this. So instead of getting the error and
+ # wait ~60s, we wait 2s here. If the error still happens, the following
+ # retry will handle that.
+ time.sleep(2)
+
+ # If this-host-connect is still not enabled, let's retry 3 times here.
+ this_host_connect_enabled = False
+ for _ in range(1, 3):
+ this_host_connect_enabled = self._WaitForJavascriptCondition(
+ 'document.getElementById("this-host-connect")'
+ '.getAttribute("data-daemon-state") == "enabled"',
+ tab_index, windex)
+ if this_host_connect_enabled:
+ break
+ if this_host_connect_enabled:
+ break;
+
+ # Clicking this-host-connect does work right after this-host-connect
+ # is enabled. Need to retry.
+ for _ in range(1, 3):
+ self._ExecuteJavascript(
+ 'document.getElementById("this-host-connect").click();',
+ tab_index, windex)
+
+ # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
+ # a long time out if WaitUntil is called right after click.
+ # Waiting 2s here can avoid this.
+ time.sleep(2)
+
+ # If cannot detect that pin-form appears, try 3 times.
+ pin_form_exposed = False
+ for _ in range(1, 3):
+ pin_form_exposed = self._WaitForJavascriptCondition(
+ 'document.getElementById("client-dialog")'
+ '.childNodes[9].hidden == false',
+ tab_index, windex)
+ if pin_form_exposed:
+ break
+ if pin_form_exposed:
+ break
+
+ self._ExecuteJavascript(
+ 'document.getElementById("pin-entry").value = "' + pin + '";',
+ tab_index, windex)
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("pin-form").childNodes[5].click();',
+ mode, tab_index, windex),
+ msg='Session was not started')
+
+ def Disconnect(self, tab_index=1, windex=0):
+ """Disconnects from the Chromoting it2me session on the client side."""
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'remoting.disconnect();',
+ 'CLIENT_SESSION_FINISHED_IT2ME', tab_index, windex),
+ msg='Disconnecting it2me session from the client side failed')
+
+ def DisconnectMe2Me(self, confirmation=True, tab_index=1, windex=0):
+ """Disconnects from the Chromoting me2me session on the client side."""
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'remoting.disconnect();',
+ 'CLIENT_SESSION_FINISHED_ME2ME', tab_index, windex),
+ msg='Disconnecting me2me session from the client side failed')
+
+ if confirmation:
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("client-finished-me2me-button")'
+ '.click();', 'HOME', tab_index, windex),
+ msg='Failed to dismiss session finished dialog')
+
+ def ReconnectMe2Me(self, pin='111111', tab_index=1, windex=0):
+ """Reconnects the me2me session."""
+ self._ExecuteJavascript(
+ 'document.getElementById("client-reconnect-button").click();',
+ tab_index, windex)
+
+ # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
+ # a long time out if WaitUntil is called right after click.
+ time.sleep(2)
+
+ # If cannot detect that pin-form appears, try 3 times.
+ for _ in range(1, 3):
+ pin_form_exposed = self._WaitForJavascriptCondition(
+ 'document.getElementById("client-dialog")'
+ '.childNodes[9].hidden == false',
+ tab_index, windex)
+ if pin_form_exposed:
+ break
+
+ self._ExecuteJavascript(
+ 'document.getElementById("pin-entry").value = "' + pin + '";',
+ tab_index, windex)
+ self.assertTrue(
+ self._ExecuteAndWaitForMode(
+ 'document.getElementById("pin-form").childNodes[5].click();',
+ 'IN_SESSION', tab_index, windex),
+ msg='Session was not started')
« no previous file with comments | « chrome/test/pyautolib/chromoting_key.p12 ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698