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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/test/pyautolib/chromoting_key.p12 ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 """Includes different methods to drive chromoting UI."""
6
7 import os
8 import subprocess
9 import sys
10 import time
11
12 from pyauto_errors import JSONInterfaceError
13
14
15 class ChromotingMixIn(object):
16 """MixIn for PyUITest that adds Chromoting-specific methods.
17
18 Prepend it as a base class of a test to enable Chromoting functionality.
19 This is a separate class from PyUITest to avoid namespace collisions.
20
21 Example usage:
22 class ChromotingExample(chromoting.ChromotingMixIn, pyauto.PyUITest):
23 def testShare(self):
24 app = self.InstallApp(self.GetWebappPath())
25 self.LaunchApp(app)
26 self.Authenticate()
27 self.assertTrue(self.Share())
28 """
29
30 def _ExecuteJavascript(self, command, tab_index, windex):
31 """Helper that returns immediately after running a Javascript command.
32 """
33 try:
34 self.ExecuteJavascript(
35 '%s; window.domAutomationController.send("done");' % command,
36 tab_index, windex)
37 return True
38 except JSONInterfaceError:
39 print '_ExecuteJavascript threw JSONInterfaceError'
40 return False
41
42 def _WaitForJavascriptCondition(self, condition, tab_index, windex):
43 """Waits until the Javascript condition is true.
44
45 This is different from a naive self.WaitUntil(lambda: self.GetDOMValue())
46 because it uses Javascript to check the condition instead of Python.
47
48 Returns: True if condition is satisfied or otherwise False.
49 """
50 try:
51 return self.WaitUntil(lambda: self.GetDOMValue(
52 '(%s) ? "1" : ""' % condition, tab_index, windex))
53 except JSONInterfaceError:
54 print '_WaitForJavascriptCondition threw JSONInterfaceError'
55 return False
56
57 def _ExecuteAndWaitForMode(self, command, mode, tab_index, windex):
58 """ Executes JavaScript and wait for remoting app mode equal to
59 the given mode.
60
61 Returns: True if condition is satisfied or otherwise False.
62 """
63 if not self._ExecuteJavascript(command, tab_index, windex):
64 return False
65 return self._WaitForJavascriptCondition(
66 'remoting.currentMode == remoting.AppMode.%s' % mode,
67 tab_index, windex)
68
69 def _ExecuteAndWaitForMajorMode(self, command, mode, tab_index, windex):
70 """ Executes JavaScript and wait for remoting app major mode equal to
71 the given mode.
72
73 Returns: True if condition is satisfied or otherwise False.
74 """
75 if not self._ExecuteJavascript(command, tab_index, windex):
76 return False
77 return self._WaitForJavascriptCondition(
78 'remoting.getMajorMode() == remoting.AppMode.%s' % mode,
79 tab_index, windex)
80
81 def GetWebappPath(self):
82 """Returns the path to the webapp.
83
84 Expects the webapp to be in the same place as the pyautolib binaries.
85 """
86 return os.path.join(self.BrowserPath(), 'remoting', 'remoting.webapp')
87
88 def _GetHelperRunner(self):
89 """Returns the python binary name that runs chromoting_helper.py."""
90 if sys.platform.startswith('win'):
91 return 'python'
92 else:
93 return 'suid-python'
94
95 def _GetHelper(self):
96 """Get chromoting_helper.py."""
97 return os.path.join('chrome', 'test', 'pyautolib', 'chromoting_helper.py')
98
99 def InstallHostDaemon(self):
100 """Installs the host daemon."""
101 subprocess.call([self._GetHelperRunner(), self._GetHelper(),
102 'install', self.BrowserPath()])
103
104 def UninstallHostDaemon(self):
105 """Uninstalls the host daemon."""
106 subprocess.call([self._GetHelperRunner(), self._GetHelper(),
107 'uninstall', self.BrowserPath()])
108
109 def ContinueAuth(self, tab_index=1, windex=0):
110 """Starts authentication."""
111 self.assertTrue(
112 self._WaitForJavascriptCondition('window.remoting && remoting.oauth2',
113 tab_index, windex),
114 msg='Timed out while waiting for remoting app to finish loading.')
115 self._ExecuteJavascript('remoting.oauth2.doAuthRedirect();',
116 tab_index, windex)
117
118 def SignIn(self, email=None, password=None, otp=None,
119 tab_index=1, windex=0):
120 """Logs a user in.
121
122 PyAuto tests start with a clean profile, so Chromoting tests should call
123 this for every run after launching the app. If email or password is
124 omitted, the user can type it into the browser window manually.
125 """
126 self.assertTrue(
127 self._WaitForJavascriptCondition('document.getElementById("signIn")',
128 tab_index, windex),
129 msg='Unable to redirect for authentication.')
130
131 if email:
132 self._ExecuteJavascript('document.getElementById("Email").value = "%s";'
133 'document.getElementById("Passwd").focus();'
134 % email, tab_index, windex)
135
136 if password:
137 self._ExecuteJavascript('document.getElementById("Passwd").value = "%s";'
138 'document.getElementById("signIn").click();'
139 % password, tab_index, windex)
140
141 if otp:
142 self.assertTrue(
143 self._WaitForJavascriptCondition(
144 'document.getElementById("smsVerifyPin")',
145 tab_index, windex),
146 msg='Invalid username or password.')
147 self._ExecuteJavascript(
148 'document.getElementById("smsUserPin").value = "%s";'
149 'document.getElementById("smsVerifyPin").click();' % otp,
150 tab_index, windex)
151
152 # If the account adder screen appears, then skip it.
153 self.assertTrue(
154 self._WaitForJavascriptCondition(
155 'document.getElementById("skip") || '
156 'document.getElementById("submit_approve_access")',
157 tab_index, windex),
158 msg='No "skip adding account" or "approve access" link.')
159 self._ExecuteJavascript(
160 'if (document.getElementById("skip")) '
161 '{ document.getElementById("skip").click(); }',
162 tab_index, windex)
163
164 def AllowAccess(self, tab_index=1, windex=0):
165 """Allows access to chromoting webapp."""
166 # Approve access.
167 self.assertTrue(
168 self._WaitForJavascriptCondition(
169 'document.getElementById("submit_approve_access")',
170 tab_index, windex),
171 msg='Did not go to permission page.')
172 self._ExecuteJavascript(
173 'document.getElementById("submit_approve_access").click();',
174 tab_index, windex)
175
176 # Wait for some things to be ready.
177 self.assertTrue(
178 self._WaitForJavascriptCondition(
179 'window.remoting && remoting.oauth2 && ' \
180 'remoting.oauth2.isAuthenticated()',
181 tab_index, windex),
182 msg='OAuth2 authentication failed.')
183 self.assertTrue(
184 self._WaitForJavascriptCondition(
185 'window.localStorage.getItem("remoting-email")',
186 tab_index, windex),
187 msg='Chromoting app did not reload after authentication.')
188
189 def DenyAccess(self, tab_index=1, windex=0):
190 """Deny and then allow access to chromoting webapp."""
191 self.assertTrue(
192 self._WaitForJavascriptCondition(
193 'document.getElementById("submit_deny_access")',
194 tab_index, windex),
195 msg='Did not go to permission page.')
196 self._ExecuteJavascript(
197 'document.getElementById("submit_deny_access").click();',
198 tab_index, windex)
199
200 def SignOut(self, tab_index=1, windex=0):
201 """Signs out from chromoting and signs back in."""
202 self._ExecuteAndWaitForMode(
203 'document.getElementById("sign-out").click();',
204 'UNAUTHENTICATED', tab_index, windex)
205
206 def Authenticate(self, tab_index=1, windex=0):
207 """Finishes authentication flow for user."""
208 self.ContinueAuth(tab_index, windex)
209 account = self.GetPrivateInfo()['test_chromoting_account']
210 self.host.SignIn(account['username'], account['password'], None,
211 tab_index, windex)
212 self.host.AllowAccess(tab_index, windex)
213
214 def StartMe2Me(self, tab_index=1, windex=0):
215 """Starts Me2Me. """
216 self._ExecuteJavascript(
217 'document.getElementById("get-started-me2me").click();',
218 tab_index, windex)
219
220 def Share(self, tab_index=1, windex=0):
221 """Generates an access code and waits for incoming connections.
222
223 Returns:
224 The access code on success; None otherwise.
225 """
226 self._ExecuteAndWaitForMode(
227 'remoting.tryShare();',
228 'HOST_WAITING_FOR_CONNECTION', tab_index, windex)
229 return self.GetDOMValue(
230 'document.getElementById("access-code-display").innerText',
231 tab_index, windex)
232
233 def CancelShare(self, tab_index=1, windex=0):
234 """Stops sharing the desktop on the host side."""
235 self.assertTrue(
236 self._ExecuteAndWaitForMode(
237 'remoting.cancelShare();',
238 'HOST_SHARE_FINISHED', tab_index, windex),
239 msg='Stopping sharing from the host side failed')
240
241 def EnableConnectionsInstalled(self, pin_exercise=False,
242 tab_index=1, windex=0):
243 """Enables the remote connections on the host side."""
244 subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'enable'])
245
246 self.assertTrue(
247 self._ExecuteAndWaitForMode(
248 'document.getElementById("start-daemon").click();',
249 'HOST_SETUP_ASK_PIN', tab_index, windex),
250 msg='Cannot start host setup')
251 self.assertTrue(
252 self._WaitForJavascriptCondition(
253 'document.getElementById("ask-pin-form").hidden == false',
254 tab_index, windex),
255 msg='No ask pin dialog')
256
257 if pin_exercise:
258 # Cancels the pin prompt
259 self._ExecuteJavascript(
260 'document.getElementById("daemon-pin-cancel").click();',
261 tab_index, windex)
262
263 # Enables again
264 self.assertTrue(
265 self._ExecuteAndWaitForMode(
266 'document.getElementById("start-daemon").click();',
267 'HOST_SETUP_ASK_PIN', tab_index, windex),
268 msg='Cannot start host setup')
269
270 # Click ok without typing in pins
271 self._ExecuteJavascript(
272 'document.getElementById("daemon-pin-ok").click();',
273 tab_index, windex)
274 self.assertTrue(
275 self._WaitForJavascriptCondition(
276 'document.getElementById("daemon-pin-error-message")',
277 tab_index, windex),
278 msg='No pin error message')
279
280 # Mis-matching pins
281 self._ExecuteJavascript(
282 'document.getElementById("daemon-pin-entry").value = "111111";',
283 tab_index, windex)
284 self._ExecuteJavascript(
285 'document.getElementById("daemon-pin-confirm").value = "123456";',
286 tab_index, windex)
287 self.assertTrue(
288 self._WaitForJavascriptCondition(
289 'document.getElementById("daemon-pin-error-message")',
290 tab_index, windex),
291 msg='No pin error message')
292
293 # Types in correct pins
294 self._ExecuteJavascript(
295 'document.getElementById("daemon-pin-entry").value = "111111";',
296 tab_index, windex)
297 self._ExecuteJavascript(
298 'document.getElementById("daemon-pin-confirm").value = "111111";',
299 tab_index, windex)
300 self.assertTrue(
301 self._ExecuteAndWaitForMode(
302 'document.getElementById("daemon-pin-ok").click();',
303 'HOST_SETUP_PROCESSING', tab_index, windex),
304 msg='Host setup was not started')
305
306 # Handles preference panes
307 self.assertTrue(
308 self._WaitForJavascriptCondition(
309 'remoting.currentMode == remoting.AppMode.HOST_SETUP_DONE',
310 tab_index, windex),
311 msg='Host setup was not done')
312
313 # Dismisses the host config done dialog
314 self.assertTrue(
315 self._WaitForJavascriptCondition(
316 'document.getElementById("host-setup-dialog")'
317 '.childNodes[5].hidden == false',
318 tab_index, windex),
319 msg='No host setup done dialog')
320 self.assertTrue(
321 self._ExecuteAndWaitForMode(
322 'document.getElementById("host-config-done-dismiss").click();',
323 'HOME', tab_index, windex),
324 msg='Failed to dismiss host setup confirmation dialog')
325
326 def EnableConnectionsUninstalledAndCancel(self, tab_index=1, windex=0):
327 """Enables remote connections while host is not installed yet."""
328 self.assertTrue(
329 self._ExecuteAndWaitForMode(
330 'document.getElementById("start-daemon").click();',
331 'HOST_SETUP_INSTALL', tab_index, windex),
332 msg='Cannot start host install')
333 self.assertTrue(
334 self._ExecuteAndWaitForMode(
335 'document.getElementById("host-config-install-dismiss").click();',
336 'HOME', tab_index, windex),
337 msg='Failed to dismiss host install dialog')
338
339 def DisableConnections(self, tab_index=1, windex=0):
340 """Disables the remote connections on the host side."""
341 subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'disable'])
342
343 self._ExecuteJavascript(
344 'document.getElementById("stop-daemon").click();',
345 tab_index, windex)
346 self.assertTrue(
347 self._ExecuteAndWaitForMode(
348 'document.getElementById("host-config-done-dismiss").click();',
349 'HOME', tab_index, windex),
350 msg='Failed to dismiss host setup confirmation dialog')
351
352 def Connect(self, access_code, tab_index=1, windex=0):
353 """Connects to a Chromoting host and starts the session."""
354 self.assertTrue(
355 self._ExecuteAndWaitForMode(
356 'document.getElementById("access-code-entry").value = "%s";'
357 'remoting.connectIt2Me();' % access_code,
358 'IN_SESSION', tab_index, windex),
359 msg='Cannot connect it2me session')
360
361 def ChangePin(self, pin='222222', tab_index=1, windex=0):
362 """Changes pin for enabled host."""
363 subprocess.call([self._GetHelperRunner(), self._GetHelper(), 'changepin'])
364
365 self.assertTrue(
366 self._ExecuteAndWaitForMode(
367 'document.getElementById("change-daemon-pin").click();',
368 'HOST_SETUP_ASK_PIN', tab_index, windex),
369 msg='Cannot change daemon pin')
370 self.assertTrue(
371 self._WaitForJavascriptCondition(
372 'document.getElementById("ask-pin-form").hidden == false',
373 tab_index, windex),
374 msg='No ask pin dialog')
375
376 self._ExecuteJavascript(
377 'document.getElementById("daemon-pin-entry").value = "' + pin + '";',
378 tab_index, windex)
379 self._ExecuteJavascript(
380 'document.getElementById("daemon-pin-confirm").value = "' +
381 pin + '";', tab_index, windex)
382 self.assertTrue(
383 self._ExecuteAndWaitForMode(
384 'document.getElementById("daemon-pin-ok").click();',
385 'HOST_SETUP_PROCESSING', tab_index, windex),
386 msg='Host setup was not started')
387
388 # Handles preference panes
389 self.assertTrue(
390 self._WaitForJavascriptCondition(
391 'remoting.currentMode == remoting.AppMode.HOST_SETUP_DONE',
392 tab_index, windex),
393 msg='Host setup was not done')
394
395 # Dismisses the host config done dialog
396 self.assertTrue(
397 self._WaitForJavascriptCondition(
398 'document.getElementById("host-setup-dialog")'
399 '.childNodes[5].hidden == false',
400 tab_index, windex),
401 msg='No host setup done dialog')
402 self.assertTrue(
403 self._ExecuteAndWaitForMode(
404 'document.getElementById("host-config-done-dismiss").click();',
405 'HOME', tab_index, windex),
406 msg='Failed to dismiss host setup confirmation dialog')
407
408 def ChangeName(self, new_name='Changed', tab_index=1, windex=0):
409 """Changes the host name."""
410 self._ExecuteJavascript(
411 'document.getElementById("this-host-rename").click();',
412 tab_index, windex)
413 self._ExecuteJavascript(
414 'document.getElementById("this-host-name").childNodes[0].value = "' +
415 new_name + '";', tab_index, windex)
416 self._ExecuteJavascript(
417 'document.getElementById("this-host-rename").click();',
418 tab_index, windex)
419
420 def ConnectMe2Me(self, pin='111111', mode='IN_SESSION',
421 tab_index=1, windex=0):
422 """Connects to a Chromoting host and starts the session."""
423
424 # There is delay from the enabling remote connections to the host
425 # showing up in the host list. We need to reload the web app to get
426 # the host to show up. We will repeat this a few times to make sure
427 # eventually host appears.
428 for _ in range(1, 3):
429 self._ExecuteJavascript(
430 'window.location.reload();',
431 tab_index, windex)
432
433 # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
434 # ~60 seconds if ExecuteJavascript is called right after reload.
435 # Waiting 2s here can avoid this. So instead of getting the error and
436 # wait ~60s, we wait 2s here. If the error still happens, the following
437 # retry will handle that.
438 time.sleep(2)
439
440 # If this-host-connect is still not enabled, let's retry 3 times here.
441 this_host_connect_enabled = False
442 for _ in range(1, 3):
443 this_host_connect_enabled = self._WaitForJavascriptCondition(
444 'document.getElementById("this-host-connect")'
445 '.getAttribute("data-daemon-state") == "enabled"',
446 tab_index, windex)
447 if this_host_connect_enabled:
448 break
449 if this_host_connect_enabled:
450 break;
451
452 # Clicking this-host-connect does work right after this-host-connect
453 # is enabled. Need to retry.
454 for _ in range(1, 3):
455 self._ExecuteJavascript(
456 'document.getElementById("this-host-connect").click();',
457 tab_index, windex)
458
459 # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
460 # a long time out if WaitUntil is called right after click.
461 # Waiting 2s here can avoid this.
462 time.sleep(2)
463
464 # If cannot detect that pin-form appears, try 3 times.
465 pin_form_exposed = False
466 for _ in range(1, 3):
467 pin_form_exposed = self._WaitForJavascriptCondition(
468 'document.getElementById("client-dialog")'
469 '.childNodes[9].hidden == false',
470 tab_index, windex)
471 if pin_form_exposed:
472 break
473 if pin_form_exposed:
474 break
475
476 self._ExecuteJavascript(
477 'document.getElementById("pin-entry").value = "' + pin + '";',
478 tab_index, windex)
479 self.assertTrue(
480 self._ExecuteAndWaitForMode(
481 'document.getElementById("pin-form").childNodes[5].click();',
482 mode, tab_index, windex),
483 msg='Session was not started')
484
485 def Disconnect(self, tab_index=1, windex=0):
486 """Disconnects from the Chromoting it2me session on the client side."""
487 self.assertTrue(
488 self._ExecuteAndWaitForMode(
489 'remoting.disconnect();',
490 'CLIENT_SESSION_FINISHED_IT2ME', tab_index, windex),
491 msg='Disconnecting it2me session from the client side failed')
492
493 def DisconnectMe2Me(self, confirmation=True, tab_index=1, windex=0):
494 """Disconnects from the Chromoting me2me session on the client side."""
495 self.assertTrue(
496 self._ExecuteAndWaitForMode(
497 'remoting.disconnect();',
498 'CLIENT_SESSION_FINISHED_ME2ME', tab_index, windex),
499 msg='Disconnecting me2me session from the client side failed')
500
501 if confirmation:
502 self.assertTrue(
503 self._ExecuteAndWaitForMode(
504 'document.getElementById("client-finished-me2me-button")'
505 '.click();', 'HOME', tab_index, windex),
506 msg='Failed to dismiss session finished dialog')
507
508 def ReconnectMe2Me(self, pin='111111', tab_index=1, windex=0):
509 """Reconnects the me2me session."""
510 self._ExecuteJavascript(
511 'document.getElementById("client-reconnect-button").click();',
512 tab_index, windex)
513
514 # pyauto _GetResultFromJSONRequest throws JSONInterfaceError after
515 # a long time out if WaitUntil is called right after click.
516 time.sleep(2)
517
518 # If cannot detect that pin-form appears, try 3 times.
519 for _ in range(1, 3):
520 pin_form_exposed = self._WaitForJavascriptCondition(
521 'document.getElementById("client-dialog")'
522 '.childNodes[9].hidden == false',
523 tab_index, windex)
524 if pin_form_exposed:
525 break
526
527 self._ExecuteJavascript(
528 'document.getElementById("pin-entry").value = "' + pin + '";',
529 tab_index, windex)
530 self.assertTrue(
531 self._ExecuteAndWaitForMode(
532 'document.getElementById("pin-form").childNodes[5].click();',
533 'IN_SESSION', tab_index, windex),
534 msg='Session was not started')
OLDNEW
« 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