1 #!/usr/bin/env python 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 """Basic sanity tests for the GTalk extension. 7 8 This module contains the basic set of sanity tests run on the 9 GTalk extension. 10 """ 11 12 import logging 13 import sys 14 import time 15 import traceback 16 import urllib2 17 import os 18 19 import gtalk_base_test 20 import pyauto_gtalk # must preceed pyauto 21 import pyauto 22 23 24 class BasicTest(gtalk_base_test.GTalkBaseTest): 25 """Test for Google Talk Chrome Extension.""" 26 27 def _OpenRoster(self, gtalk_version): 28 """Download Talk extension and open the roster.""" 29 30 self.InstallGTalkExtension(gtalk_version) 31 32 # Wait for the background view to load. 33 extension = self.GetGTalkExtensionInfo() 34 background_view = self.WaitUntilExtensionViewLoaded( 35 extension_id=extension['id'], 36 view_type='EXTENSION_BACKGROUND_PAGE') 37 self.assertTrue(background_view, 38 msg='Failed to get background view: views = %s.' % 39 self.GetBrowserInfo()['extension_views']) 40 41 # Click browser action icon 42 self.TriggerBrowserActionById(extension['id']) 43 44 # Wait for viewer window to open. 45 self.assertTrue( 46 self.WaitUntil(self.GetViewerInfo), 47 msg='Timed out waiting for viewer.html to open.') 48 49 # Wait for the sign-in iframe to load. 50 self.WaitUntilCondition( 51 lambda: self.RunInViewer( 52 'window.document.getElementsByTagName("iframe") != null && ' 53 'window.document.getElementsByTagName("iframe").length > 0') and 54 self.RunInViewer('window.location.href', 55 '//iframe[1]'), 56 lambda url: url and '/qsignin' in url, 57 msg='Timed out waiting for /qsignin page.') 58 59 60 def _SignIn(self, gtalk_version): 61 """Download the extension, open the roster, and sign in""" 62 # Open the roster. 63 self._OpenRoster(gtalk_version) 64 65 # Wait for /qsignin's BODY. 66 self.WaitUntilResult(True, 67 lambda: self.RunInViewer( 68 'Boolean($BODY())', '//iframe[1]'), 69 msg='Timed out waiting for document.body in /qsignin page.') 70 71 # Wait for the "Sign In" link. 72 self.WaitUntilResult(True, 73 lambda: self.RunInViewer( 74 'Boolean($FindByText($BODY(), "Sign In"))', '//iframe[1]'), 75 msg='Timed out waiting for "Sign In" link in DOM.') 76 77 # Click the "Sign In" link. 78 self.assertTrue(self.RunInViewer( 79 '$Click($FindByText($BODY(), "Sign In"))', '//iframe[1]')) 80 81 # Wait for the login page to open. 82 self.assertTrue(self.WaitUntil(self.GetLoginPageInfo), 83 msg='Timed out waiting for login page to open.') 84 85 # Wait for the login page's form element. 86 self.WaitUntilResult(True, 87 lambda: self.RunInLoginPage('Boolean(document.forms[0])'), 88 msg='Timed out waiting for document.forms[0].') 89 90 # Fill and submit the login form. 91 credentials = self.GetPrivateInfo()['test_google_account'] 92 93 self.RunInLoginPage( 94 'document.forms[0].Email.value="' + credentials['username'] + '"') 95 self.RunInLoginPage( 96 'document.forms[0].Passwd.value="' + credentials['password'] + '"') 97 self.RunInLoginPage('document.forms[0].submit() || true') 98 99 def RunBasicFunctionalityTest(self, gtalk_version): 100 """Run tests for basic functionality in GTalk.""" 101 102 # Install the extension, open the viewer, and sign in. 103 self._SignIn(gtalk_version) 104 105 # Wait for the roster container iframe. 106 self.WaitUntilResult(True, 107 lambda: self.RunInViewer( 108 'window.document.getElementById("popoutRoster") != null'), 109 msg='Timed out waiting for roster container iframe.') 110 111 self.WaitUntilResult(True, 112 lambda: self.RunInViewer('Boolean(window.frames[0])', '//iframe[1]'), 113 msg='Timed out waiting for roster iframe.') 114 115 # Wait for the roster iframe to load. 116 self.WaitUntilCondition( 117 lambda: self.RunInRoster('window.location.href'), 118 lambda url: url and '/frame' in url, 119 msg='Timed out waiting for /frame in url.') 120 121 self.WaitUntilResult(True, 122 lambda: self.RunInRoster( 123 'Boolean($FindByText($BODY(), "Send a message to..."))'), 124 msg='Timed out waiting for "Send a message to..." label in roster DOM.') 125 126 # Wait for "chatpinger (at] appspot.com" to appear in the roster. 127 self.WaitUntilResult(True, 128 lambda: self.RunInRoster( 129 'Boolean($FindByText($BODY(), "chatpinger (at] appspot.com"))'), 130 msg='Timed out waiting for chatpinger (at] appspot.com in roster DOM.') 131 132 # Works around for issue where mole doesn't open when clicked too quickly. 133 time.sleep(1) 134 135 # Click "chatpinger (at] appspot.com" to open a chat mole. 136 self.RunInRoster('$Click($FindByText($BODY(), "chatpinger (at] appspot.com"))') 137 138 # Wait until ready to check whether mole is open(temporary work around). 139 time.sleep(1) 140 141 # Wait for chat mole to open. 142 self.assertTrue(self.WaitUntil(self.GetMoleInfo), 143 msg='Timed out waiting for mole window to open.') 144 145 self.WaitUntilResult(True, 146 lambda: self.RunInViewer( 147 'window.document.getElementsByTagName("iframe") != null'), 148 msg='Timed out waiting for iframes to load.') 149 150 # Wait for chat mole to load. 151 self.WaitUntilResult(True, 152 lambda: self.RunInMole('Boolean(window.location.href)'), 153 msg='Timed out waiting for mole window location.') 154 155 # Wait for the chat mole's input textarea to load. 156 self.WaitUntilResult(True, 157 lambda: self.RunInMole( 158 'Boolean($FindByTagName($BODY(), "textarea", 0))'), 159 msg='Timed out waiting for mole textarea.') 160 161 # Type /ping in the mole's input widget. 162 self.assertTrue(self.RunInMole( 163 '$Type($FindByTagName($BODY(), "textarea", 0), "/ping")'), 164 msg='Error typing in mole textarea.') 165 166 # Type ENTER in the mole's input widget. 167 self.assertTrue(self.RunInMole( 168 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ENTER)'), 169 msg='Error sending ENTER in mole textarea.') 170 171 # Wait for chat input to clear. 172 self.WaitUntilResult(True, 173 lambda: self.RunInMole( 174 'Boolean($FindByTagName($BODY(),"textarea",0).value=="")'), 175 msg='Timed out waiting for textarea to clear after ENTER.') 176 177 # Wait for /ping to appear in the chat history. 178 self.WaitUntilCondition( 179 lambda: self.RunInMole('window.document.body.innerHTML'), 180 lambda html: html and '/ping' in html, 181 msg='Timed out waiting for /ping to appear in mole DOM.') 182 183 # Wait for the echo "Ping!" to appear in the chat history. 184 self.WaitUntilCondition( 185 lambda: self.RunInMole('window.document.body.innerHTML'), 186 lambda html: html and 'Ping!' in html, 187 msg='Timed out waiting for "Ping!" reply to appear in mole DOM.') 188 189 # Request a ping in 7 seconds. 190 self.assertTrue(self.RunInMole( 191 '$Type($FindByTagName($BODY(),"textarea",0), "/ping 7")'), 192 msg='Error typing "ping /7" in mole textarea.') 193 194 # Press Enter in chat input. 195 self.assertTrue(self.RunInMole( 196 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ENTER)'), 197 msg='Error sending ENTER after "ping /7" in mole textarea.') 198 199 # Briefly show mole for visual examination. 200 # Also works around issue where extension may show the first 201 # Ping! notification before closing the mole. 202 time.sleep(2) 203 204 # Press escape to close the mole. 205 self.assertTrue(self.RunInMole( 206 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ESC)'), 207 msg='Error sending ESC after "ping /7" in mole textarea.') 208 209 # Wait for the mole to close. 210 self.assertTrue(self.WaitUntil( 211 lambda: not(bool(self.GetMoleInfo()))), 212 msg='Timed out waiting for chatpinger mole to close.') 213 214 # Ensure "chatpinger2 (at] appspot.com" is in the roster. 215 self.WaitUntilResult(True, 216 lambda: self.RunInRoster( 217 'Boolean($FindByText($BODY(), "chatpinger2 (at] appspot.com"))'), 218 msg='Timed out waiting for chatpinger2 (at] appspot.com in roster DOM.') 219 220 # Click "chatpinger2 (at] appspot.com" in the roster. 221 self.RunInRoster('$Click($FindByText($BODY(), "chatpinger2 (at] appspot.com"))') 222 223 self.WaitUntilResult(True, 224 lambda: self.RunInViewer( 225 'window.document.getElementsByTagName("iframe") != null'), 226 msg='Timed out waiting for iframes to load.') 227 228 # Wait for a second chat mole to open. 229 time.sleep(1) 230 self.assertTrue(self.WaitUntil(lambda: bool(self.GetMoleInfo(1))), 231 msg='Timed out waiting for second mole window to open.') 232 233 # Wait for mole content to load 234 self.WaitUntilCondition( 235 lambda: self.RunInMole('window.document.body.innerHTML', 1), 236 lambda html: html and 'Ping!' in html, 237 msg='Timed out waiting for Ping! to appear in mole DOM.') 238 239 # Disable the extension. 240 extension = self.GetGTalkExtensionInfo() 241 self.SetExtensionStateById(extension['id'], enable=False, 242 allow_in_incognito=False) 243 extension = self.GetGTalkExtensionInfo() 244 self.assertFalse(extension['is_enabled']) 245 246 # Verify all moles + windows are closed. 247 self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetViewerInfo()))), 248 msg='Timed out waiting for viewer.html to close after disabling.') 249 self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetMoleInfo()))), 250 msg='Timed out waiting for first mole to close after disabling.') 251 self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetMoleInfo(1)))), 252 msg='Timed out waiting for second mole to close after disabling.') 253 254 def _GetCurrentGtalkVersion(self): 255 """Read current gtalk extension version from file.""" 256 return self._GetGtalkVersion('current_version') 257 258 def _GetRCGtalkVersion(self): 259 """Read RC gtalk extension version from file""" 260 return self._GetGtalkVersion('rc_version') 261 262 def _GetGtalkVersion(self, version_type): 263 """Read gtalk version from file""" 264 version_path = os.path.abspath( 265 os.path.join(self.DataDir(), 'extensions', 266 'gtalk', version_type)) 267 self.assertTrue( 268 os.path.exists(version_path), 269 msg='Failed to find version ' + version_path) 270 with open(version_path) as version_file: 271 return version_file.read() 272 273 def _TestBasicFunctionality(self, version): 274 """Run tests for basic functionality in GTalk with retries.""" 275 276 # Since this test goes against prod servers, we'll retry to mitigate 277 # flakiness due to network issues. 278 RETRIES = 5 279 for tries in range(RETRIES): 280 logging.info('Calling RunBasicFunctionalityTest on %s. Try #%s/%s' 281 % (version, tries + 1, RETRIES)) 282 try: 283 self.RunBasicFunctionalityTest(version) 284 logging.info('RunBasicFunctionalityTest on %s succeeded. Tries: %s' 285 % (version, tries + 1)) 286 break 287 except Exception as e: 288 logging.info("\n*** ERROR in RunBasicFunctionalityTest ***") 289 exc_type, exc_value, exc_traceback = sys.exc_info() 290 traceback.print_exception(exc_type, exc_value, exc_traceback) 291 logging.info("\n") 292 if tries < RETRIES - 1: 293 self.NavigateToURL('http://accounts.google.com/Logout') 294 logging.info('Closing all moles.') 295 self.RunInAllMoles( 296 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ESC)') 297 logging.info('Retrying...') 298 else: 299 raise 300 301 def testCurrentVersion(self): 302 """Run basic functionality test on current version of gtalk extension""" 303 version = self._GetCurrentGtalkVersion() 304 self._TestBasicFunctionality(version) 305 306 def testRCVersion(self): 307 """Run basic functionality test on RC version of gtalk extension""" 308 version = self._GetRCGtalkVersion() 309 self._TestBasicFunctionality(version) 310 311 if __name__ == '__main__': 312 pyauto_gtalk.Main() 313