OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 2011 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 (http://go/quasar) |
| 7 |
| 8 This module contains the basic set of sanity tests run on the |
| 9 GTalk extension: |
| 10 https://chrome.google.com/webstore/detail/nckgahadagoaajjgafhacjanaoiihapd |
| 11 """ |
| 12 |
| 13 import logging |
| 14 import sys |
| 15 import time |
| 16 import traceback |
| 17 import urllib2 |
| 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 Prompt(self, text): |
| 28 """Pause execution with debug output. |
| 29 |
| 30 Args: |
| 31 text: The debug output. |
| 32 """ |
| 33 text = str(text) |
| 34 raw_input('--------------------> ' + text.encode('utf-8')) |
| 35 |
| 36 def _OpenRoster(self): |
| 37 """Download Talk extension and open the roster.""" |
| 38 |
| 39 self.InstallGTalkExtension() |
| 40 |
| 41 # Wait for the background view to load. |
| 42 extension = self.GetGTalkExtensionInfo() |
| 43 background_view = self.WaitUntilExtensionViewLoaded( |
| 44 extension_id=extension['id'], |
| 45 view_type='EXTENSION_BACKGROUND_PAGE') |
| 46 self.assertTrue(background_view, |
| 47 msg='Failed to get background view: views = %s.' % |
| 48 self.GetBrowserInfo()['extension_views']) |
| 49 |
| 50 # Wait for the custom QTest hook to load. |
| 51 self.WaitUntilResult(True, |
| 52 lambda: self.RunInBackground('Boolean(QTest)'), |
| 53 msg='Timed out waiting for QTest.handleBrowserAction function') |
| 54 |
| 55 # Run hook to simluate clicking the browser action icon. |
| 56 # TODO(wud): replace after click BA icon is supported. |
| 57 # See http://crbug.com/97342. |
| 58 result = self.RunInBackground('QTest.handleBrowserAction()') |
| 59 self.assertEqual('ok', result, |
| 60 msg='Call to QTest.handleBrowserAction failed.') |
| 61 |
| 62 # Wait for viewer window to open. |
| 63 self.assertTrue(self.WaitUntil(self.GetViewerInfo), |
| 64 msg='Timed out waiting for viewer.html to open') |
| 65 |
| 66 # Wait for viewer window to load the sign-in page. |
| 67 self.WaitUntilCondition( |
| 68 lambda: self.RunInViewer('window.location.href', |
| 69 '//iframe[1]'), |
| 70 lambda url: url and '/qsignin' in url, |
| 71 msg='Timed out waiting for /qsignin page') |
| 72 |
| 73 def _SignIn(self): |
| 74 """Download the extension, open the roster, and sign in""" |
| 75 |
| 76 # Open the roster. |
| 77 self._OpenRoster() |
| 78 |
| 79 # Wait for /qsignin's BODY. |
| 80 self.WaitUntilResult(True, |
| 81 lambda: self.RunInViewer( |
| 82 'Boolean($BODY())', '//iframe[1]'), |
| 83 msg='Timed out waiting for document.body in /qsignin page.') |
| 84 |
| 85 # Wait for the "Sign In" link. |
| 86 self.WaitUntilResult(True, |
| 87 lambda: self.RunInViewer( |
| 88 'Boolean($FindByText($BODY(), "Sign In"))', '//iframe[1]'), |
| 89 msg='Timed out waiting for "Sign In" link in DOM.') |
| 90 |
| 91 # Click the "Sign In" link. |
| 92 self.assertTrue(self.RunInViewer( |
| 93 '$Click($FindByText($BODY(), "Sign In"))', '//iframe[1]')) |
| 94 |
| 95 # Wait for the login page to open. |
| 96 self.assertTrue(self.WaitUntil(self.GetLoginPageInfo), |
| 97 msg='Timed out waiting for login page to open') |
| 98 |
| 99 # Wait for the login page's form element. |
| 100 self.WaitUntilResult(True, |
| 101 lambda: self.RunInLoginPage('Boolean(document.forms[0])'), |
| 102 msg='Timed out waiting for document.forms[0]') |
| 103 |
| 104 # Fill and submit the login form. |
| 105 self.RunInLoginPage( |
| 106 'document.forms[0].Email.value="quasar.test.1@gmail.com"') |
| 107 self.RunInLoginPage('document.forms[0].Passwd.value="stablechat"') |
| 108 self.RunInLoginPage('document.forms[0].submit() || true') |
| 109 |
| 110 def RunBasicFunctionalityTest(self): |
| 111 """Run tests for basic functionality in GTalk.""" |
| 112 |
| 113 # Install the extension, open the viewer, and sign in. |
| 114 self._SignIn() |
| 115 |
| 116 # Wait for the roster container iframe. |
| 117 self.WaitUntilResult(True, |
| 118 lambda: self.RunInViewer('Boolean(window.frames[0])'), |
| 119 msg='Timed out waiting for roster container iframe') |
| 120 |
| 121 # Wait for the roster iframe. |
| 122 self.WaitUntilResult(True, |
| 123 lambda: self.RunInViewer('Boolean(window.frames[0])', '//iframe[1]'), |
| 124 msg='Timed out waiting for roster iframe') |
| 125 |
| 126 # Wait for the roster iframe to load. |
| 127 self.WaitUntilCondition( |
| 128 lambda: self.RunInRoster('window.location.href'), |
| 129 lambda url: url and '/notifierclient' in url, |
| 130 msg='Timed out waiting for /notifierclient url') |
| 131 |
| 132 # Wait for "Search contacts..." to appear in the roster. |
| 133 self.WaitUntilCondition( |
| 134 lambda: self.RunInRoster('window.document.body.innerHTML'), |
| 135 lambda html: html and 'Search contacts...' in html, |
| 136 msg='Timed out waiting for search contacts text in roster DOM.') |
| 137 |
| 138 # Wait for "chatpinger@appspot.com" to appear in the roster. |
| 139 self.WaitUntilResult(True, |
| 140 lambda: self.RunInRoster( |
| 141 'Boolean($FindByText($BODY(), "chatpinger@appspot.com"))'), |
| 142 msg='Timed out waiting for chatpinger@appspot.com in roster DOM.') |
| 143 |
| 144 # TODO(wud): fix issue where mole doesn't open when clicked too quickly. |
| 145 time.sleep(1) |
| 146 |
| 147 # Click "chatpinger@appspot.com" to open a chat mole. |
| 148 self.RunInRoster('$Click($FindByText($BODY(), "chatpinger@appspot.com"))') |
| 149 |
| 150 # Wait for chat mole to open. |
| 151 self.assertTrue(self.WaitUntil(self.GetMoleInfo), |
| 152 msg='Timed out waiting for mole window to open') |
| 153 |
| 154 # Wait for chat mole to load. |
| 155 self.WaitUntilResult(True, |
| 156 lambda: self.RunInMole('Boolean(window.location.href)'), |
| 157 msg='Timed out waiting for mole window location') |
| 158 |
| 159 # Wait for the chat mole's input textarea to load. |
| 160 self.WaitUntilResult(True, |
| 161 lambda: self.RunInMole( |
| 162 'Boolean($FindByTagName($BODY(), "textarea", 0))'), |
| 163 msg='Timed out waiting for mole textarea') |
| 164 |
| 165 # Type /ping in the mole's input widget. |
| 166 self.assertTrue(self.RunInMole( |
| 167 '$Type($FindByTagName($BODY(), "textarea", 0), "/ping")'), |
| 168 msg='Error typing in mole textarea') |
| 169 |
| 170 # Type ENTER in the mole's input widget. |
| 171 self.assertTrue(self.RunInMole( |
| 172 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ENTER)'), |
| 173 msg='Error sending ENTER in mole textarea') |
| 174 |
| 175 # Wait for chat input to clear. |
| 176 self.WaitUntilResult(True, |
| 177 lambda: self.RunInMole( |
| 178 'Boolean($FindByTagName($BODY(),"textarea",0).value=="")'), |
| 179 msg='Timed out waiting for textarea to clear after ENTER') |
| 180 |
| 181 # Wait for /ping to appear in the chat history. |
| 182 self.WaitUntilCondition( |
| 183 lambda: self.RunInMole('window.document.body.innerHTML'), |
| 184 lambda html: html and '/ping' in html, |
| 185 msg='Timed out waiting for /ping to appear in mole DOM') |
| 186 |
| 187 # Wait for the echo "Ping!" to appear in the chat history. |
| 188 self.WaitUntilCondition( |
| 189 lambda: self.RunInMole('window.document.body.innerHTML'), |
| 190 lambda html: html and 'Ping!' in html, |
| 191 msg='Timed out waiting for "Ping!" reply to appear in mole DOM') |
| 192 |
| 193 # Request a ping in 7 seconds. |
| 194 self.assertTrue(self.RunInMole( |
| 195 '$Type($FindByTagName($BODY(),"textarea",0), "/ping 7")'), |
| 196 msg='Error typing "ping /7" in mole textarea') |
| 197 |
| 198 # Press Enter in chat input. |
| 199 self.assertTrue(self.RunInMole( |
| 200 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ENTER)'), |
| 201 msg='Error sending ENTER after "ping /7" in mole textarea') |
| 202 |
| 203 # Briefly show mole for visual examination. |
| 204 # Also works around issue where extension may show the first |
| 205 # Ping! notification before closing the mole. |
| 206 time.sleep(2) |
| 207 |
| 208 # Press escape to close the mole. |
| 209 self.assertTrue(self.RunInMole( |
| 210 '$Press($FindByTagName($BODY(),"textarea",0), $KEYS.ESC)'), |
| 211 msg='Error sending ESC after "ping /7" in mole textarea') |
| 212 |
| 213 # Wait for the mole to close. |
| 214 self.assertTrue(self.WaitUntil( |
| 215 lambda: not(bool(self.GetMoleInfo()))), |
| 216 msg='Timed out waiting for chatpinger mole to close') |
| 217 |
| 218 # Wait for a incoming chat toast to appear (requested above). |
| 219 self.WaitUntilResult(True, |
| 220 lambda: self.RunInBackground('Boolean($VIEW("/toast.html"))'), |
| 221 msg='Timed out waiting for toast') |
| 222 |
| 223 # Wait for the toast body to exist. |
| 224 self.WaitUntilResult(True, |
| 225 lambda: self.RunInBackground('Boolean($BODY($VIEW("/toast.html")))'), |
| 226 msg='Timed out waiting for toast body') |
| 227 |
| 228 # Wait for "Ping!" to appear in the toast. |
| 229 self.WaitUntilResult(True, |
| 230 lambda: self.RunInBackground( |
| 231 'Boolean($FindByText($BODY($VIEW("/toast.html")), "Ping!"))'), |
| 232 msg='Timed out waiting for "Ping!" in toast') |
| 233 |
| 234 # Click "Ping!" in the toast to open a mole. |
| 235 self.assertTrue(self.RunInBackground( |
| 236 '$Click($FindByText($BODY($VIEW("/toast.html")), "Ping!"))'), |
| 237 msg='Error clicking "Ping!" in toast') |
| 238 |
| 239 # Wait for the mole to open. |
| 240 self.assertTrue(self.WaitUntil(self.GetMoleInfo), |
| 241 msg='Timed out waiting for mole window to open') |
| 242 |
| 243 # Ensure "chatpinger2@appspot.com" is in the roster. |
| 244 self.WaitUntilResult(True, |
| 245 lambda: self.RunInRoster( |
| 246 'Boolean($FindByText($BODY(), "chatpinger2@appspot.com"))'), |
| 247 msg='Timed out waiting for chatpinger2@appspot.com in roster DOM.') |
| 248 |
| 249 # Click "chatpinger2@appspot.com" in the roster. |
| 250 self.RunInRoster('$Click($FindByText($BODY(), "chatpinger2@appspot.com"))') |
| 251 |
| 252 # Wait for a second chat mole to open. |
| 253 self.assertTrue(self.WaitUntil(lambda: bool(self.GetMoleInfo(1))), |
| 254 msg='Timed out waiting for second mole window to open') |
| 255 |
| 256 # Disable the extension. |
| 257 extension = self.GetGTalkExtensionInfo() |
| 258 self.SetExtensionStateById(extension['id'], enable=False, |
| 259 allow_in_incognito=False) |
| 260 extension = self.GetGTalkExtensionInfo() |
| 261 self.assertFalse(extension['is_enabled']) |
| 262 |
| 263 # Verify all moles + windows are closed. |
| 264 self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetViewerInfo()))), |
| 265 msg='Timed out waiting for viewer.html to close after disabling') |
| 266 self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetMoleInfo()))), |
| 267 msg='Timed out waiting for first mole to close after disabling') |
| 268 self.assertTrue(self.WaitUntil(lambda: not(bool(self.GetMoleInfo(1)))), |
| 269 msg='Timed out waiting for second mole to close after disabling') |
| 270 |
| 271 def testBasicFunctionality(self): |
| 272 """Run tests for basic functionality in GTalk with retries.""" |
| 273 |
| 274 # Since this test goes against prod servers, we'll retry to mitigate |
| 275 # flakiness due to network issues. |
| 276 tries = 0 |
| 277 RETRIES = 5 |
| 278 for tries in range(RETRIES): |
| 279 logging.info('Calling RunBasicFunctionalityTest. Try #{0}/{1}' |
| 280 .format(tries + 1, RETRIES)) |
| 281 try: |
| 282 self.RunBasicFunctionalityTest() |
| 283 logging.info('RunBasicFunctionalityTest succeeded. Tries: {0}' |
| 284 .format(tries + 1)) |
| 285 break |
| 286 except Exception as e: |
| 287 logging.info("\n*** ERROR in RunBasicFunctionalityTest ***") |
| 288 exc_type, exc_value, exc_traceback = sys.exc_info() |
| 289 traceback.print_exception(exc_type, exc_value, exc_traceback) |
| 290 logging.info("\n") |
| 291 if tries < RETRIES - 1: |
| 292 self.NavigateToURL('http://accounts.google.com/Logout') |
| 293 logging.info('Retrying...') |
| 294 else: |
| 295 raise |
| 296 |
| 297 |
| 298 if __name__ == '__main__': |
| 299 pyauto_gtalk.Main() |
OLD | NEW |