1 # ***** BEGIN LICENSE BLOCK *****
2 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 # The contents of this file are subject to the Mozilla Public License Version
5 # 1.1 (the "License"); you may not use this file except in compliance with
6 # the License. You may obtain a copy of the License at
7 # http://www.mozilla.org/MPL/
9 # Software distributed under the License is distributed on an "AS IS" basis,
10 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 # for the specific language governing rights and limitations under the
14 # The Original Code is standalone Firefox Windows performance test.
16 # The Initial Developer of the Original Code is Google Inc.
17 # Portions created by the Initial Developer are Copyright (C) 2006
18 # the Initial Developer. All Rights Reserved.
21 # Annie Sullivan <annie.sullivan@gmail.com> (original author)
22 # Ben Hearsum <bhearsum@wittydomain.com> (OS independence)
23 # Alice Nodelman <anodelman@mozilla.com>
25 # Alternatively, the contents of this file may be used under the terms of
26 # either the GNU General Public License Version 2 or later (the "GPL"), or
27 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 # in which case the provisions of the GPL or the LGPL are applicable instead
29 # of those above. If you wish to allow use of your version of this file only
30 # under the terms of either the GPL or the LGPL, and not to allow others to
31 # use your version of this file under the terms of the MPL, indicate your
32 # decision by deleting the provisions above and replace them with the notice
33 # and other provisions required by the GPL or the LGPL. If you do not delete
34 # the provisions above, a recipient may use your version of this file under
35 # the terms of any one of the MPL, the GPL or the LGPL.
37 # ***** END LICENSE BLOCK *****
39 """A generic means of running an URL based browser test
40 follows the following steps
43 - gets metrics for the current test environment
45 - collects info on any counters while test runs
46 - waits for a 'dump' from the browser
49 __author__
= 'annie.sullivan@gmail.com (Annie Sullivan)'
60 from utils
import talosError
65 if platform
.system() == "Linux":
66 from cmanager_linux
import *
67 platform_type
= 'unix_'
68 elif platform
.system() in ("Windows", "Microsoft"):
69 from cmanager_win32
import *
70 platform_type
= 'win_'
71 elif platform
.system() == "Darwin":
72 from cmanager_mac
import *
73 platform_type
= 'unix_'
76 # Regula expression for getting results from most tests
77 RESULTS_REGEX
= re
.compile('__start_report(.*)__end_report',
78 re
.DOTALL | re
.MULTILINE
)
79 # Regular expression to get stats for page load test (Tp) - should go away once data passing is standardized
80 RESULTS_TP_REGEX
= re
.compile('__start_tp_report(.*)__end_tp_report',
81 re
.DOTALL | re
.MULTILINE
)
82 RESULTS_GENERIC
= re
.compile('(.*)', re
.DOTALL | re
.MULTILINE
)
83 RESULTS_REGEX_FAIL
= re
.compile('__FAIL(.*)__FAIL', re
.DOTALL|re
.MULTILINE
)
85 def checkBrowserAlive():
86 #is the browser actually up?
87 return (ffprocess
.ProcessesWithNameExist("firefox") and not ffprocess
.ProcessesWithNameExist("crashreporter", "talkback", "dwwin"))
89 def checkAllProcesses():
90 #is anything browser related active?
91 return ffprocess
.ProcessesWithNameExist("firefox", "crashreporter", "talkback", "dwwin")
93 def cleanupProcesses():
94 #kill any remaining firefox processes
95 ffprocess
.TerminateAllProcesses("firefox", "crashreporter", "dwwin", "talkback")
96 #check if anything is left behind
97 if checkAllProcesses():
98 #this is for windows machines. when attempting to send kill messages to win processes the OS
99 # always gives the process a chance to close cleanly before terminating it, this takes longer
100 # and we need to give it a little extra time to complete
102 if checkAllProcesses():
103 raise talosError("failed to cleanup")
105 def createProfile(browser_config
):
106 if browser_config
["profile_path"] != {}:
107 # Create the new profile
108 temp_dir
, profile_dir
= ffsetup
.CreateTempProfileDir(browser_config
['profile_path'],
109 browser_config
['preferences'],
110 browser_config
['extensions'])
111 utils
.debug("created profile")
113 # no profile path was set in the config, set the profile_dir to an empty string.
115 return profile_dir
, temp_dir
117 def initializeProfile(profile_dir
, browser_config
):
118 if browser_config
["profile_path"] != {}:
119 if not (ffsetup
.InitializeNewProfile(browser_config
['firefox'], profile_dir
, browser_config
['init_url'])):
120 raise talosError("failed to initialize browser")
122 if checkAllProcesses():
123 raise talosError("browser failed to close after being initialized")
125 def cleanupProfile(dir, browser_config
):
126 # Delete the temp profile directory Make it writeable first,
127 # because every once in a while Firefox seems to drop a read-only
129 if browser_config
["profile_path"] != {}:
130 ffsetup
.MakeDirectoryContentsWritable(dir)
133 def runTest(browser_config
, test_config
):
135 Runs an url based test on the browser as specified in the browser_config dictionary
138 browser_config: Dictionary of configuration options for the browser (paths, prefs, etc)
139 test_config : Dictionary of configuration for the given test (url, cycles, counters, etc)
143 utils
.debug("operating with platform_type : " + platform_type
)
144 counters
= test_config
[platform_type
+ 'counters']
145 resolution
= test_config
['resolution']
146 all_browser_results
= []
147 all_counter_results
= []
148 utils
.setEnvironmentVars(browser_config
['env'])
152 if checkAllProcesses():
153 utils
.debug("firefox already running before testing started (unclean system)")
154 raise talosError("system not clean")
156 # add any provided directories to the installed firefox
157 for dir in browser_config
['dirs']:
158 ffsetup
.InstallInBrowser(browser_config
['firefox'], browser_config
['dirs'][dir])
160 profile_dir
, temp_dir
= createProfile(browser_config
)
161 initializeProfile(profile_dir
, browser_config
)
163 utils
.debug("initialized firefox")
166 for i
in range(test_config
['cycles']):
167 # check to see if the previous cycle is still hanging around
168 if (i
> 0) and checkAllProcesses():
169 raise talosError("previous cycle still running")
172 if 'timeout' in test_config
:
173 timeout
= test_config
['timeout']
175 timeout
= 28800 # 8 hours
178 url
= test_config
['url']
179 if 'url_mod' in test_config
:
180 url
+= eval(test_config
['url_mod'])
181 command_line
= ffprocess
.GenerateFirefoxCommandLine(browser_config
['firefox'], profile_dir
, url
)
183 utils
.debug("command line: " + command_line
)
185 process
= subprocess
.Popen(command_line
, stdout
=subprocess
.PIPE
, universal_newlines
=True, shell
=True, bufsize
=0, env
=os
.environ
)
186 handle
= process
.stdout
188 #give firefox a chance to open
189 # this could mean that we are losing the first couple of data points as the tests starts, but if we don't provide
190 # some time for the browser to start we have trouble connecting the CounterManager to it
192 #set up the counters for this test
194 cm
= CounterManager("firefox", counters
)
197 for counter
in counters
:
198 counter_results
[counter
] = []
201 while total_time
< timeout
:
202 # Sleep for [resolution] seconds
203 time
.sleep(resolution
)
204 total_time
+= resolution
206 # Get the output from all the possible counters
207 for count_type
in counters
:
208 val
= cm
.getCounterValue(count_type
)
211 counter_results
[count_type
].append(val
)
213 # Check to see if page load times were outputted
214 (bytes
, current_output
) = ffprocess
.NonBlockingReadProcessOutput(handle
)
215 output
+= current_output
216 match
= RESULTS_GENERIC
.search(current_output
)
219 utils
.noisy(match
.group(1))
220 match
= RESULTS_REGEX
.search(output
)
222 browser_results
+= match
.group(1)
223 utils
.debug("Matched basic results: " + browser_results
)
225 #TODO: this a stop gap until all of the tests start outputting the same format
226 match
= RESULTS_TP_REGEX
.search(output
)
228 browser_results
+= match
.group(1)
229 utils
.debug("Matched tp results: " + browser_results
)
231 match
= RESULTS_REGEX_FAIL
.search(output
)
233 browser_results
+= match
.group(1)
234 utils
.debug("Matched fail results: " + browser_results
)
235 raise talosError(match
.group(1))
237 #ensure that the browser is still running
238 #check at intervals of 60 - this is just to cut down on load
239 #use the busted check to ensure that we aren't catching a bad time slice where the browser has
240 # completed the test and closed but we haven't picked up the result yet
242 raise talosError("browser crash")
243 if (total_time
% 60 == 0):
244 if not checkBrowserAlive():
247 if total_time
>= timeout
:
248 raise talosError("timeout exceeded")
250 #stop the counter manager since this test is complete
254 utils
.debug("Completed test with: " + browser_results
)
256 all_browser_results
.append(browser_results
)
257 all_counter_results
.append(counter_results
)
260 cleanupProfile(temp_dir
, browser_config
)
262 utils
.restoreEnvironmentVars()
264 return (all_browser_results
, all_counter_results
)
268 if vars().has_key('temp_dir'):
269 cleanupProfile(temp_dir
, browser_config
)
270 except talosError
, te
:
271 utils
.debug("cleanup error: " + te
.msg
)
273 utils
.debug("unknown error during cleanup")