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 |