| OLD | NEW |
| (Empty) |
| 1 # Copyright 2013 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 import copy | |
| 6 import ctypes | |
| 7 import email | |
| 8 import logging | |
| 9 import os | |
| 10 import shutil | |
| 11 import smtplib | |
| 12 import subprocess | |
| 13 import sys | |
| 14 import types | |
| 15 | |
| 16 import pyauto_functional | |
| 17 import pyauto | |
| 18 import pyauto_utils | |
| 19 import pyauto_errors | |
| 20 | |
| 21 | |
| 22 """Commonly used functions for PyAuto tests.""" | |
| 23 | |
| 24 def CrashBrowser(test): | |
| 25 """Crashes the browser by navigating to special URL.""" | |
| 26 try: | |
| 27 test.NavigateToURL('chrome://inducebrowsercrashforrealz') | |
| 28 except pyauto_errors.JSONInterfaceError: | |
| 29 pass | |
| 30 else: | |
| 31 raise RuntimeError( | |
| 32 'Browser did not crash at chrome://inducebrowsercrashforrealz') | |
| 33 | |
| 34 | |
| 35 def CopyFileFromDataDirToDownloadDir(test, file_path): | |
| 36 """Copy a file from data directory to downloads directory. | |
| 37 | |
| 38 Args: | |
| 39 test: derived from pyauto.PyUITest - base class for UI test cases. | |
| 40 path: path of the file relative to the data directory | |
| 41 """ | |
| 42 data_file = os.path.join(test.DataDir(), file_path) | |
| 43 download_dir = test.GetDownloadDirectory().value() | |
| 44 shutil.copy(data_file, download_dir) | |
| 45 | |
| 46 | |
| 47 def CopyFileFromContentDataDirToDownloadDir(test, file_path): | |
| 48 """Copy a file from content data directory to downloads directory. | |
| 49 | |
| 50 Args: | |
| 51 test: derived from pyauto.PyUITest - base class for UI test cases. | |
| 52 path: path of the file relative to the data directory | |
| 53 """ | |
| 54 data_file = os.path.join(test.ContentDataDir(), file_path) | |
| 55 download_dir = test.GetDownloadDirectory().value() | |
| 56 shutil.copy(data_file, download_dir) | |
| 57 | |
| 58 | |
| 59 def RemoveDownloadedTestFile(test, file_name): | |
| 60 """Delete a file from the downloads directory. | |
| 61 | |
| 62 Arg: | |
| 63 test: derived from pyauto.PyUITest - base class for UI test cases | |
| 64 file_name: name of file to remove | |
| 65 """ | |
| 66 downloaded_pkg = os.path.join(test.GetDownloadDirectory().value(), | |
| 67 file_name) | |
| 68 pyauto_utils.RemovePath(downloaded_pkg) | |
| 69 pyauto_utils.RemovePath(downloaded_pkg + '.crdownload') | |
| 70 | |
| 71 | |
| 72 def GoogleAccountsLogin(test, username, password, | |
| 73 tab_index=0, windex=0, url=None): | |
| 74 """Log into Google Accounts. | |
| 75 | |
| 76 Attempts to login to Google by entering the username/password into the google | |
| 77 login page and click submit button. | |
| 78 | |
| 79 Args: | |
| 80 test: derived from pyauto.PyUITest - base class for UI test cases. | |
| 81 username: users login input. | |
| 82 password: users login password input. | |
| 83 tab_index: The tab index, default is 0. | |
| 84 windex: The window index, default is 0. | |
| 85 url: an alternative url for login page, if None, original one will be used. | |
| 86 """ | |
| 87 url = url or 'https://accounts.google.com/' | |
| 88 test.NavigateToURL(url, windex, tab_index) | |
| 89 email_id = 'document.getElementById("Email").value = "%s"; ' \ | |
| 90 'window.domAutomationController.send("done")' % username | |
| 91 password = 'document.getElementById("Passwd").value = "%s"; ' \ | |
| 92 'window.domAutomationController.send("done")' % password | |
| 93 test.ExecuteJavascript(email_id, tab_index, windex) | |
| 94 test.ExecuteJavascript(password, tab_index, windex) | |
| 95 test.assertTrue(test.SubmitForm('gaia_loginform', tab_index, windex)) | |
| 96 | |
| 97 | |
| 98 def VerifyGoogleAccountCredsFilled(test, username, password, tab_index=0, | |
| 99 windex=0): | |
| 100 """Verify stored/saved user and password values to the values in the field. | |
| 101 | |
| 102 Args: | |
| 103 test: derived from pyauto.PyUITest - base class for UI test cases. | |
| 104 username: user log in input. | |
| 105 password: user log in password input. | |
| 106 tab_index: The tab index, default is 0. | |
| 107 windex: The window index, default is 0. | |
| 108 """ | |
| 109 email_value = test.GetDOMValue('document.getElementById("Email").value', | |
| 110 tab_index, windex) | |
| 111 passwd_value = test.GetDOMValue('document.getElementById("Passwd").value', | |
| 112 tab_index, windex) | |
| 113 test.assertEqual(email_value, username) | |
| 114 # Not using assertEqual because if it fails it would end up dumping the | |
| 115 # password (which is supposed to be private) | |
| 116 test.assertTrue(passwd_value == password) | |
| 117 | |
| 118 | |
| 119 def Shell2(cmd_string, bg=False): | |
| 120 """Run a shell command. | |
| 121 | |
| 122 Args: | |
| 123 cmd_string: command to run | |
| 124 bg: should the process be run in background? Default: False | |
| 125 | |
| 126 Returns: | |
| 127 Output, return code | |
| 128 """ | |
| 129 if not cmd_string: return ('', 0) | |
| 130 if bg: | |
| 131 cmd_string += ' 1>/dev/null 2>&1 &' | |
| 132 proc = os.popen(cmd_string) | |
| 133 if bg: return ('Background process: %s' % cmd_string, 0) | |
| 134 out = proc.read() | |
| 135 retcode = proc.close() | |
| 136 if not retcode: # Success | |
| 137 retcode = 0 | |
| 138 return (out, retcode) | |
| 139 | |
| 140 | |
| 141 def SendMail(send_from, send_to, subject, text, smtp, file_to_send=None): | |
| 142 """Send mail to all the group to notify about the crash and uploaded data. | |
| 143 | |
| 144 Args: | |
| 145 send_from: From mail id as a string. | |
| 146 send_to: To mail id. Can be a string representing a single address, or a | |
| 147 list of strings representing multiple addresses. | |
| 148 subject: Mail subject as a string. | |
| 149 text: Mail body as a string. | |
| 150 smtp: The smtp to use, as a string. | |
| 151 file_to_send: Attachments for the mail. | |
| 152 """ | |
| 153 msg = email.MIMEMultipart.MIMEMultipart() | |
| 154 msg['From'] = send_from | |
| 155 if isinstance(send_to, list): | |
| 156 msg['To'] = ','.join(send_to) | |
| 157 else: | |
| 158 msg['To'] = send_to | |
| 159 msg['Date'] = email.Utils.formatdate(localtime=True) | |
| 160 msg['Subject'] = subject | |
| 161 | |
| 162 # To send multiple files in one message, introduce for loop here for files. | |
| 163 msg.attach(email.MIMEText.MIMEText(text)) | |
| 164 part = email.MIMEBase.MIMEBase('application', 'octet-stream') | |
| 165 if file_to_send is not None: | |
| 166 part.set_payload(open(file_to_send,'rb').read()) | |
| 167 email.Encoders.encode_base64(part) | |
| 168 part.add_header('Content-Disposition', | |
| 169 'attachment; filename="%s"' | |
| 170 % os.path.basename(file_to_send)) | |
| 171 msg.attach(part) | |
| 172 smtp_obj = smtplib.SMTP(smtp) | |
| 173 smtp_obj.sendmail(send_from, send_to, msg.as_string()) | |
| 174 smtp_obj.close() | |
| 175 | |
| 176 | |
| 177 def GetFreeSpace(path): | |
| 178 """Returns the free space (in bytes) on the drive containing |path|.""" | |
| 179 if sys.platform == 'win32': | |
| 180 free_bytes = ctypes.c_ulonglong(0) | |
| 181 ctypes.windll.kernel32.GetDiskFreeSpaceExW( | |
| 182 ctypes.c_wchar_p(os.path.dirname(path)), None, None, | |
| 183 ctypes.pointer(free_bytes)) | |
| 184 return free_bytes.value | |
| 185 fs_stat = os.statvfs(path) | |
| 186 return fs_stat.f_bsize * fs_stat.f_bavail | |
| 187 | |
| 188 | |
| 189 def StripUnmatchedKeys(item_to_strip, reference_item): | |
| 190 """Returns a copy of 'item_to_strip' where unmatched key-value pairs in | |
| 191 every dictionary are removed. | |
| 192 | |
| 193 This will examine each dictionary in 'item_to_strip' recursively, and will | |
| 194 remove keys that are not found in the corresponding dictionary in | |
| 195 'reference_item'. This is useful for testing equality of a subset of data. | |
| 196 | |
| 197 Items may contain dictionaries, lists, or primitives, but only corresponding | |
| 198 dictionaries will be stripped. A corresponding entry is one which is found | |
| 199 in the same index in the corresponding parent array or at the same key in the | |
| 200 corresponding parent dictionary. | |
| 201 | |
| 202 Arg: | |
| 203 item_to_strip: item to copy and remove all unmatched key-value pairs | |
| 204 reference_item: item that serves as a reference for which keys-value pairs | |
| 205 to strip from 'item_to_strip' | |
| 206 | |
| 207 Returns: | |
| 208 a copy of 'item_to_strip' where all key-value pairs that do not have a | |
| 209 matching key in 'reference_item' are removed | |
| 210 | |
| 211 Example: | |
| 212 item_to_strip = {'tabs': 3, | |
| 213 'time': 5908} | |
| 214 reference_item = {'tabs': 2} | |
| 215 StripUnmatchedKeys(item_to_strip, reference_item) will return {'tabs': 3} | |
| 216 """ | |
| 217 def StripList(list1, list2): | |
| 218 return_list = copy.deepcopy(list2) | |
| 219 for i in range(min(len(list1), len(list2))): | |
| 220 return_list[i] = StripUnmatchedKeys(list1[i], list2[i]) | |
| 221 return return_list | |
| 222 | |
| 223 def StripDict(dict1, dict2): | |
| 224 return_dict = {} | |
| 225 for key in dict1: | |
| 226 if key in dict2: | |
| 227 return_dict[key] = StripUnmatchedKeys(dict1[key], dict2[key]) | |
| 228 return return_dict | |
| 229 | |
| 230 item_to_strip_type = type(item_to_strip) | |
| 231 if item_to_strip_type is type(reference_item): | |
| 232 if item_to_strip_type is types.ListType: | |
| 233 return StripList(item_to_strip, reference_item) | |
| 234 elif item_to_strip_type is types.DictType: | |
| 235 return StripDict(item_to_strip, reference_item) | |
| 236 return copy.deepcopy(item_to_strip) | |
| 237 | |
| 238 | |
| 239 def StringContentCheck(test, content_string, have_list, nothave_list): | |
| 240 """Check for the presence or absence of strings within content. | |
| 241 | |
| 242 Confirm all strings in |have_list| are found in |content_string|. | |
| 243 Confirm all strings in |nothave_list| are not found in |content_string|. | |
| 244 | |
| 245 Args: | |
| 246 content_string: string containing the content to check. | |
| 247 have_list: list of strings expected to be found within the content. | |
| 248 nothave_list: list of strings expected to not be found within the content. | |
| 249 """ | |
| 250 for s in have_list: | |
| 251 test.assertTrue(s in content_string, | |
| 252 msg='"%s" missing from content.' % s) | |
| 253 for s in nothave_list: | |
| 254 test.assertTrue(s not in content_string, | |
| 255 msg='"%s" unexpectedly contained in content.' % s) | |
| 256 | |
| 257 | |
| 258 def CallFunctionWithNewTimeout(self, new_timeout, function): | |
| 259 """Sets the timeout to |new_timeout| and calls |function|. | |
| 260 | |
| 261 This method resets the timeout before returning. | |
| 262 """ | |
| 263 timeout_changer = pyauto.PyUITest.ActionTimeoutChanger( | |
| 264 self, new_timeout) | |
| 265 logging.info('Automation execution timeout has been changed to %d. ' | |
| 266 'If the timeout is large the test might appear to hang.' | |
| 267 % new_timeout) | |
| 268 function() | |
| 269 del timeout_changer | |
| 270 | |
| 271 | |
| 272 def GetOmniboxMatchesFor(self, text, windex=0, attr_dict=None): | |
| 273 """Fetch omnibox matches with the given attributes for the given query. | |
| 274 | |
| 275 Args: | |
| 276 text: the query text to use | |
| 277 windex: the window index to work on. Defaults to 0 (first window) | |
| 278 attr_dict: the dictionary of properties to be satisfied | |
| 279 | |
| 280 Returns: | |
| 281 a list of match items | |
| 282 """ | |
| 283 self.SetOmniboxText(text, windex=windex) | |
| 284 self.WaitUntilOmniboxQueryDone(windex=windex) | |
| 285 if not attr_dict: | |
| 286 matches = self.GetOmniboxInfo(windex=windex).Matches() | |
| 287 else: | |
| 288 matches = self.GetOmniboxInfo(windex=windex).MatchesWithAttributes( | |
| 289 attr_dict=attr_dict) | |
| 290 return matches | |
| 291 | |
| 292 | |
| 293 def GetMemoryUsageOfProcess(pid): | |
| 294 """Queries the system for the current memory usage of a specified process. | |
| 295 | |
| 296 This function only works in Linux and ChromeOS. | |
| 297 | |
| 298 Args: | |
| 299 pid: The integer process identifier for the process to use. | |
| 300 | |
| 301 Returns: | |
| 302 The memory usage of the process in MB, given as a float. If the process | |
| 303 doesn't exist on the machine, then the value 0 is returned. | |
| 304 """ | |
| 305 assert pyauto.PyUITest.IsLinux() or pyauto.PyUITest.IsChromeOS() | |
| 306 process = subprocess.Popen('ps h -o rss -p %s' % pid, shell=True, | |
| 307 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| 308 stdout = process.communicate()[0] | |
| 309 if stdout: | |
| 310 return float(stdout.strip()) / 1024 | |
| 311 else: | |
| 312 return 0 | |
| 313 | |
| 314 | |
| 315 def LoginToDevice(test, test_account='test_google_account'): | |
| 316 """Login to the Chromeos device using the given test account. | |
| 317 | |
| 318 If no test account is specified, we use test_google_account as the default. | |
| 319 You can choose test accounts from - | |
| 320 chrome/test/data/pyauto_private/private_tests_info.txt | |
| 321 | |
| 322 Args: | |
| 323 test_account: The account used to login to the Chromeos device. | |
| 324 """ | |
| 325 if not test.GetLoginInfo()['is_logged_in']: | |
| 326 credentials = test.GetPrivateInfo()[test_account] | |
| 327 test.Login(credentials['username'], credentials['password']) | |
| 328 login_info = test.GetLoginInfo() | |
| 329 test.assertTrue(login_info['is_logged_in'], msg='Login failed.') | |
| 330 else: | |
| 331 test.fail(msg='Another user is already logged in. Please logout first.') | |
| 332 | |
| 333 def GetInfobarIndexByType(test, infobar_type, windex=0, tab_index=0): | |
| 334 """Returns the index of the infobar of the given type. | |
| 335 | |
| 336 Args: | |
| 337 test: Derived from pyauto.PyUITest - base class for UI test cases. | |
| 338 infobar_type: The infobar type to look for. | |
| 339 windex: Window index. | |
| 340 tab_index: Tab index. | |
| 341 | |
| 342 Returns: | |
| 343 Index of infobar for infobar type, or None if not found. | |
| 344 """ | |
| 345 infobar_list = ( | |
| 346 test.GetBrowserInfo()['windows'][windex]['tabs'][tab_index] \ | |
| 347 ['infobars']) | |
| 348 for infobar in infobar_list: | |
| 349 if infobar_type == infobar['type']: | |
| 350 return infobar_list.index(infobar) | |
| 351 return None | |
| 352 | |
| 353 def WaitForInfobarTypeAndGetIndex(test, infobar_type, windex=0, tab_index=0): | |
| 354 """Wait for infobar type to appear and returns its index. | |
| 355 | |
| 356 If the infobar never appears, an exception will be raised. | |
| 357 | |
| 358 Args: | |
| 359 test: Derived from pyauto.PyUITest - base class for UI test cases. | |
| 360 infobar_type: The infobar type to look for. | |
| 361 windex: Window index. Defaults to 0 (first window). | |
| 362 tab_index: Tab index. Defaults to 0 (first tab). | |
| 363 | |
| 364 Returns: | |
| 365 Index of infobar for infobar type. | |
| 366 """ | |
| 367 test.assertTrue( | |
| 368 test.WaitUntil(lambda: GetInfobarIndexByType( | |
| 369 test, infobar_type, windex, tab_index) is not None), | |
| 370 msg='Infobar type for %s did not appear.' % infobar_type) | |
| 371 # Return the infobar index. | |
| 372 return GetInfobarIndexByType(test, infobar_type, windex, tab_index) | |
| 373 | |
| 374 def AssertInfobarTypeDoesNotAppear(test, infobar_type, windex=0, tab_index=0): | |
| 375 """Check that the infobar type does not appear. | |
| 376 | |
| 377 This function waits 20s to assert that the infobar does not appear. | |
| 378 | |
| 379 Args: | |
| 380 test: Derived from pyauto.PyUITest - base class for UI test cases. | |
| 381 infobar_type: The infobar type to look for. | |
| 382 windex: Window index. Defaults to 0 (first window). | |
| 383 tab_index: Tab index. Defaults to 0 (first tab). | |
| 384 """ | |
| 385 test.assertFalse( | |
| 386 test.WaitUntil(lambda: GetInfobarIndexByType( | |
| 387 test, infobar_type, windex, tab_index) is not None, timeout=20), | |
| 388 msg=('Infobar type for %s appeared when it should be hidden.' | |
| 389 % infobar_type)) | |
| 390 | |
| 391 def OpenCroshVerification(self): | |
| 392 """This test opens crosh. | |
| 393 | |
| 394 This function assumes that no browser windows are open. | |
| 395 """ | |
| 396 self.assertEqual(0, self.GetBrowserWindowCount()) | |
| 397 self.OpenCrosh() | |
| 398 self.assertEqual(1, self.GetBrowserWindowCount()) | |
| 399 self.assertEqual(1, self.GetTabCount(), | |
| 400 msg='Could not open crosh') | |
| 401 self.assertEqual('crosh', self.GetActiveTabTitle()) | |
| OLD | NEW |