| #!/usr/bin/env python |
| # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| |
| """ |
| Stess Tests for Google Chrome. |
| |
| This script runs 4 different stress tests: |
| 1. Plugin stress. |
| 2. Back and forward stress. |
| 3. Download stress. |
| 4. Preference stress. |
| |
| After every cycle (running all 4 stress tests) it checks for crashes. |
| If there are any crashes, the script generates a report, uploads it to |
| a server and mails about the crash and the link to the report on the server. |
| Apart from this whenever the test stops on mac it looks for and reports |
| zombies. |
| |
| Prerequisites: |
| Test needs the following files/folders in the Data dir. |
| 1. A crash_report tool in "pyauto_private/stress/mac" folder for use on Mac. |
| 2. A "downloads" folder containing stress_downloads and all the files |
| referenced in it. |
| 3. A pref_dict file in "pyauto_private/stress/mac" folder. |
| 4. A "plugin" folder containing doubleAnimation.xaml, flash.swf, FlashSpin.swf, |
| generic.html, get_flash_player.gif, js-invoker.swf, mediaplayer.wmv, |
| NavigatorTicker11.class, Plugins_page.html, sample5.mov, silverlight.xaml, |
| silverlight.js, embed.pdf, plugins_page.html and test6.swf. |
| 5. A stress_pref file in "pyauto_private/stress". |
| """ |
| |
| |
| import commands |
| import glob |
| import logging |
| import os |
| import random |
| import re |
| import shutil |
| import sys |
| import time |
| import urllib |
| import test_utils |
| import subprocess |
| |
| import pyauto_functional |
| import pyauto |
| import pyauto_utils |
| |
| |
| CRASHES = 'crashes' # Name of the folder to store crashes |
| |
| |
| class StressTest(pyauto.PyUITest): |
| """Run all the stress tests.""" |
| |
| flash_url1 = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'flash.swf')) |
| flash_url2 = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(),'plugin', 'js-invoker.swf')) |
| flash_url3 = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'generic.html')) |
| plugin_url = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(), 'plugin', 'plugins_page.html')) |
| empty_url = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(), 'empty.html')) |
| download_url1 = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(), 'downloads', 'a_zip_file.zip')) |
| download_url2 = pyauto.PyUITest.GetFileURLForPath( |
| os.path.join(pyauto.PyUITest.DataDir(),'zip', 'test.zip')) |
| file_list = pyauto.PyUITest.EvalDataFrom( |
| os.path.join(pyauto.PyUITest.DataDir(), 'downloads', 'stress_downloads')) |
| symbols_dir = os.path.join(os.getcwd(), 'Build_Symbols') |
| stress_pref = pyauto.PyUITest.EvalDataFrom( |
| os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private', 'stress', |
| 'stress_pref')) |
| breakpad_dir = None |
| chrome_version = None |
| bookmarks_list = [] |
| |
| |
| def _FuncDir(self): |
| """Returns the path to the functional dir chrome/test/functional.""" |
| return os.path.dirname(__file__) |
| |
| def _DownloadSymbols(self): |
| """Downloads the symbols for the build being tested.""" |
| download_location = os.path.join(os.getcwd(), 'Build_Symbols') |
| if os.path.exists(download_location): |
| shutil.rmtree(download_location) |
| os.makedirs(download_location) |
| |
| url = self.stress_pref['symbols_dir'] + self.chrome_version |
| # TODO: Add linux symbol_files |
| if self.IsWin(): |
| url = url + '/win/' |
| symbol_files = ['chrome_dll.pdb', 'chrome_exe.pdb'] |
| elif self.IsMac(): |
| url = url + '/mac/' |
| symbol_files = map(urllib.quote, |
| ['Google Chrome Framework.framework', |
| 'Google Chrome Helper.app', |
| 'Google Chrome.app', |
| 'crash_inspector', |
| 'crash_report_sender', |
| 'ffmpegsumo.so', |
| 'libplugin_carbon_interpose.dylib']) |
| index = 0 |
| symbol_files = ['%s-%s-i386.breakpad' % (sym_file, self.chrome_version) \ |
| for sym_file in symbol_files] |
| logging.info(symbol_files) |
| |
| for sym_file in symbol_files: |
| sym_url = url + sym_file |
| logging.info(sym_url) |
| download_sym_file = os.path.join(download_location, sym_file) |
| logging.info(download_sym_file) |
| urllib.urlretrieve(sym_url, download_sym_file) |
| |
| def setUp(self): |
| pyauto.PyUITest.setUp(self) |
| self.breakpad_dir = self._CrashDumpFolder() |
| self.chrome_version = self.GetBrowserInfo()['properties']['ChromeVersion'] |
| |
| # Plugin stress functions |
| |
| def _CheckForPluginProcess(self, plugin_name): |
| """Checks if a particular plugin process exists. |
| |
| Args: |
| plugin_name : plugin process which should be running. |
| """ |
| process = self.GetBrowserInfo()['child_processes'] |
| self.assertTrue([x for x in process |
| if x['type'] == 'Plug-in' and |
| x['name'] == plugin_name]) |
| |
| def _GetPluginProcessId(self, plugin_name): |
| """Get Plugin process id. |
| |
| Args: |
| plugin_name: Plugin whose pid is expected. |
| Eg: "Shockwave Flash" |
| |
| Returns: |
| Process id if the plugin process is running. |
| None otherwise. |
| """ |
| for process in self.GetBrowserInfo()['child_processes']: |
| if process['type'] == 'Plug-in' and \ |
| re.search(plugin_name, process['name']): |
| return process['pid'] |
| return None |
| |
| def _CloseAllTabs(self): |
| """Close all but one tab in first window.""" |
| tab_count = self.GetTabCount(0) |
| for tab_index in xrange(tab_count - 1, 0, -1): |
| self.CloseTab(tab_index) |
| |
| def _CloseAllWindows(self): |
| """Close all windows except one.""" |
| win_count = self.GetBrowserWindowCount() |
| for windex in xrange(win_count - 1, 0, -1): |
| self.RunCommand(pyauto.IDC_CLOSE_WINDOW, windex) |
| |
| def _ReloadAllTabs(self): |
| """Reload all the tabs in first window.""" |
| for tab_index in range(self.GetTabCount()): |
| self.ReloadTab(tab_index) |
| |
| def _LoadFlashInMultipleTabs(self): |
| """Load Flash in multiple tabs in first window.""" |
| self.NavigateToURL(self.empty_url) |
| # Open 18 tabs with flash |
| for _ in range(9): |
| self.AppendTab(pyauto.GURL(self.flash_url1)) |
| self.AppendTab(pyauto.GURL(self.flash_url2)) |
| |
| def _OpenAndCloseMultipleTabsWithFlash(self): |
| """Stress test for flash in multiple tabs.""" |
| logging.info("In _OpenAndCloseMultipleWindowsWithFlash.") |
| self._LoadFlashInMultipleTabs() |
| self._CheckForPluginProcess('Shockwave Flash') |
| self._CloseAllTabs() |
| |
| def _OpenAndCloseMultipleWindowsWithFlash(self): |
| """Stress test for flash in multiple windows.""" |
| logging.info('In _OpenAndCloseMultipleWindowsWithFlash.') |
| # Open 5 Normal and 4 Incognito windows |
| for tab_index in range(1, 10): |
| if tab_index < 6: |
| self.OpenNewBrowserWindow(True) |
| else: |
| self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) |
| self.NavigateToURL(self.flash_url2, tab_index, 0) |
| self.AppendTab(pyauto.GURL(self.flash_url2), tab_index) |
| self._CloseAllWindows() |
| |
| def _OpenAndCloseMultipleTabsWithMultiplePlugins(self): |
| """Stress test using multiple plugins in multiple tabs.""" |
| logging.info('In _OpenAndCloseMultipleTabsWithMultiplePlugins.') |
| # Append 4 tabs with URL |
| for _ in range(5): |
| self.AppendTab(pyauto.GURL(self.plugin_url)) |
| self._CloseAllTabs() |
| |
| def _OpenAndCloseMultipleWindowsWithMultiplePlugins(self): |
| """Stress test using multiple plugins in multiple windows.""" |
| logging.info('In _OpenAndCloseMultipleWindowsWithMultiplePlugins.') |
| # Open 4 windows with URL |
| for tab_index in range(1, 5): |
| if tab_index < 6: |
| self.OpenNewBrowserWindow(True) |
| else: |
| self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) |
| self.NavigateToURL(self.plugin_url, tab_index, 0) |
| self._CloseAllWindows() |
| |
| def _KillAndReloadFlash(self): |
| """Stress test by killing flash process and reloading tabs.""" |
| self._LoadFlashInMultipleTabs() |
| flash_process_id1 = self._GetPluginProcessId('Shockwave Flash') |
| self.Kill(flash_process_id1) |
| self._ReloadAllTabs() |
| self._CloseAllTabs() |
| |
| def _KillAndReloadRenderersWithFlash(self): |
| """Stress test by killing renderer processes and reloading tabs.""" |
| logging.info('In _KillAndReloadRenderersWithFlash') |
| self._LoadFlashInMultipleTabs() |
| info = self.GetBrowserInfo() |
| # Kill all renderer processes |
| for tab_index in range(self.GetTabCount(0)): |
| self.KillRendererProcess( |
| info['windows'][0]['tabs'][tab_index]['renderer_pid']) |
| self._ReloadAllTabs() |
| self._CloseAllTabs() |
| |
| def _TogglePlugin(self, plugin_name): |
| """Toggle plugin status. |
| |
| Args: |
| plugin_name: Name of the plugin to toggle. |
| """ |
| plugins = self.GetPluginsInfo().Plugins() |
| for item in range(len(plugins)): |
| if re.search(plugin_name, plugins[item]['name']): |
| if plugins[item]['enabled']: |
| self.DisablePlugin(plugins[item]['path']) |
| else: |
| self.EnablePlugin(plugins[item]['path']) |
| |
| def _ToggleAndReloadFlashPlugin(self): |
| """Toggle flash and reload all tabs.""" |
| logging.info('In _ToggleAndReloadFlashPlugin') |
| for _ in range(10): |
| self.AppendTab(pyauto.GURL(self.flash_url3)) |
| # Disable Flash Plugin |
| self._TogglePlugin('Shockwave Flash') |
| self._ReloadAllTabs() |
| # Enable Flash Plugin |
| self._TogglePlugin('Shockwave Flash') |
| self._ReloadAllTabs() |
| self._CloseAllTabs() |
| |
| # Downloads stress functions |
| |
| def _LoadDownloadsInMultipleTabs(self): |
| """Load Downloads in multiple tabs in the same window.""" |
| # Open 15 tabs with downloads |
| logging.info('In _LoadDownloadsInMultipleTabs') |
| for tab_index in range(15): |
| # We open an empty tab and then downlad a file from it. |
| self.AppendTab(pyauto.GURL(self.empty_url)) |
| self.NavigateToURL(self.download_url1, 0, tab_index + 1) |
| self.AppendTab(pyauto.GURL(self.empty_url)) |
| self.NavigateToURL(self.download_url2, 0, tab_index + 2) |
| |
| def _OpenAndCloseMultipleTabsWithDownloads(self): |
| """Download items in multiple tabs.""" |
| logging.info('In _OpenAndCloseMultipleTabsWithDownloads') |
| self._LoadDownloadsInMultipleTabs() |
| self._CloseAllTabs() |
| |
| def _OpenAndCloseMultipleWindowsWithDownloads(self): |
| """Randomly have downloads in multiple windows.""" |
| logging.info('In _OpenAndCloseMultipleWindowsWithDownloads') |
| # Open 15 Windows randomly on both regular and incognito with downloads |
| for window_index in range(15): |
| tick = round(random.random() * 100) |
| if tick % 2 != 0: |
| self.NavigateToURL(self.download_url2, 0, 0) |
| else: |
| self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) |
| self.AppendTab(pyauto.GURL(self.empty_url), 1) |
| self.NavigateToURL(self.download_url2, 1, 1) |
| self._CloseAllWindows() |
| |
| def _OpenAndCloseMultipleTabsWithMultipleDownloads(self): |
| """Download multiple items in multiple tabs.""" |
| logging.info('In _OpenAndCloseMultipleTabsWithMultipleDownloads') |
| self.NavigateToURL(self.empty_url) |
| for _ in range(15): |
| for file in self.file_list: |
| count = 1 |
| url = self.GetFileURLForPath( |
| os.path.join(self.DataDir(), 'downloads', file)) |
| self.AppendTab(pyauto.GURL(self.empty_url)) |
| self.NavigateToURL(url, 0, count) |
| count = count + 1 |
| self._CloseAllTabs() |
| |
| def _OpenAndCloseMultipleWindowsWithMultipleDownloads(self): |
| """Randomly multiple downloads in multiple windows.""" |
| logging.info('In _OpenAndCloseMultipleWindowsWithMultipleDownloads') |
| for _ in range(15): |
| for file in self.file_list: |
| tick = round(random.random() * 100) |
| url = self.GetFileURLForPath( |
| os.path.join(self.DataDir(), 'downloads', file)) |
| if tick % 2!= 0: |
| self.NavigateToURL(url, 0, 0) |
| else: |
| self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) |
| self.AppendTab(pyauto.GURL(self.empty_url), 1) |
| self.NavigateToURL(url, 1, 1) |
| self._CloseAllWindows() |
| |
| # Back and Forward stress functions |
| |
| def _BrowserGoBack(self, window_index): |
| """Go back in the browser history. |
| |
| Chrome has limitation on going back and can only go back 49 pages. |
| |
| Args: |
| window_index: the index of the browser window to work on. |
| """ |
| for nback in range(48): # Go back 48 times. |
| if nback % 4 == 0: # Bookmark every 5th url when going back. |
| self._BookMarkEvery5thURL(window_index) |
| self.TabGoBack(tab_index=0, windex=window_index) |
| |
| def _BrowserGoForward(self, window_index): |
| """Go Forward in the browser history. |
| |
| Chrome has limitation on going back and can only go back 49 pages. |
| |
| Args: |
| window_index: the index of the browser window to work on. |
| """ |
| for nforward in range(48): # Go back 48 times. |
| if nforward % 4 == 0: # Bookmark every 5th url when going Forward |
| self._BookMarkEvery5thURL(window_index) |
| self.TabGoForward(tab_index=0, windex=window_index) |
| |
| def _AddToListAndBookmark(self, newname, url): |
| """Bookmark the url to bookmarkbar and to he list of bookmarks. |
| |
| Args: |
| newname: the name of the bookmark. |
| url: the url to bookmark. |
| """ |
| bookmarks = self.GetBookmarkModel() |
| bar_id = bookmarks.BookmarkBar()['id'] |
| self.AddBookmarkURL(bar_id, 0, newname, url) |
| self.bookmarks_list.append(newname) |
| |
| def _RemoveFromListAndBookmarkBar(self, name): |
| """Remove the bookmark bor and bookmarks list. |
| |
| Args: |
| name: the name of bookmark to remove. |
| """ |
| bookmarks = self.GetBookmarkModel() |
| node = bookmarks.FindByTitle(name) |
| self.RemoveBookmark(node[0]['id']) |
| self.bookmarks_list.remove(name) |
| |
| def _DuplicateBookmarks(self, name): |
| """Find duplicate bookmark in the bookmarks list. |
| |
| Args: |
| name: name of the bookmark. |
| |
| Returns: |
| True if it's a duplicate. |
| """ |
| for index in (self.bookmarks_list): |
| if index == name: |
| return True |
| return False |
| |
| def _BookMarkEvery5thURL(self, window_index): |
| """Check for duplicate in list and bookmark current url. |
| If its the first time and list is empty add the bookmark. |
| If its a duplicate remove the bookmark. |
| If its new tab page move over. |
| |
| Args: |
| window_index: the index of the browser window to work on. |
| """ |
| tab_title = self.GetActiveTabTitle(window_index) # get the page title |
| url = self.GetActiveTabURL(window_index).spec() # get the page url |
| if not self.bookmarks_list: |
| self._AddToListAndBookmark(tab_title, url) # first run bookmark the url |
| return |
| elif self._DuplicateBookmarks(tab_title): |
| self._RemoveFromListAndBookmarkBar(tab_title) |
| return |
| elif tab_title == 'New Tab': # new tab page pass over |
| return |
| else: |
| # new bookmark add it to bookmarkbar |
| self._AddToListAndBookmark(tab_title, url) |
| return |
| |
| def _ReadFileAndLoadInNormalAndIncognito(self): |
| """Read urls and load them in normal and incognito window. |
| We load 96 urls only as we can go back and forth 48 times. |
| Uses time to get different urls in normal and incognito window |
| The source file is taken from stress folder in /data folder. |
| """ |
| # URL source from stress folder in data folder |
| data_file = os.path.join(self.DataDir(), 'pyauto_private', 'stress', |
| 'urls_and_titles') |
| url_data = self.EvalDataFrom(data_file) |
| urls = url_data.keys() |
| i = 0 |
| ticks = int(time.time()) # get the latest time. |
| for url in urls: |
| if i <= 96 : # load only 96 urls. |
| if ticks % 2 == 0: # loading in Incognito and Normal window. |
| self.NavigateToURL(url) |
| else: |
| self.NavigateToURL(url, 1, 0) |
| else: |
| break |
| ticks = ticks - 1 |
| i += 1 |
| return |
| |
| def _StressTestNavigation(self): |
| """ This is the method from where various navigations are called. |
| First we load the urls then call navigete back and forth in |
| incognito window then in normal window. |
| """ |
| self._ReadFileAndLoadInNormalAndIncognito() # Load the urls. |
| self._BrowserGoBack(1) # Navigate back in incognito window. |
| self._BrowserGoForward(1) # Navigate forward in incognito window |
| self._BrowserGoBack(0) # Navigate back in normal window |
| self._BrowserGoForward(0) # Navigate forward in normal window |
| |
| # Preference stress functions |
| |
| def _RandomBool(self): |
| """For any preferences bool value, it takes True or False value. |
| We are generating random True or False value. |
| """ |
| return random.randint(0, 1) == 1 |
| |
| def _RandomURL(self): |
| """Some of preferences take string url, so generating random url here.""" |
| # Site list |
| site_list = ['test1.html', 'test2.html','test3.html','test4.html', |
| 'test5.html', 'test7.html', 'test6.html'] |
| random_site = random.choice(site_list) |
| # Returning a url of random site |
| return self.GetFileURLForPath(os.path.join(self.DataDir(), random_site)) |
| |
| def _RandomURLArray(self): |
| """Returns a list of 10 random URLs.""" |
| return [self._RandomURL() for _ in range(10)] |
| |
| def _RandomInt(self, max_number): |
| """Some of the preferences takes integer value. |
| Eg: If there are three options, we generate random |
| value for any option. |
| |
| Arg: |
| max_number: The number of options that a preference has. |
| """ |
| return random.randrange(1, max_number) |
| |
| def _RandomDownloadDir(self): |
| """Returns a random download directory.""" |
| return random.choice(['dl_dir1', 'dl_dir2', 'dl_dir3', |
| 'dl_dir4', 'dl_dir5']) |
| |
| def _SetPref(self): |
| """Reads the preferences from file and |
| sets the preferences to Chrome. |
| """ |
| raw_dictionary = self.EvalDataFrom(os.path.join(self.DataDir(), |
| 'pyauto_private', 'stress', 'pref_dict')) |
| value_dictionary = {} |
| |
| for key, value in raw_dictionary.iteritems(): |
| if value == 'BOOL': |
| value_dictionary[key] = self._RandomBool() |
| elif value == 'STRING_URL': |
| value_dictionary[key] = self._RandomURL() |
| elif value == 'ARRAY_URL': |
| value_dictionary[key] = self._RandomURLArray() |
| elif value == 'STRING_PATH': |
| value_dictionary[key] = self._RandomDownloadDir() |
| elif value[0:3] == 'INT': |
| # Normally we difine INT datatype with number of options, |
| # so parsing number of options and selecting any of them |
| # randomly. |
| value_dictionary[key] = 1 |
| max_number = raw_dictionary[key][3:4] |
| if not max_number == 1: |
| value_dictionary[key]= self._RandomInt(int(max_number)) |
| self.SetPrefs(getattr(pyauto,key), value_dictionary[key]) |
| |
| return value_dictionary |
| |
| # Crash reporting functions |
| |
| def _CrashDumpFolder(self): |
| """Get the breakpad folder. |
| |
| Returns: |
| The full path of the Crash Reports folder. |
| """ |
| breakpad_folder = self.GetBrowserInfo()['properties']['DIR_CRASH_DUMPS'] |
| self.assertTrue(breakpad_folder, 'Cannot figure crash dir') |
| return breakpad_folder |
| |
| def _DeleteDumps(self): |
| """Delete all the dump files in teh Crash Reports folder.""" |
| # should be called at the start of stress run |
| if os.path.exists(self.breakpad_dir): |
| logging.info('xxxxxxxxxxxxxxxINSIDE DELETE DUMPSxxxxxxxxxxxxxxxxx') |
| if self.IsMac(): |
| shutil.rmtree(self.breakpad_dir) |
| elif self.IsWin(): |
| files = os.listdir(self.breakpad_dir) |
| for file in files: |
| os.remove(file) |
| |
| first_crash = os.path.join(os.getcwd(), '1stcrash') |
| crashes_dir = os.path.join(os.getcwd(), 'crashes') |
| if (os.path.exists(crashes_dir)): |
| shutil.rmtree(crashes_dir) |
| shutil.rmtree(first_crash) |
| |
| def _SymbolicateCrashDmp(self, dmp_file, symbols_dir, output_file): |
| """Generate symbolicated crash report. |
| |
| Args: |
| dmp_file: the dmp file to symbolicate. |
| symbols_dir: the directory containing the symbols. |
| output_file: the output file. |
| |
| Returns: |
| Crash report text. |
| """ |
| report = '' |
| if self.IsWin(): |
| windbg_cmd = [ |
| os.path.join('C:', 'Program Files', 'Debugging Tools for Windows', |
| 'windbg.exe'), |
| '-Q', |
| '-y', |
| '\"', |
| symbols_dir, |
| '\"', |
| '-c', |
| '\".ecxr;k50;.logclose;q\"', |
| '-logo', |
| output_file, |
| '-z', |
| '\"', |
| dmp_file, |
| '\"'] |
| subprocess.call(windbg_cmd) |
| # Since we are directly writing the info into output_file, |
| # we just need to copy that in to report |
| report = open(output_file, 'r').read() |
| |
| elif self.IsMac(): |
| crash_report = os.path.join(self.DataDir(), 'pyauto_private', 'stress', |
| 'mac', 'crash_report') |
| for i in range(5): # crash_report doesn't work sometimes. So we retry |
| report = test_utils.Shell2( |
| '%s -S "%s" "%s"' % (crash_report, symbols_dir, dmp_file))[0] |
| if len(report) < 200: |
| try_again = 'Try %d. crash_report didn\'t work out. Trying again', i |
| logging.info(try_again) |
| else: |
| break |
| open(output_file, 'w').write(report) |
| return report |
| |
| def _SaveSymbols(self, symbols_dir, dump_dir=' ', multiple_dumps=True): |
| """Save the symbolicated files for all crash dumps. |
| |
| Args: |
| symbols_dir: the directory containing the symbols. |
| dump_dir: Path to the directory holding the crash dump files. |
| multiple_dumps: True if we are processing multiple dump files, |
| False if we are processing only the first crash. |
| """ |
| if multiple_dumps: |
| dump_dir = self.breakpad_dir |
| |
| if not os.path.isdir(CRASHES): |
| os.makedirs(CRASHES) |
| |
| # This will be sent to the method by the caller. |
| dmp_files = glob.glob(os.path.join(dump_dir, '*.dmp')) |
| for dmp_file in dmp_files: |
| dmp_id = os.path.splitext(os.path.basename(dmp_file))[0] |
| if multiple_dumps: |
| report_folder = CRASHES |
| else: |
| report_folder = dump_dir |
| report_fname = os.path.join(report_folder, |
| '%s.txt' % (dmp_id)) |
| report = self._SymbolicateCrashDmp(dmp_file, symbols_dir, |
| report_fname) |
| if report == '': |
| logging.info('Crash report is empty.') |
| # This is for copying the original dumps. |
| if multiple_dumps: |
| shutil.copy2(dmp_file, CRASHES) |
| |
| def _GetFirstCrashDir(self): |
| """Get first crash file in the crash folder. |
| Here we create the 1stcrash directory which holds the |
| first crash report, which will be attached to the mail. |
| """ |
| breakpad_folder = self.breakpad_dir |
| dump_list = glob.glob1(breakpad_folder,'*.dmp') |
| dump_list.sort(key=lambda s: os.path.getmtime(os.path.join( |
| breakpad_folder, s))) |
| first_crash_file = os.path.join(breakpad_folder, dump_list[0]) |
| |
| if not os.path.isdir('1stcrash'): |
| os.makedirs('1stcrash') |
| shutil.copy2(first_crash_file, '1stcrash') |
| first_crash_dir = os.path.join(os.getcwd(), '1stcrash') |
| return first_crash_dir |
| |
| def _GetFirstCrashFile(self): |
| """Get first crash file in the crash folder.""" |
| first_crash_dir = os.path.join(os.getcwd(), '1stcrash') |
| for each in os.listdir(first_crash_dir): |
| if each.endswith('.txt'): |
| first_crash_file = each |
| return os.path.join(first_crash_dir, first_crash_file) |
| |
| def _ProcessOnlyFirstCrash(self): |
| """ Process only the first crash report for email.""" |
| first_dir = self._GetFirstCrashDir() |
| self._SaveSymbols(self.symbols_dir, first_dir, False) |
| |
| def _GetOSName(self): |
| """Returns the OS type we are running this script on.""" |
| os_name = '' |
| if self.IsMac(): |
| os_number = commands.getoutput('sw_vers -productVersion | cut -c 1-4') |
| if os_number == '10.6': |
| os_name = 'Snow_Leopard' |
| elif os_number == '10.5': |
| os_name = 'Leopard' |
| elif self.IsWin(): |
| # TODO: Windows team need to find the way to get OS name |
| os_name = 'Windows' |
| if platform.version()[0] == '5': |
| os_name = os_name + '_XP' |
| else: |
| os_name = os_name + '_Vista/Win7' |
| return os_name |
| |
| def _ProcessUploadAndEmailCrashes(self): |
| """Upload the crashes found and email the team about this.""" |
| logging.info('#########INSIDE _ProcessUploadAndEmailCrashes#########') |
| try: |
| build_version = self.chrome_version |
| self._SaveSymbols(self.symbols_dir) |
| self._ProcessOnlyFirstCrash() |
| file_to_attach = self._GetFirstCrashFile() |
| # removing the crash_txt for now, |
| # since we are getting UnicodeDecodeError |
| # crash_txt = open(file_to_attach).read() |
| except ValueError: |
| test_utils.SendMail(self.stress_pref['mailing_address'], |
| self.stress_pref['mailing_address'], |
| "We don't have build version", |
| "BROWSER CRASHED, PLEASE CHECK", |
| self.stress_pref['smtp']) |
| # Move crash reports and dumps to server |
| os_name = self._GetOSName() |
| dest_dir = build_version + '_' + os_name |
| if (test_utils.Shell2(self.stress_pref['script'] % (CRASHES, dest_dir))): |
| logging.info('Copy Complete') |
| upload_dir= self.stress_pref['upload_dir'] + dest_dir |
| num_crashes = '\n \n Number of Crashes :' + \ |
| str(len(glob.glob1(self.breakpad_dir, '*.dmp'))) |
| mail_content = '\n\n Crash Report URL :' + upload_dir + '\n' + \ |
| num_crashes + '\n\n' # + crash_txt |
| mail_subject = 'Stress Results :' + os_name + '_' + build_version |
| # Sending mail with first crash report, # of crashes, location of upload |
| test_utils.SendMail(self.stress_pref['mailing_address'], |
| self.stress_pref['mailing_address'], |
| mail_subject, mail_content, |
| self.stress_pref['smtp'], file_to_attach) |
| |
| def _ReportCrashIfAny(self): |
| """Check for browser crashes and report.""" |
| if os.path.isdir(self.breakpad_dir): |
| listOfDumps = glob.glob(os.path.join(self.breakpad_dir, '*.dmp')) |
| if len(listOfDumps) > 0: |
| logging.info('========== INSIDE REPORT CRASH++++++++++++++') |
| # inform a method to process the dumps |
| self._ProcessUploadAndEmailCrashes() |
| |
| # Test functions |
| |
| def _PrefStress(self): |
| """Stress preferences.""" |
| default_prefs = self.GetPrefsInfo() |
| pref_dictionary = self._SetPref() |
| for key, value in pref_dictionary.iteritems(): |
| self.assertEqual(value, self.GetPrefsInfo().Prefs( |
| getattr(pyauto, key))) |
| |
| for key, value in pref_dictionary.iteritems(): |
| self.SetPrefs(getattr(pyauto, key), |
| default_prefs.Prefs(getattr(pyauto, key))) |
| |
| def _NavigationStress(self): |
| """Run back and forward stress in normal and incognito window.""" |
| self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW) |
| self._StressTestNavigation() |
| |
| def _DownloadStress(self): |
| """Run all the Download stress test.""" |
| org_download_dir = self.GetDownloadDirectory().value() |
| new_dl_dir = os.path.join(org_download_dir, 'My+Downloads Folder') |
| os.path.exists(new_dl_dir) and shutil.rmtree(new_dl_dir) |
| os.makedirs(new_dl_dir) |
| self.SetPrefs(pyauto.kDownloadDefaultDirectory, new_dl_dir) |
| self._OpenAndCloseMultipleTabsWithDownloads() |
| self._OpenAndCloseMultipleWindowsWithDownloads() |
| self._OpenAndCloseMultipleTabsWithMultipleDownloads() |
| self._OpenAndCloseMultipleWindowsWithMultipleDownloads() |
| pyauto_utils.RemovePath(new_dl_dir) # cleanup |
| self.SetPrefs(pyauto.kDownloadDefaultDirectory, org_download_dir) |
| |
| def _PluginStress(self): |
| """Run all the plugin stress tests.""" |
| self._OpenAndCloseMultipleTabsWithFlash() |
| self._OpenAndCloseMultipleWindowsWithFlash() |
| self._OpenAndCloseMultipleTabsWithMultiplePlugins() |
| self._OpenAndCloseMultipleWindowsWithMultiplePlugins() |
| self._KillAndReloadRenderersWithFlash() |
| self._ToggleAndReloadFlashPlugin() |
| |
| def testStress(self): |
| """Run all the stress tests for 24 hrs.""" |
| if self.GetBrowserInfo()['properties']['branding'] != 'Google Chrome': |
| logging.info('This is not a branded build, so stopping the stress') |
| return 1 |
| self._DownloadSymbols() |
| run_number = 1 |
| start_time = time.time() |
| while True: |
| logging.info('run %d...' % run_number) |
| run_number = run_number + 1 |
| if (time.time() - start_time) >= 24*60*60: |
| logging.info('Its been 24hrs, so we break now.') |
| break |
| try: |
| methods = [self._NavigationStress, self._DownloadStress, |
| self._PluginStress, self._PrefStress] |
| random.shuffle(methods) |
| for method in methods: |
| method() |
| logging.info('Method %s done' % method) |
| except KeyboardInterrupt: |
| logging.info('----------We got a KeyboardInterrupt-----------') |
| except Exception, error: |
| logging.info('-------------There was an ERROR---------------') |
| logging.info(error) |
| |
| # Crash Reporting |
| self._ReportCrashIfAny() |
| self._DeleteDumps() |
| |
| if self.IsMac(): |
| zombie = 'ps -el | grep Chrom | grep -v grep | grep Z | wc -l' |
| zombie_count = int(commands.getoutput(zombie)) |
| if zombie_count > 0: |
| logging.info('WE HAVE ZOMBIES = %d' % zombie_count) |
| |
| |
| if __name__ == '__main__': |
| pyauto_functional.Main() |