| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env 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 | |
| 7 """ | |
| 8 Stess Tests for Google Chrome. | |
| 9 | |
| 10 This script runs 4 different stress tests: | |
| 11 1. Plugin stress. | |
| 12 2. Back and forward stress. | |
| 13 3. Download stress. | |
| 14 4. Preference stress. | |
| 15 | |
| 16 After every cycle (running all 4 stress tests) it checks for crashes. | |
| 17 If there are any crashes, the script generates a report, uploads it to | |
| 18 a server and mails about the crash and the link to the report on the server. | |
| 19 Apart from this whenever the test stops on mac it looks for and reports | |
| 20 zombies. | |
| 21 | |
| 22 Prerequisites: | |
| 23 Test needs the following files/folders in the Data dir. | |
| 24 1. A crash_report tool in "pyauto_private/stress/mac" folder for use on Mac. | |
| 25 2. A "downloads" folder containing stress_downloads and all the files | |
| 26 referenced in it. | |
| 27 3. A pref_dict file in "pyauto_private/stress/mac" folder. | |
| 28 4. A "plugin" folder containing doubleAnimation.xaml, flash.swf, FlashSpin.swf, | |
| 29 generic.html, get_flash_player.gif, js-invoker.swf, mediaplayer.wmv, | |
| 30 NavigatorTicker11.class, Plugins_page.html, sample5.mov, silverlight.xaml, | |
| 31 silverlight.js, embed.pdf, plugins_page.html and test6.swf. | |
| 32 5. A stress_pref file in "pyauto_private/stress". | |
| 33 """ | |
| 34 | |
| 35 | |
| 36 import commands | |
| 37 import glob | |
| 38 import logging | |
| 39 import os | |
| 40 import random | |
| 41 import re | |
| 42 import shutil | |
| 43 import sys | |
| 44 import time | |
| 45 import urllib | |
| 46 import test_utils | |
| 47 import subprocess | |
| 48 | |
| 49 import pyauto_functional | |
| 50 import pyauto | |
| 51 import pyauto_utils | |
| 52 | |
| 53 | |
| 54 CRASHES = 'crashes' # Name of the folder to store crashes | |
| 55 | |
| 56 | |
| 57 class StressTest(pyauto.PyUITest): | |
| 58 """Run all the stress tests.""" | |
| 59 | |
| 60 flash_url1 = pyauto.PyUITest.GetFileURLForPath( | |
| 61 os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'flash.swf')) | |
| 62 flash_url2 = pyauto.PyUITest.GetFileURLForPath( | |
| 63 os.path.join(pyauto.PyUITest.DataDir(),'plugin', 'js-invoker.swf')) | |
| 64 flash_url3 = pyauto.PyUITest.GetFileURLForPath( | |
| 65 os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'generic.html')) | |
| 66 plugin_url = pyauto.PyUITest.GetFileURLForPath( | |
| 67 os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'plugins_page.html')) | |
| 68 empty_url = pyauto.PyUITest.GetFileURLForPath( | |
| 69 os.path.join(pyauto.PyUITest.DataDir(), 'empty.html')) | |
| 70 download_url1 = pyauto.PyUITest.GetFileURLForPath( | |
| 71 os.path.join(pyauto.PyUITest.DataDir(), 'downloads', 'a_zip_file.zip')) | |
| 72 download_url2 = pyauto.PyUITest.GetFileURLForPath( | |
| 73 os.path.join(pyauto.PyUITest.DataDir(),'zip', 'test.zip')) | |
| 74 file_list = pyauto.PyUITest.EvalDataFrom( | |
| 75 os.path.join(pyauto.PyUITest.DataDir(), 'downloads', 'stress_downloads')) | |
| 76 symbols_dir = os.path.join(os.getcwd(), 'Build_Symbols') | |
| 77 stress_pref = pyauto.PyUITest.EvalDataFrom( | |
| 78 os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private', 'stress', | |
| 79 'stress_pref')) | |
| 80 breakpad_dir = None | |
| 81 chrome_version = None | |
| 82 bookmarks_list = [] | |
| 83 | |
| 84 | |
| 85 def _FuncDir(self): | |
| 86 """Returns the path to the functional dir chrome/test/functional.""" | |
| 87 return os.path.dirname(__file__) | |
| 88 | |
| 89 def _DownloadSymbols(self): | |
| 90 """Downloads the symbols for the build being tested.""" | |
| 91 download_location = os.path.join(os.getcwd(), 'Build_Symbols') | |
| 92 if os.path.exists(download_location): | |
| 93 shutil.rmtree(download_location) | |
| 94 os.makedirs(download_location) | |
| 95 | |
| 96 url = self.stress_pref['symbols_dir'] + self.chrome_version | |
| 97 # TODO: Add linux symbol_files | |
| 98 if self.IsWin(): | |
| 99 url = url + '/win/' | |
| 100 symbol_files = ['chrome.dll.pdb', 'chrome.exe.pdb'] | |
| 101 elif self.IsMac(): | |
| 102 url = url + '/mac/' | |
| 103 symbol_files = map(urllib.quote, | |
| 104 ['Google Chrome Framework.framework', | |
| 105 'Google Chrome Helper.app', | |
| 106 'Google Chrome.app', | |
| 107 'crash_inspector', | |
| 108 'crash_report_sender', | |
| 109 'ffmpegsumo.so', | |
| 110 'libplugin_carbon_interpose.dylib']) | |
| 111 index = 0 | |
| 112 symbol_files = ['%s-%s-i386.breakpad' % (sym_file, self.chrome_version) \ | |
| 113 for sym_file in symbol_files] | |
| 114 logging.info(symbol_files) | |
| 115 | |
| 116 for sym_file in symbol_files: | |
| 117 sym_url = url + sym_file | |
| 118 logging.info(sym_url) | |
| 119 download_sym_file = os.path.join(download_location, sym_file) | |
| 120 logging.info(download_sym_file) | |
| 121 urllib.urlretrieve(sym_url, download_sym_file) | |
| 122 | |
| 123 def setUp(self): | |
| 124 pyauto.PyUITest.setUp(self) | |
| 125 self.breakpad_dir = self._CrashDumpFolder() | |
| 126 self.chrome_version = self.GetBrowserInfo()['properties']['ChromeVersion'] | |
| 127 | |
| 128 # Plugin stress functions | |
| 129 | |
| 130 def _CheckForPluginProcess(self, plugin_name): | |
| 131 """Checks if a particular plugin process exists. | |
| 132 | |
| 133 Args: | |
| 134 plugin_name : plugin process which should be running. | |
| 135 """ | |
| 136 process = self.GetBrowserInfo()['child_processes'] | |
| 137 self.assertTrue([x for x in process | |
| 138 if x['type'] == 'Plug-in' and | |
| 139 x['name'] == plugin_name]) | |
| 140 | |
| 141 def _GetPluginProcessId(self, plugin_name): | |
| 142 """Get Plugin process id. | |
| 143 | |
| 144 Args: | |
| 145 plugin_name: Plugin whose pid is expected. | |
| 146 Eg: "Shockwave Flash" | |
| 147 | |
| 148 Returns: | |
| 149 Process id if the plugin process is running. | |
| 150 None otherwise. | |
| 151 """ | |
| 152 for process in self.GetBrowserInfo()['child_processes']: | |
| 153 if process['type'] == 'Plug-in' and \ | |
| 154 re.search(plugin_name, process['name']): | |
| 155 return process['pid'] | |
| 156 return None | |
| 157 | |
| 158 def _CloseAllTabs(self): | |
| 159 """Close all but one tab in first window.""" | |
| 160 tab_count = self.GetTabCount(0) | |
| 161 for tab_index in xrange(tab_count - 1, 0, -1): | |
| 162 self.CloseTab(tab_index) | |
| 163 | |
| 164 def _CloseAllWindows(self): | |
| 165 """Close all windows except one.""" | |
| 166 win_count = self.GetBrowserWindowCount() | |
| 167 for windex in xrange(win_count - 1, 0, -1): | |
| 168 self.RunCommand(pyauto.IDC_CLOSE_WINDOW, windex) | |
| 169 | |
| 170 def _ReloadAllTabs(self): | |
| 171 """Reload all the tabs in first window.""" | |
| 172 for tab_index in range(self.GetTabCount()): | |
| 173 self.ReloadTab(tab_index) | |
| 174 | |
| 175 def _LoadFlashInMultipleTabs(self): | |
| 176 """Load Flash in multiple tabs in first window.""" | |
| 177 self.NavigateToURL(self.empty_url) | |
| 178 # Open 18 tabs with flash | |
| 179 for _ in range(9): | |
| 180 self.AppendTab(pyauto.GURL(self.flash_url1)) | |
| 181 self.AppendTab(pyauto.GURL(self.flash_url2)) | |
| 182 | |
| 183 def _OpenAndCloseMultipleTabsWithFlash(self): | |
| 184 """Stress test for flash in multiple tabs.""" | |
| 185 logging.info("In _OpenAndCloseMultipleWindowsWithFlash.") | |
| 186 self._LoadFlashInMultipleTabs() | |
| 187 self._CheckForPluginProcess('Shockwave Flash') | |
| 188 self._CloseAllTabs() | |
| 189 | |
| 190 def _OpenAndCloseMultipleWindowsWithFlash(self): | |
| 191 """Stress test for flash in multiple windows.""" | |
| 192 logging.info('In _OpenAndCloseMultipleWindowsWithFlash.') | |
| 193 # Open 5 Normal and 4 Incognito windows | |
| 194 for tab_index in range(1, 10): | |
| 195 if tab_index < 6: | |
| 196 self.OpenNewBrowserWindow(True) | |
| 197 else: | |
| 198 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
| 199 self.NavigateToURL(self.flash_url2, tab_index, 0) | |
| 200 self.AppendTab(pyauto.GURL(self.flash_url2), tab_index) | |
| 201 self._CloseAllWindows() | |
| 202 | |
| 203 def _OpenAndCloseMultipleTabsWithMultiplePlugins(self): | |
| 204 """Stress test using multiple plugins in multiple tabs.""" | |
| 205 logging.info('In _OpenAndCloseMultipleTabsWithMultiplePlugins.') | |
| 206 # Append 4 tabs with URL | |
| 207 for _ in range(5): | |
| 208 self.AppendTab(pyauto.GURL(self.plugin_url)) | |
| 209 self._CloseAllTabs() | |
| 210 | |
| 211 def _OpenAndCloseMultipleWindowsWithMultiplePlugins(self): | |
| 212 """Stress test using multiple plugins in multiple windows.""" | |
| 213 logging.info('In _OpenAndCloseMultipleWindowsWithMultiplePlugins.') | |
| 214 # Open 4 windows with URL | |
| 215 for tab_index in range(1, 5): | |
| 216 if tab_index < 6: | |
| 217 self.OpenNewBrowserWindow(True) | |
| 218 else: | |
| 219 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
| 220 self.NavigateToURL(self.plugin_url, tab_index, 0) | |
| 221 self._CloseAllWindows() | |
| 222 | |
| 223 def _KillAndReloadFlash(self): | |
| 224 """Stress test by killing flash process and reloading tabs.""" | |
| 225 self._LoadFlashInMultipleTabs() | |
| 226 flash_process_id1 = self._GetPluginProcessId('Shockwave Flash') | |
| 227 self.Kill(flash_process_id1) | |
| 228 self._ReloadAllTabs() | |
| 229 self._CloseAllTabs() | |
| 230 | |
| 231 def _KillAndReloadRenderersWithFlash(self): | |
| 232 """Stress test by killing renderer processes and reloading tabs.""" | |
| 233 logging.info('In _KillAndReloadRenderersWithFlash') | |
| 234 self._LoadFlashInMultipleTabs() | |
| 235 info = self.GetBrowserInfo() | |
| 236 # Kill all renderer processes | |
| 237 for tab_index in range(self.GetTabCount(0)): | |
| 238 self.KillRendererProcess( | |
| 239 info['windows'][0]['tabs'][tab_index]['renderer_pid']) | |
| 240 self._ReloadAllTabs() | |
| 241 self._CloseAllTabs() | |
| 242 | |
| 243 def _TogglePlugin(self, plugin_name): | |
| 244 """Toggle plugin status. | |
| 245 | |
| 246 Args: | |
| 247 plugin_name: Name of the plugin to toggle. | |
| 248 """ | |
| 249 plugins = self.GetPluginsInfo().Plugins() | |
| 250 for item in range(len(plugins)): | |
| 251 if re.search(plugin_name, plugins[item]['name']): | |
| 252 if plugins[item]['enabled']: | |
| 253 self.DisablePlugin(plugins[item]['path']) | |
| 254 else: | |
| 255 self.EnablePlugin(plugins[item]['path']) | |
| 256 | |
| 257 def _ToggleAndReloadFlashPlugin(self): | |
| 258 """Toggle flash and reload all tabs.""" | |
| 259 logging.info('In _ToggleAndReloadFlashPlugin') | |
| 260 for _ in range(10): | |
| 261 self.AppendTab(pyauto.GURL(self.flash_url3)) | |
| 262 # Disable Flash Plugin | |
| 263 self._TogglePlugin('Shockwave Flash') | |
| 264 self._ReloadAllTabs() | |
| 265 # Enable Flash Plugin | |
| 266 self._TogglePlugin('Shockwave Flash') | |
| 267 self._ReloadAllTabs() | |
| 268 self._CloseAllTabs() | |
| 269 | |
| 270 # Downloads stress functions | |
| 271 | |
| 272 def _LoadDownloadsInMultipleTabs(self): | |
| 273 """Load Downloads in multiple tabs in the same window.""" | |
| 274 # Open 15 tabs with downloads | |
| 275 logging.info('In _LoadDownloadsInMultipleTabs') | |
| 276 for tab_index in range(15): | |
| 277 # We open an empty tab and then downlad a file from it. | |
| 278 self.AppendTab(pyauto.GURL(self.empty_url)) | |
| 279 self.NavigateToURL(self.download_url1, 0, tab_index + 1) | |
| 280 self.AppendTab(pyauto.GURL(self.empty_url)) | |
| 281 self.NavigateToURL(self.download_url2, 0, tab_index + 2) | |
| 282 | |
| 283 def _OpenAndCloseMultipleTabsWithDownloads(self): | |
| 284 """Download items in multiple tabs.""" | |
| 285 logging.info('In _OpenAndCloseMultipleTabsWithDownloads') | |
| 286 self._LoadDownloadsInMultipleTabs() | |
| 287 self._CloseAllTabs() | |
| 288 | |
| 289 def _OpenAndCloseMultipleWindowsWithDownloads(self): | |
| 290 """Randomly have downloads in multiple windows.""" | |
| 291 logging.info('In _OpenAndCloseMultipleWindowsWithDownloads') | |
| 292 # Open 15 Windows randomly on both regular and incognito with downloads | |
| 293 for window_index in range(15): | |
| 294 tick = round(random.random() * 100) | |
| 295 if tick % 2 != 0: | |
| 296 self.NavigateToURL(self.download_url2, 0, 0) | |
| 297 else: | |
| 298 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
| 299 self.AppendTab(pyauto.GURL(self.empty_url), 1) | |
| 300 self.NavigateToURL(self.download_url2, 1, 1) | |
| 301 self._CloseAllWindows() | |
| 302 | |
| 303 def _OpenAndCloseMultipleTabsWithMultipleDownloads(self): | |
| 304 """Download multiple items in multiple tabs.""" | |
| 305 logging.info('In _OpenAndCloseMultipleTabsWithMultipleDownloads') | |
| 306 self.NavigateToURL(self.empty_url) | |
| 307 for _ in range(15): | |
| 308 for file in self.file_list: | |
| 309 count = 1 | |
| 310 url = self.GetFileURLForPath( | |
| 311 os.path.join(self.DataDir(), 'downloads', file)) | |
| 312 self.AppendTab(pyauto.GURL(self.empty_url)) | |
| 313 self.NavigateToURL(url, 0, count) | |
| 314 count = count + 1 | |
| 315 self._CloseAllTabs() | |
| 316 | |
| 317 def _OpenAndCloseMultipleWindowsWithMultipleDownloads(self): | |
| 318 """Randomly multiple downloads in multiple windows.""" | |
| 319 logging.info('In _OpenAndCloseMultipleWindowsWithMultipleDownloads') | |
| 320 for _ in range(15): | |
| 321 for file in self.file_list: | |
| 322 tick = round(random.random() * 100) | |
| 323 url = self.GetFileURLForPath( | |
| 324 os.path.join(self.DataDir(), 'downloads', file)) | |
| 325 if tick % 2!= 0: | |
| 326 self.NavigateToURL(url, 0, 0) | |
| 327 else: | |
| 328 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
| 329 self.AppendTab(pyauto.GURL(self.empty_url), 1) | |
| 330 self.NavigateToURL(url, 1, 1) | |
| 331 self._CloseAllWindows() | |
| 332 | |
| 333 # Back and Forward stress functions | |
| 334 | |
| 335 def _BrowserGoBack(self, window_index): | |
| 336 """Go back in the browser history. | |
| 337 | |
| 338 Chrome has limitation on going back and can only go back 49 pages. | |
| 339 | |
| 340 Args: | |
| 341 window_index: the index of the browser window to work on. | |
| 342 """ | |
| 343 for nback in range(48): # Go back 48 times. | |
| 344 if nback % 4 == 0: # Bookmark every 5th url when going back. | |
| 345 self._BookMarkEvery5thURL(window_index) | |
| 346 self.TabGoBack(tab_index=0, windex=window_index) | |
| 347 | |
| 348 def _BrowserGoForward(self, window_index): | |
| 349 """Go Forward in the browser history. | |
| 350 | |
| 351 Chrome has limitation on going back and can only go back 49 pages. | |
| 352 | |
| 353 Args: | |
| 354 window_index: the index of the browser window to work on. | |
| 355 """ | |
| 356 for nforward in range(48): # Go back 48 times. | |
| 357 if nforward % 4 == 0: # Bookmark every 5th url when going Forward | |
| 358 self._BookMarkEvery5thURL(window_index) | |
| 359 self.TabGoForward(tab_index=0, windex=window_index) | |
| 360 | |
| 361 def _AddToListAndBookmark(self, newname, url): | |
| 362 """Bookmark the url to bookmarkbar and to he list of bookmarks. | |
| 363 | |
| 364 Args: | |
| 365 newname: the name of the bookmark. | |
| 366 url: the url to bookmark. | |
| 367 """ | |
| 368 bookmarks = self.GetBookmarkModel() | |
| 369 bar_id = bookmarks.BookmarkBar()['id'] | |
| 370 self.AddBookmarkURL(bar_id, 0, newname, url) | |
| 371 self.bookmarks_list.append(newname) | |
| 372 | |
| 373 def _RemoveFromListAndBookmarkBar(self, name): | |
| 374 """Remove the bookmark bor and bookmarks list. | |
| 375 | |
| 376 Args: | |
| 377 name: the name of bookmark to remove. | |
| 378 """ | |
| 379 bookmarks = self.GetBookmarkModel() | |
| 380 node = bookmarks.FindByTitle(name) | |
| 381 self.RemoveBookmark(node[0]['id']) | |
| 382 self.bookmarks_list.remove(name) | |
| 383 | |
| 384 def _DuplicateBookmarks(self, name): | |
| 385 """Find duplicate bookmark in the bookmarks list. | |
| 386 | |
| 387 Args: | |
| 388 name: name of the bookmark. | |
| 389 | |
| 390 Returns: | |
| 391 True if it's a duplicate. | |
| 392 """ | |
| 393 for index in (self.bookmarks_list): | |
| 394 if index == name: | |
| 395 return True | |
| 396 return False | |
| 397 | |
| 398 def _BookMarkEvery5thURL(self, window_index): | |
| 399 """Check for duplicate in list and bookmark current url. | |
| 400 If its the first time and list is empty add the bookmark. | |
| 401 If its a duplicate remove the bookmark. | |
| 402 If its new tab page move over. | |
| 403 | |
| 404 Args: | |
| 405 window_index: the index of the browser window to work on. | |
| 406 """ | |
| 407 tab_title = self.GetActiveTabTitle(window_index) # get the page title | |
| 408 url = self.GetActiveTabURL(window_index).spec() # get the page url | |
| 409 if not self.bookmarks_list: | |
| 410 self._AddToListAndBookmark(tab_title, url) # first run bookmark the url | |
| 411 return | |
| 412 elif self._DuplicateBookmarks(tab_title): | |
| 413 self._RemoveFromListAndBookmarkBar(tab_title) | |
| 414 return | |
| 415 elif tab_title == 'New Tab': # new tab page pass over | |
| 416 return | |
| 417 else: | |
| 418 # new bookmark add it to bookmarkbar | |
| 419 self._AddToListAndBookmark(tab_title, url) | |
| 420 return | |
| 421 | |
| 422 def _ReadFileAndLoadInNormalAndIncognito(self): | |
| 423 """Read urls and load them in normal and incognito window. | |
| 424 We load 96 urls only as we can go back and forth 48 times. | |
| 425 Uses time to get different urls in normal and incognito window | |
| 426 The source file is taken from stress folder in /data folder. | |
| 427 """ | |
| 428 # URL source from stress folder in data folder | |
| 429 data_file = os.path.join(self.DataDir(), 'pyauto_private', 'stress', | |
| 430 'urls_and_titles') | |
| 431 url_data = self.EvalDataFrom(data_file) | |
| 432 urls = url_data.keys() | |
| 433 i = 0 | |
| 434 ticks = int(time.time()) # get the latest time. | |
| 435 for url in urls: | |
| 436 if i <= 96 : # load only 96 urls. | |
| 437 if ticks % 2 == 0: # loading in Incognito and Normal window. | |
| 438 self.NavigateToURL(url) | |
| 439 else: | |
| 440 self.NavigateToURL(url, 1, 0) | |
| 441 else: | |
| 442 break | |
| 443 ticks = ticks - 1 | |
| 444 i += 1 | |
| 445 return | |
| 446 | |
| 447 def _StressTestNavigation(self): | |
| 448 """ This is the method from where various navigations are called. | |
| 449 First we load the urls then call navigete back and forth in | |
| 450 incognito window then in normal window. | |
| 451 """ | |
| 452 self._ReadFileAndLoadInNormalAndIncognito() # Load the urls. | |
| 453 self._BrowserGoBack(1) # Navigate back in incognito window. | |
| 454 self._BrowserGoForward(1) # Navigate forward in incognito window | |
| 455 self._BrowserGoBack(0) # Navigate back in normal window | |
| 456 self._BrowserGoForward(0) # Navigate forward in normal window | |
| 457 | |
| 458 # Preference stress functions | |
| 459 | |
| 460 def _RandomBool(self): | |
| 461 """For any preferences bool value, it takes True or False value. | |
| 462 We are generating random True or False value. | |
| 463 """ | |
| 464 return random.randint(0, 1) == 1 | |
| 465 | |
| 466 def _RandomURL(self): | |
| 467 """Some of preferences take string url, so generating random url here.""" | |
| 468 # Site list | |
| 469 site_list = ['test1.html', 'test2.html','test3.html','test4.html', | |
| 470 'test5.html', 'test7.html', 'test6.html'] | |
| 471 random_site = random.choice(site_list) | |
| 472 # Returning a url of random site | |
| 473 return self.GetFileURLForPath(os.path.join(self.DataDir(), random_site)) | |
| 474 | |
| 475 def _RandomURLArray(self): | |
| 476 """Returns a list of 10 random URLs.""" | |
| 477 return [self._RandomURL() for _ in range(10)] | |
| 478 | |
| 479 def _RandomInt(self, max_number): | |
| 480 """Some of the preferences takes integer value. | |
| 481 Eg: If there are three options, we generate random | |
| 482 value for any option. | |
| 483 | |
| 484 Arg: | |
| 485 max_number: The number of options that a preference has. | |
| 486 """ | |
| 487 return random.randrange(1, max_number) | |
| 488 | |
| 489 def _RandomDownloadDir(self): | |
| 490 """Returns a random download directory.""" | |
| 491 return random.choice(['dl_dir1', 'dl_dir2', 'dl_dir3', | |
| 492 'dl_dir4', 'dl_dir5']) | |
| 493 | |
| 494 def _SetPref(self): | |
| 495 """Reads the preferences from file and | |
| 496 sets the preferences to Chrome. | |
| 497 """ | |
| 498 raw_dictionary = self.EvalDataFrom(os.path.join(self.DataDir(), | |
| 499 'pyauto_private', 'stress', 'pref_dict')) | |
| 500 value_dictionary = {} | |
| 501 | |
| 502 for key, value in raw_dictionary.iteritems(): | |
| 503 if value == 'BOOL': | |
| 504 value_dictionary[key] = self._RandomBool() | |
| 505 elif value == 'STRING_URL': | |
| 506 value_dictionary[key] = self._RandomURL() | |
| 507 elif value == 'ARRAY_URL': | |
| 508 value_dictionary[key] = self._RandomURLArray() | |
| 509 elif value == 'STRING_PATH': | |
| 510 value_dictionary[key] = self._RandomDownloadDir() | |
| 511 elif value[0:3] == 'INT': | |
| 512 # Normally we difine INT datatype with number of options, | |
| 513 # so parsing number of options and selecting any of them | |
| 514 # randomly. | |
| 515 value_dictionary[key] = 1 | |
| 516 max_number = raw_dictionary[key][3:4] | |
| 517 if not max_number == 1: | |
| 518 value_dictionary[key]= self._RandomInt(int(max_number)) | |
| 519 self.SetPrefs(getattr(pyauto,key), value_dictionary[key]) | |
| 520 | |
| 521 return value_dictionary | |
| 522 | |
| 523 # Crash reporting functions | |
| 524 | |
| 525 def _CrashDumpFolder(self): | |
| 526 """Get the breakpad folder. | |
| 527 | |
| 528 Returns: | |
| 529 The full path of the Crash Reports folder. | |
| 530 """ | |
| 531 breakpad_folder = self.GetBrowserInfo()['properties']['DIR_CRASH_DUMPS'] | |
| 532 self.assertTrue(breakpad_folder, 'Cannot figure crash dir') | |
| 533 return breakpad_folder | |
| 534 | |
| 535 def _DeleteDumps(self): | |
| 536 """Delete all the dump files in teh Crash Reports folder.""" | |
| 537 # should be called at the start of stress run | |
| 538 if os.path.exists(self.breakpad_dir): | |
| 539 logging.info('xxxxxxxxxxxxxxxINSIDE DELETE DUMPSxxxxxxxxxxxxxxxxx') | |
| 540 if self.IsMac(): | |
| 541 shutil.rmtree(self.breakpad_dir) | |
| 542 elif self.IsWin(): | |
| 543 files = os.listdir(self.breakpad_dir) | |
| 544 for file in files: | |
| 545 os.remove(file) | |
| 546 | |
| 547 first_crash = os.path.join(os.getcwd(), '1stcrash') | |
| 548 crashes_dir = os.path.join(os.getcwd(), 'crashes') | |
| 549 if (os.path.exists(crashes_dir)): | |
| 550 shutil.rmtree(crashes_dir) | |
| 551 shutil.rmtree(first_crash) | |
| 552 | |
| 553 def _SymbolicateCrashDmp(self, dmp_file, symbols_dir, output_file): | |
| 554 """Generate symbolicated crash report. | |
| 555 | |
| 556 Args: | |
| 557 dmp_file: the dmp file to symbolicate. | |
| 558 symbols_dir: the directory containing the symbols. | |
| 559 output_file: the output file. | |
| 560 | |
| 561 Returns: | |
| 562 Crash report text. | |
| 563 """ | |
| 564 report = '' | |
| 565 if self.IsWin(): | |
| 566 windbg_cmd = [ | |
| 567 os.path.join('C:', 'Program Files', 'Debugging Tools for Windows', | |
| 568 'windbg.exe'), | |
| 569 '-Q', | |
| 570 '-y', | |
| 571 '\"', | |
| 572 symbols_dir, | |
| 573 '\"', | |
| 574 '-c', | |
| 575 '\".ecxr;k50;.logclose;q\"', | |
| 576 '-logo', | |
| 577 output_file, | |
| 578 '-z', | |
| 579 '\"', | |
| 580 dmp_file, | |
| 581 '\"'] | |
| 582 subprocess.call(windbg_cmd) | |
| 583 # Since we are directly writing the info into output_file, | |
| 584 # we just need to copy that in to report | |
| 585 report = open(output_file, 'r').read() | |
| 586 | |
| 587 elif self.IsMac(): | |
| 588 crash_report = os.path.join(self.DataDir(), 'pyauto_private', 'stress', | |
| 589 'mac', 'crash_report') | |
| 590 for i in range(5): # crash_report doesn't work sometimes. So we retry | |
| 591 report = test_utils.Shell2( | |
| 592 '%s -S "%s" "%s"' % (crash_report, symbols_dir, dmp_file))[0] | |
| 593 if len(report) < 200: | |
| 594 try_again = 'Try %d. crash_report didn\'t work out. Trying again', i | |
| 595 logging.info(try_again) | |
| 596 else: | |
| 597 break | |
| 598 open(output_file, 'w').write(report) | |
| 599 return report | |
| 600 | |
| 601 def _SaveSymbols(self, symbols_dir, dump_dir=' ', multiple_dumps=True): | |
| 602 """Save the symbolicated files for all crash dumps. | |
| 603 | |
| 604 Args: | |
| 605 symbols_dir: the directory containing the symbols. | |
| 606 dump_dir: Path to the directory holding the crash dump files. | |
| 607 multiple_dumps: True if we are processing multiple dump files, | |
| 608 False if we are processing only the first crash. | |
| 609 """ | |
| 610 if multiple_dumps: | |
| 611 dump_dir = self.breakpad_dir | |
| 612 | |
| 613 if not os.path.isdir(CRASHES): | |
| 614 os.makedirs(CRASHES) | |
| 615 | |
| 616 # This will be sent to the method by the caller. | |
| 617 dmp_files = glob.glob(os.path.join(dump_dir, '*.dmp')) | |
| 618 for dmp_file in dmp_files: | |
| 619 dmp_id = os.path.splitext(os.path.basename(dmp_file))[0] | |
| 620 if multiple_dumps: | |
| 621 report_folder = CRASHES | |
| 622 else: | |
| 623 report_folder = dump_dir | |
| 624 report_fname = os.path.join(report_folder, | |
| 625 '%s.txt' % (dmp_id)) | |
| 626 report = self._SymbolicateCrashDmp(dmp_file, symbols_dir, | |
| 627 report_fname) | |
| 628 if report == '': | |
| 629 logging.info('Crash report is empty.') | |
| 630 # This is for copying the original dumps. | |
| 631 if multiple_dumps: | |
| 632 shutil.copy2(dmp_file, CRASHES) | |
| 633 | |
| 634 def _GetFirstCrashDir(self): | |
| 635 """Get first crash file in the crash folder. | |
| 636 Here we create the 1stcrash directory which holds the | |
| 637 first crash report, which will be attached to the mail. | |
| 638 """ | |
| 639 breakpad_folder = self.breakpad_dir | |
| 640 dump_list = glob.glob1(breakpad_folder,'*.dmp') | |
| 641 dump_list.sort(key=lambda s: os.path.getmtime(os.path.join( | |
| 642 breakpad_folder, s))) | |
| 643 first_crash_file = os.path.join(breakpad_folder, dump_list[0]) | |
| 644 | |
| 645 if not os.path.isdir('1stcrash'): | |
| 646 os.makedirs('1stcrash') | |
| 647 shutil.copy2(first_crash_file, '1stcrash') | |
| 648 first_crash_dir = os.path.join(os.getcwd(), '1stcrash') | |
| 649 return first_crash_dir | |
| 650 | |
| 651 def _GetFirstCrashFile(self): | |
| 652 """Get first crash file in the crash folder.""" | |
| 653 first_crash_dir = os.path.join(os.getcwd(), '1stcrash') | |
| 654 for each in os.listdir(first_crash_dir): | |
| 655 if each.endswith('.txt'): | |
| 656 first_crash_file = each | |
| 657 return os.path.join(first_crash_dir, first_crash_file) | |
| 658 | |
| 659 def _ProcessOnlyFirstCrash(self): | |
| 660 """ Process only the first crash report for email.""" | |
| 661 first_dir = self._GetFirstCrashDir() | |
| 662 self._SaveSymbols(self.symbols_dir, first_dir, False) | |
| 663 | |
| 664 def _GetOSName(self): | |
| 665 """Returns the OS type we are running this script on.""" | |
| 666 os_name = '' | |
| 667 if self.IsMac(): | |
| 668 os_number = commands.getoutput('sw_vers -productVersion | cut -c 1-4') | |
| 669 if os_number == '10.6': | |
| 670 os_name = 'Snow_Leopard' | |
| 671 elif os_number == '10.5': | |
| 672 os_name = 'Leopard' | |
| 673 elif self.IsWin(): | |
| 674 # TODO: Windows team need to find the way to get OS name | |
| 675 os_name = 'Windows' | |
| 676 if platform.version()[0] == '5': | |
| 677 os_name = os_name + '_XP' | |
| 678 else: | |
| 679 os_name = os_name + '_Vista/Win7' | |
| 680 return os_name | |
| 681 | |
| 682 def _ProcessUploadAndEmailCrashes(self): | |
| 683 """Upload the crashes found and email the team about this.""" | |
| 684 logging.info('#########INSIDE _ProcessUploadAndEmailCrashes#########') | |
| 685 try: | |
| 686 build_version = self.chrome_version | |
| 687 self._SaveSymbols(self.symbols_dir) | |
| 688 self._ProcessOnlyFirstCrash() | |
| 689 file_to_attach = self._GetFirstCrashFile() | |
| 690 # removing the crash_txt for now, | |
| 691 # since we are getting UnicodeDecodeError | |
| 692 # crash_txt = open(file_to_attach).read() | |
| 693 except ValueError: | |
| 694 test_utils.SendMail(self.stress_pref['mailing_address'], | |
| 695 self.stress_pref['mailing_address'], | |
| 696 "We don't have build version", | |
| 697 "BROWSER CRASHED, PLEASE CHECK", | |
| 698 self.stress_pref['smtp']) | |
| 699 # Move crash reports and dumps to server | |
| 700 os_name = self._GetOSName() | |
| 701 dest_dir = build_version + '_' + os_name | |
| 702 if (test_utils.Shell2(self.stress_pref['script'] % (CRASHES, dest_dir))): | |
| 703 logging.info('Copy Complete') | |
| 704 upload_dir= self.stress_pref['upload_dir'] + dest_dir | |
| 705 num_crashes = '\n \n Number of Crashes :' + \ | |
| 706 str(len(glob.glob1(self.breakpad_dir, '*.dmp'))) | |
| 707 mail_content = '\n\n Crash Report URL :' + upload_dir + '\n' + \ | |
| 708 num_crashes + '\n\n' # + crash_txt | |
| 709 mail_subject = 'Stress Results :' + os_name + '_' + build_version | |
| 710 # Sending mail with first crash report, # of crashes, location of upload | |
| 711 test_utils.SendMail(self.stress_pref['mailing_address'], | |
| 712 self.stress_pref['mailing_address'], | |
| 713 mail_subject, mail_content, | |
| 714 self.stress_pref['smtp'], file_to_attach) | |
| 715 | |
| 716 def _ReportCrashIfAny(self): | |
| 717 """Check for browser crashes and report.""" | |
| 718 if os.path.isdir(self.breakpad_dir): | |
| 719 listOfDumps = glob.glob(os.path.join(self.breakpad_dir, '*.dmp')) | |
| 720 if len(listOfDumps) > 0: | |
| 721 logging.info('========== INSIDE REPORT CRASH++++++++++++++') | |
| 722 # inform a method to process the dumps | |
| 723 self._ProcessUploadAndEmailCrashes() | |
| 724 | |
| 725 # Test functions | |
| 726 | |
| 727 def _PrefStress(self): | |
| 728 """Stress preferences.""" | |
| 729 default_prefs = self.GetPrefsInfo() | |
| 730 pref_dictionary = self._SetPref() | |
| 731 for key, value in pref_dictionary.iteritems(): | |
| 732 self.assertEqual(value, self.GetPrefsInfo().Prefs( | |
| 733 getattr(pyauto, key))) | |
| 734 | |
| 735 for key, value in pref_dictionary.iteritems(): | |
| 736 self.SetPrefs(getattr(pyauto, key), | |
| 737 default_prefs.Prefs(getattr(pyauto, key))) | |
| 738 | |
| 739 def _NavigationStress(self): | |
| 740 """Run back and forward stress in normal and incognito window.""" | |
| 741 self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) | |
| 742 self._StressTestNavigation() | |
| 743 | |
| 744 def _DownloadStress(self): | |
| 745 """Run all the Download stress test.""" | |
| 746 org_download_dir = self.GetDownloadDirectory().value() | |
| 747 new_dl_dir = os.path.join(org_download_dir, 'My+Downloads Folder') | |
| 748 os.path.exists(new_dl_dir) and shutil.rmtree(new_dl_dir) | |
| 749 os.makedirs(new_dl_dir) | |
| 750 self.SetPrefs(pyauto.kDownloadDefaultDirectory, new_dl_dir) | |
| 751 self._OpenAndCloseMultipleTabsWithDownloads() | |
| 752 self._OpenAndCloseMultipleWindowsWithDownloads() | |
| 753 self._OpenAndCloseMultipleTabsWithMultipleDownloads() | |
| 754 self._OpenAndCloseMultipleWindowsWithMultipleDownloads() | |
| 755 pyauto_utils.RemovePath(new_dl_dir) # cleanup | |
| 756 self.SetPrefs(pyauto.kDownloadDefaultDirectory, org_download_dir) | |
| 757 | |
| 758 def _PluginStress(self): | |
| 759 """Run all the plugin stress tests.""" | |
| 760 self._OpenAndCloseMultipleTabsWithFlash() | |
| 761 self._OpenAndCloseMultipleWindowsWithFlash() | |
| 762 self._OpenAndCloseMultipleTabsWithMultiplePlugins() | |
| 763 self._OpenAndCloseMultipleWindowsWithMultiplePlugins() | |
| 764 self._KillAndReloadRenderersWithFlash() | |
| 765 self._ToggleAndReloadFlashPlugin() | |
| 766 | |
| 767 def testStress(self): | |
| 768 """Run all the stress tests for 24 hrs.""" | |
| 769 if self.GetBrowserInfo()['properties']['branding'] != 'Google Chrome': | |
| 770 logging.info('This is not a branded build, so stopping the stress') | |
| 771 return 1 | |
| 772 self._DownloadSymbols() | |
| 773 run_number = 1 | |
| 774 start_time = time.time() | |
| 775 while True: | |
| 776 logging.info('run %d...' % run_number) | |
| 777 run_number = run_number + 1 | |
| 778 if (time.time() - start_time) >= 24*60*60: | |
| 779 logging.info('Its been 24hrs, so we break now.') | |
| 780 break | |
| 781 try: | |
| 782 methods = [self._NavigationStress, self._DownloadStress, | |
| 783 self._PluginStress, self._PrefStress] | |
| 784 random.shuffle(methods) | |
| 785 for method in methods: | |
| 786 method() | |
| 787 logging.info('Method %s done' % method) | |
| 788 except KeyboardInterrupt: | |
| 789 logging.info('----------We got a KeyboardInterrupt-----------') | |
| 790 except Exception, error: | |
| 791 logging.info('-------------There was an ERROR---------------') | |
| 792 logging.info(error) | |
| 793 | |
| 794 # Crash Reporting | |
| 795 self._ReportCrashIfAny() | |
| 796 self._DeleteDumps() | |
| 797 | |
| 798 if self.IsMac(): | |
| 799 zombie = 'ps -el | grep Chrom | grep -v grep | grep Z | wc -l' | |
| 800 zombie_count = int(commands.getoutput(zombie)) | |
| 801 if zombie_count > 0: | |
| 802 logging.info('WE HAVE ZOMBIES = %d' % zombie_count) | |
| 803 | |
| 804 | |
| 805 if __name__ == '__main__': | |
| 806 pyauto_functional.Main() | |
| OLD | NEW |