- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / functional / stress.py
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()