| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2012 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 | |
| 5 import os | |
| 6 | |
| 7 | |
| 8 class ChromotingMixIn(object): | |
| 9 """MixIn for PyUITest that adds Chromoting-specific methods. | |
| 10 | |
| 11 Prepend it as a base class of a test to enable Chromoting functionality. | |
| 12 This is a separate class from PyUITest to avoid namespace collisions. | |
| 13 | |
| 14 Example usage: | |
| 15 class ChromotingExample(chromoting.ChromotingMixIn, pyauto.PyUITest): | |
| 16 def testShare(self): | |
| 17 app = self.InstallApp(self.GetWebappPath()) | |
| 18 self.LaunchApp(app) | |
| 19 self.Authenticate() | |
| 20 self.assertTrue(self.Share()) | |
| 21 """ | |
| 22 | |
| 23 def _ExecuteJavascript(self, command, tab_index, windex): | |
| 24 """Helper that returns immediately after running a Javascript command.""" | |
| 25 return self.ExecuteJavascript( | |
| 26 '%s; window.domAutomationController.send("done");' % command, | |
| 27 tab_index, windex) | |
| 28 | |
| 29 def _WaitForJavascriptCondition(self, condition, tab_index, windex): | |
| 30 """Waits until the Javascript condition is true. | |
| 31 | |
| 32 This is different from a naive self.WaitUntil(lambda: self.GetDOMValue()) | |
| 33 because it uses Javascript to check the condition instead of Python. | |
| 34 """ | |
| 35 return self.WaitUntil(lambda: self.GetDOMValue( | |
| 36 '(%s) ? "1" : ""' % condition, tab_index, windex)) | |
| 37 | |
| 38 def _ExecuteAndWaitForMode(self, command, mode, tab_index, windex): | |
| 39 self.assertTrue(self._ExecuteJavascript(command, tab_index, windex), | |
| 40 'Javascript command did not return anything.') | |
| 41 return self._WaitForJavascriptCondition( | |
| 42 'remoting.currentMode == remoting.AppMode.%s' % mode, | |
| 43 tab_index, windex) | |
| 44 | |
| 45 def _ExecuteAndWaitForMajorMode(self, command, mode, tab_index, windex): | |
| 46 self.assertTrue(self._ExecuteJavascript(command, tab_index, windex), | |
| 47 'Javascript command did not return anything.') | |
| 48 return self._WaitForJavascriptCondition( | |
| 49 'remoting.getMajorMode() == remoting.AppMode.%s' % mode, | |
| 50 tab_index, windex) | |
| 51 | |
| 52 def GetWebappPath(self): | |
| 53 """Returns the path to the webapp. | |
| 54 | |
| 55 Expects the webapp to be in the same place as the pyautolib binaries. | |
| 56 """ | |
| 57 return os.path.join(self.BrowserPath(), 'remoting', 'remoting.webapp') | |
| 58 | |
| 59 def Authenticate(self, email=None, password=None, otp=None, | |
| 60 tab_index=1, windex=0): | |
| 61 """Logs a user in for Chromoting and accepts permissions for the app. | |
| 62 | |
| 63 PyAuto tests start with a clean profile, so Chromoting tests should call | |
| 64 this for every run after launching the app. If email or password is omitted, | |
| 65 the user can type it into the browser window manually. | |
| 66 | |
| 67 Raises: | |
| 68 AssertionError if the authentication flow changes or | |
| 69 the credentials are incorrect. | |
| 70 """ | |
| 71 self.assertTrue( | |
| 72 self._WaitForJavascriptCondition('window.remoting && remoting.oauth2', | |
| 73 tab_index, windex), | |
| 74 msg='Timed out while waiting for remoting app to finish loading.') | |
| 75 self._ExecuteJavascript('remoting.oauth2.doAuthRedirect();', | |
| 76 tab_index, windex) | |
| 77 self.assertTrue( | |
| 78 self._WaitForJavascriptCondition('document.getElementById("signIn")', | |
| 79 tab_index, windex), | |
| 80 msg='Unable to redirect for authentication.') | |
| 81 | |
| 82 if email: | |
| 83 self._ExecuteJavascript('document.getElementById("Email").value = "%s";' | |
| 84 'document.getElementById("Passwd").focus();' | |
| 85 % email, tab_index, windex) | |
| 86 | |
| 87 if password: | |
| 88 self._ExecuteJavascript('document.getElementById("Passwd").value = "%s";' | |
| 89 'document.getElementById("signIn").click();' | |
| 90 % password, tab_index, windex) | |
| 91 | |
| 92 if otp: | |
| 93 self.assertTrue( | |
| 94 self._WaitForJavascriptCondition( | |
| 95 'document.getElementById("smsVerifyPin")', | |
| 96 tab_index, windex), | |
| 97 msg='Invalid username or password.') | |
| 98 self._ExecuteJavascript('document.getElementById("smsUserPin").value = ' | |
| 99 '"%s";' | |
| 100 'document.getElementById("smsVerifyPin").click();' | |
| 101 % otp, tab_index, windex) | |
| 102 | |
| 103 # If the account adder screen appears, then skip it. | |
| 104 self.assertTrue( | |
| 105 self._WaitForJavascriptCondition( | |
| 106 'document.getElementById("skip") || ' | |
| 107 'document.getElementById("submit_approve_access")', | |
| 108 tab_index, windex), | |
| 109 msg='No "skip adding account" or "approve access" link.') | |
| 110 self._ExecuteJavascript( | |
| 111 'if (document.getElementById("skip")) ' | |
| 112 '{ document.getElementById("skip").click(); }', | |
| 113 tab_index, windex) | |
| 114 | |
| 115 # Approve access. | |
| 116 self.assertTrue( | |
| 117 self._WaitForJavascriptCondition( | |
| 118 'document.getElementById("submit_approve_access")', | |
| 119 tab_index, windex), | |
| 120 msg='Authentication failed. The username, password, or otp is invalid.') | |
| 121 self._ExecuteJavascript( | |
| 122 'document.getElementById("submit_approve_access").click();', | |
| 123 tab_index, windex) | |
| 124 | |
| 125 # Wait for some things to be ready. | |
| 126 self.assertTrue( | |
| 127 self._WaitForJavascriptCondition( | |
| 128 'window.remoting && remoting.oauth2 && ' | |
| 129 'remoting.oauth2.isAuthenticated()', | |
| 130 tab_index, windex), | |
| 131 msg='OAuth2 authentication failed.') | |
| 132 self.assertTrue( | |
| 133 self._WaitForJavascriptCondition( | |
| 134 'window.localStorage.getItem("remoting-email")', | |
| 135 tab_index, windex), | |
| 136 msg='Chromoting app did not reload after authentication.') | |
| 137 | |
| 138 def Share(self, tab_index=1, windex=0): | |
| 139 """Generates an access code and waits for incoming connections. | |
| 140 | |
| 141 Returns: | |
| 142 The access code on success; None otherwise. | |
| 143 """ | |
| 144 self._ExecuteAndWaitForMode( | |
| 145 'remoting.tryShare();', | |
| 146 'HOST_WAITING_FOR_CONNECTION', tab_index, windex) | |
| 147 return self.GetDOMValue( | |
| 148 'document.getElementById("access-code-display").innerText', | |
| 149 tab_index, windex) | |
| 150 | |
| 151 def Connect(self, access_code, wait_for_frame, tab_index=1, windex=0): | |
| 152 """Connects to a Chromoting host and starts the session. | |
| 153 | |
| 154 Returns: | |
| 155 True on success; False otherwise. | |
| 156 """ | |
| 157 if not self._ExecuteAndWaitForMode( | |
| 158 'document.getElementById("access-code-entry").value = "%s";' | |
| 159 'remoting.connectIt2Me();' % access_code, | |
| 160 'IN_SESSION', tab_index, windex): | |
| 161 return False | |
| 162 | |
| 163 if wait_for_frame and not self._WaitForJavascriptCondition( | |
| 164 'remoting.clientSession && remoting.clientSession.hasReceivedFrame()', | |
| 165 tab_index, windex): | |
| 166 return False | |
| 167 return True | |
| 168 | |
| 169 def CancelShare(self, tab_index=1, windex=0): | |
| 170 """Stops sharing the desktop on the host side. | |
| 171 | |
| 172 Returns: | |
| 173 True on success; False otherwise. | |
| 174 """ | |
| 175 return self._ExecuteAndWaitForMode( | |
| 176 'remoting.cancelShare();', | |
| 177 'HOST_SHARE_FINISHED', tab_index, windex) | |
| 178 | |
| 179 def Disconnect(self, tab_index=1, windex=0): | |
| 180 """Disconnects from the Chromoting session on the client side. | |
| 181 | |
| 182 Returns: | |
| 183 True on success; False otherwise. | |
| 184 """ | |
| 185 return self._ExecuteAndWaitForMode( | |
| 186 'remoting.disconnect();', | |
| 187 'CLIENT_SESSION_FINISHED_IT2ME', tab_index, windex) | |
| OLD | NEW |