| 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 """Base GTalk tests. | |
| 6 | |
| 7 This module contains a set of common utilities for querying | |
| 8 and manipulating the Google Talk Chrome Extension. | |
| 9 """ | |
| 10 | |
| 11 import logging | |
| 12 import re | |
| 13 import os | |
| 14 | |
| 15 import pyauto_gtalk | |
| 16 import pyauto | |
| 17 import pyauto_errors | |
| 18 | |
| 19 | |
| 20 class GTalkBaseTest(pyauto.PyUITest): | |
| 21 """Base test class for testing GTalk.""" | |
| 22 | |
| 23 _injected_js = None | |
| 24 | |
| 25 def Prompt(self, text): | |
| 26 """Pause execution with debug output. | |
| 27 | |
| 28 Args: | |
| 29 text: The debug output. | |
| 30 """ | |
| 31 text = str(text) | |
| 32 raw_input('--------------------> ' + text) | |
| 33 | |
| 34 def InstallGTalkExtension(self, gtalk_version): | |
| 35 """Download and install the GTalk extension.""" | |
| 36 extension_path = os.path.abspath( | |
| 37 os.path.join(self.DataDir(), 'extensions', 'gtalk', | |
| 38 gtalk_version + '.crx')) | |
| 39 self.assertTrue( | |
| 40 os.path.exists(extension_path), | |
| 41 msg='Failed to find GTalk extension: ' + extension_path) | |
| 42 | |
| 43 extension = self.GetGTalkExtensionInfo() | |
| 44 if extension: | |
| 45 logging.info('Extension already installed. Skipping install...\n') | |
| 46 return | |
| 47 | |
| 48 self.InstallExtension(extension_path, False) | |
| 49 extension = self.GetGTalkExtensionInfo() | |
| 50 self.assertTrue(extension, msg='Failed to install GTalk extension.') | |
| 51 self.assertTrue(extension['is_enabled'], msg='GTalk extension is disabled.') | |
| 52 | |
| 53 def UninstallGTalkExtension(self): | |
| 54 """Uninstall the GTalk extension (if present)""" | |
| 55 extension = self.GetGTalkExtensionInfo() | |
| 56 if extension: | |
| 57 self.UninstallExtensionById(extension['id']) | |
| 58 | |
| 59 def GetGTalkExtensionInfo(self): | |
| 60 """Get the data object about the GTalk extension.""" | |
| 61 extensions = [x for x in self.GetExtensionsInfo() | |
| 62 if x['name'] == 'Chat for Google'] | |
| 63 return extensions[0] if len(extensions) == 1 else None | |
| 64 | |
| 65 def RunInMole(self, js, mole_index=0): | |
| 66 """Execute javascript in a chat mole. | |
| 67 | |
| 68 Args: | |
| 69 js: The javascript to run. | |
| 70 mole_index: The index of the mole in which to run the JS. | |
| 71 | |
| 72 Returns: | |
| 73 The resulting value from executing the javascript. | |
| 74 """ | |
| 75 return self._RunInRenderView(self.GetMoleInfo(mole_index), js, | |
| 76 '//iframe[1]') | |
| 77 | |
| 78 def RunInAllMoles(self, js): | |
| 79 """Execute javascript in all chat moles. | |
| 80 | |
| 81 Args: | |
| 82 js: The javascript to run. | |
| 83 """ | |
| 84 moles = self.GetMolesInfo() | |
| 85 for mole in moles: | |
| 86 self._RunInRenderView(mole, js, '//iframe[1]') | |
| 87 | |
| 88 def RunInRoster(self, js): | |
| 89 """Execute javascript in the chat roster. | |
| 90 | |
| 91 Args: | |
| 92 js: The javascript to run. | |
| 93 | |
| 94 Returns: | |
| 95 The resulting value from executing the javascript. | |
| 96 """ | |
| 97 return self._RunInRenderView(self.GetViewerInfo(), js, | |
| 98 '//iframe[1]\n//iframe[1]') | |
| 99 | |
| 100 def RunInLoginPage(self, js, xpath=''): | |
| 101 """Execute javascript in the gaia login popup. | |
| 102 | |
| 103 Args: | |
| 104 js: The javascript to run. | |
| 105 xpath: The xpath to the frame in which to execute the javascript. | |
| 106 | |
| 107 Returns: | |
| 108 The resulting value from executing the javascript. | |
| 109 """ | |
| 110 return self._RunInTab(self.GetLoginPageInfo(), js, xpath) | |
| 111 | |
| 112 def RunInViewer(self, js, xpath=''): | |
| 113 """Execute javascript in the GTalk viewer window. | |
| 114 | |
| 115 Args: | |
| 116 js: The javascript to run. | |
| 117 xpath: The xpath to the frame in which to execute the javascript. | |
| 118 | |
| 119 Returns: | |
| 120 The resulting value from executing the javascript. | |
| 121 """ | |
| 122 return self._RunInRenderView(self.GetViewerInfo(), js, xpath) | |
| 123 | |
| 124 def RunInBackground(self, js, xpath=''): | |
| 125 """Execute javascript in the GTalk viewer window. | |
| 126 | |
| 127 Args: | |
| 128 js: The javascript to run. | |
| 129 xpath: The xpath to the frame in which to execute the javascript. | |
| 130 | |
| 131 Returns: | |
| 132 The resulting value from executing the javascript. | |
| 133 """ | |
| 134 background_view = self.GetBackgroundInfo() | |
| 135 return self._RunInRenderView(background_view['view'], js, xpath) | |
| 136 | |
| 137 def GetMoleInfo(self, mole_index=0): | |
| 138 """Get the data object about a given chat mole. | |
| 139 | |
| 140 Args: | |
| 141 mole_index: The index of the mole to retrieve. | |
| 142 | |
| 143 Returns: | |
| 144 Data object describing mole. | |
| 145 """ | |
| 146 extension = self.GetGTalkExtensionInfo() | |
| 147 return self._GetExtensionViewInfo( | |
| 148 'chrome-extension://%s/panel.html' % extension['id'], | |
| 149 mole_index) | |
| 150 | |
| 151 def GetMolesInfo(self): | |
| 152 """Get the data objects for all of the chat moles. | |
| 153 | |
| 154 Returns: | |
| 155 Set of data objects describing moles. | |
| 156 """ | |
| 157 extension = self.GetGTalkExtensionInfo() | |
| 158 return self._GetMatchingExtensionViews( | |
| 159 'chrome-extension://%s/panel.html' % extension['id']) | |
| 160 | |
| 161 def GetViewerInfo(self): | |
| 162 """Get the data object about the GTalk viewer dialog.""" | |
| 163 extension = self.GetGTalkExtensionInfo() | |
| 164 return self._GetExtensionViewInfo( | |
| 165 'chrome-extension://%s/viewer.html' % extension['id']) | |
| 166 | |
| 167 def GetLoginPageInfo(self): | |
| 168 """Get the data object about the gaia login popup.""" | |
| 169 return self._GetTabInfo('https://accounts.google.com/ServiceLogin?') | |
| 170 | |
| 171 def GetBackgroundInfo(self): | |
| 172 """Get the data object about the GTalk background page.""" | |
| 173 extension_views = self.GetBrowserInfo()['extension_views'] | |
| 174 for extension_view in extension_views: | |
| 175 if 'Google Talk' in extension_view['name'] and \ | |
| 176 'EXTENSION_BACKGROUND_PAGE' == extension_view['view_type']: | |
| 177 return extension_view | |
| 178 return None | |
| 179 | |
| 180 def WaitUntilResult(self, result, func, msg): | |
| 181 """Loop func until a condition matches is satified. | |
| 182 | |
| 183 Args: | |
| 184 result: Value of func() at which to stop. | |
| 185 func: Function to run at each iteration. | |
| 186 msg: Error to print upon timing out. | |
| 187 """ | |
| 188 assert callable(func) | |
| 189 self.assertTrue(self.WaitUntil( | |
| 190 lambda: func(), expect_retval=result), msg=msg) | |
| 191 | |
| 192 def WaitUntilCondition(self, func, matches, msg): | |
| 193 """Loop func until condition matches is satified. | |
| 194 | |
| 195 Args: | |
| 196 func: Function to run at each iteration. | |
| 197 matches: Funtion to evalute output and determine whether to stop. | |
| 198 msg: Error to print upon timing out. | |
| 199 """ | |
| 200 assert callable(func) | |
| 201 assert callable(matches) | |
| 202 self.assertTrue(self.WaitUntil( | |
| 203 lambda: matches(func())), msg=msg) | |
| 204 | |
| 205 def _WrapJs(self, statement): | |
| 206 """Wrap the javascript to be executed. | |
| 207 | |
| 208 Args: | |
| 209 statement: The piece of javascript to wrap. | |
| 210 | |
| 211 Returns: | |
| 212 The wrapped javascript. | |
| 213 """ | |
| 214 return """ | |
| 215 window.domAutomationController.send( | |
| 216 (function(){ | |
| 217 %s | |
| 218 try{return %s} | |
| 219 catch(e){return "JS_ERROR: " + e}})()) | |
| 220 """ % (self._GetInjectedJs(), statement) | |
| 221 | |
| 222 def _RunInTab(self, tab, js, xpath=''): | |
| 223 """Execute javascript in a given tab. | |
| 224 | |
| 225 Args: | |
| 226 tab: The data object for the Chrome window tab returned by | |
| 227 _GetTabInfo. | |
| 228 js: The javascript to run. | |
| 229 xpath: The xpath to the frame in which to execute the javascript. | |
| 230 | |
| 231 Returns: | |
| 232 The resulting value from executing the javascript. | |
| 233 """ | |
| 234 if not tab: | |
| 235 logging.debug('Tab not found: %s' % tab) | |
| 236 return False | |
| 237 logging.info('Run in tab: %s' % js) | |
| 238 | |
| 239 value = self.ExecuteJavascript( | |
| 240 self._WrapJs(js), | |
| 241 tab_index = tab['index'], | |
| 242 windex = tab['windex'], | |
| 243 frame_xpath = xpath) | |
| 244 self._LogRun(js, value) | |
| 245 return value | |
| 246 | |
| 247 def _RunInRenderView(self, view, js, xpath=''): | |
| 248 """Execute javascript in a given render view. | |
| 249 | |
| 250 Args: | |
| 251 view: The data object for the Chrome render view returned by | |
| 252 _GetExtensionViewInfo. | |
| 253 js: The javascript to run. | |
| 254 xpath: The xpath to the frame in which to execute the javascript. | |
| 255 | |
| 256 Returns: | |
| 257 The resulting value from executing the javascript. | |
| 258 """ | |
| 259 if not view: | |
| 260 logging.debug('View not found: %s' % view) | |
| 261 return False | |
| 262 logging.info('Run in view: %s' % js) | |
| 263 | |
| 264 value = self.ExecuteJavascriptInRenderView( | |
| 265 self._WrapJs(js), | |
| 266 view, | |
| 267 frame_xpath = xpath) | |
| 268 self._LogRun(js, value) | |
| 269 return value | |
| 270 | |
| 271 def _LogRun(self, js, value): | |
| 272 """Log a particular run. | |
| 273 | |
| 274 Args: | |
| 275 js: The javascript statement executed. | |
| 276 value: The return value for the execution. | |
| 277 """ | |
| 278 # works around UnicodeEncodeError: 'ascii' codec can't encode... | |
| 279 out = value | |
| 280 if not isinstance(value, basestring): | |
| 281 out = str(value) | |
| 282 out = re.sub('\s', ';', out[:300]) | |
| 283 logging.info(js + ' ===> ' + out.encode('utf-8')) | |
| 284 | |
| 285 def _GetTabInfo(self, url_query, index=0): | |
| 286 """Get the data object for a given tab. | |
| 287 | |
| 288 Args: | |
| 289 url_query: The substring of the URL to search for. | |
| 290 index: The index within the list of matches to return. | |
| 291 | |
| 292 Returns: | |
| 293 The data object for the tab. | |
| 294 """ | |
| 295 windows = self.GetBrowserInfo()['windows'] | |
| 296 i = 0 | |
| 297 for win in windows: | |
| 298 for tab in win['tabs']: | |
| 299 if tab['url'] and url_query in tab['url']: | |
| 300 # Store reference to windex used in _RunInTab. | |
| 301 tab['windex'] = win['index'] | |
| 302 if i == index: | |
| 303 return tab | |
| 304 i = i + 1 | |
| 305 return None | |
| 306 | |
| 307 def _GetExtensionViewInfo(self, url_query, index=0): | |
| 308 """Get the data object for a given extension view. | |
| 309 | |
| 310 Args: | |
| 311 url_query: The substring of the URL to search for. | |
| 312 index: The index within the list of matches to return. | |
| 313 | |
| 314 Returns: | |
| 315 The data object for the tab. | |
| 316 """ | |
| 317 | |
| 318 candidate_views = self._GetMatchingExtensionViews(url_query) | |
| 319 if len(candidate_views) > index: | |
| 320 return candidate_views[index] | |
| 321 return None | |
| 322 | |
| 323 def _GetMatchingExtensionViews(self, url_query): | |
| 324 """Gets the data objects for the extension views matching the url_query. | |
| 325 | |
| 326 Args: | |
| 327 url_query: The substring of the URL to search for. | |
| 328 | |
| 329 Returns: | |
| 330 An array of matching data objects. | |
| 331 """ | |
| 332 extension_views = self.GetBrowserInfo()['extension_views'] | |
| 333 candidate_views = list() | |
| 334 for extension_view in extension_views: | |
| 335 if extension_view['url'] and url_query in extension_view['url']: | |
| 336 candidate_views.append(extension_view['view']) | |
| 337 | |
| 338 # No guarantee on view order, so sort the views to get the correct one for | |
| 339 # a given index. | |
| 340 candidate_views.sort() | |
| 341 return candidate_views | |
| 342 | |
| 343 def _GetInjectedJs(self): | |
| 344 """Get the javascript to inject in the execution environment.""" | |
| 345 if self._injected_js is None: | |
| 346 self._injected_js = open( | |
| 347 os.path.join(os.path.dirname(__file__), 'jsutils.js')).read() | |
| 348 return self._injected_js | |
| OLD | NEW |