summaryrefslogtreecommitdiffstats
path: root/chrome/test/pyautolib/chromoting.py
blob: 5e0f5ee3d49bd7fd2fa1a5fcb22317700068bc93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Copyright (c) 2011 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 os


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.GetIT2MeAppPath())
        self.LaunchApp(app)
        self.Authenticate()
        self.SetHostMode()
        self.assertTrue(self.Share())
  """

  def _ExecuteJavascript(self, command, tab_index, windex):
    """Helper that returns immediately after running a Javascript command."""
    return self.ExecuteJavascript(
        '%s; window.domAutomationController.send("done");' % command,
        tab_index, windex)

  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.
    """
    return self.WaitUntil(lambda: self.GetDOMValue(
        '(%s) ? "1" : ""' % condition, tab_index, windex))

  def _ExecuteAndWaitForMode(self, command, mode, tab_index, windex):
    self.assertTrue(self._ExecuteJavascript(command, tab_index, windex),
                    'Javascript command did not return anything.')
    return self._WaitForJavascriptCondition(
        'remoting.currentMode == remoting.AppMode.%s' % mode,
        tab_index, windex)

  def _ExecuteAndWaitForMajorMode(self, command, mode, tab_index, windex):
    self.assertTrue(self._ExecuteJavascript(command, tab_index, windex),
                    'Javascript command did not return anything.')
    return self._WaitForJavascriptCondition(
        'remoting.getMajorMode() == remoting.AppMode.%s' % mode,
        tab_index, windex)

  def GetIT2MeAppPath(self):
    """Returns the path to the IT2Me App.

    Expects the IT2Me webapp to be in the same place as the pyautolib binaries.
    """
    return os.path.join(self.BrowserPath(), 'remoting', 'it2me.webapp')

  def Authenticate(self, email=None, password=None, otp=None,
                   tab_index=1, windex=0):
    """Logs a user in for Chromoting and accepts permissions for the app.

    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.

    Raises:
      AssertionError if the authentication flow changes or
          the credentials are incorrect.
    """
    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)
    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)

    # Approve access.
    self.assertTrue(
        self._WaitForJavascriptCondition(
            'document.getElementById("submit_approve_access")',
            tab_index, windex),
        msg='Authentication failed. The username, password, or otp is invalid.')
    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 SetHostMode(self, tab_index=1, windex=0):
    """Sets the Chromoting app to host mode, perfect for sharing!

    Returns:
      True on success; False otherwise.
    """
    return self._ExecuteAndWaitForMajorMode(
        'remoting.setAppMode(remoting.AppMode.HOST);',
        'HOST', tab_index, windex)

  def SetClientMode(self, tab_index=1, windex=0):
    """Sets the Chromoting app to client mode, perfect for connecting to a host!

    Returns:
      True on success; False otherwise.
    """
    return self._ExecuteAndWaitForMajorMode(
        'remoting.setAppMode(remoting.AppMode.CLIENT);',
        'CLIENT', 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 Connect(self, access_code, tab_index=1, windex=0):
    """Connects to a Chromoting host and starts the session.

    Returns:
      True on success; False otherwise.
    """
    return self._ExecuteAndWaitForMode(
        'document.getElementById("access-code-entry").value = "%s";'
        'remoting.tryConnect();' % access_code,
        'IN_SESSION', tab_index, windex)

  def CancelShare(self, tab_index=1, windex=0):
    """Stops sharing the desktop on the host side.

    Returns:
      True on success; False otherwise.
    """
    return self._ExecuteAndWaitForMode(
        'remoting.cancelShare();',
        'HOST_SHARE_FINISHED', tab_index, windex)

  def Disconnect(self, tab_index=1, windex=0):
    """Disconnects from the Chromoting session on the client side.

    Returns:
      True on success; False otherwise.
    """
    return self._ExecuteAndWaitForMode(
        'remoting.disconnect();',
        'CLIENT_SESSION_FINISHED', tab_index, windex)