Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: webkit/tools/leak_tests/run_node_leak_test.py

Issue 8678022: Fix python scripts in src/webkit (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: 2012 Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2006-2008 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 """Run node leak tests using the test_shell.
7
8 TODO(pjohnson): Add a way for layout tests (and other local files in the
9 working copy) to be easily run by specifying paths relative to webkit (or
10 something similar).
11 """
12
13 import logging
14 import optparse
15 import os
16 import random
17 import re
18 import sys
19
20 import google.logging_utils
21 import google.path_utils
22 import google.platform_utils
23 import google.process_utils
24
25 # Magic exit code to indicate a new fix.
26 REBASELINE_EXIT_CODE = -88
27
28 # Status codes.
29 PASS, FAIL, REBASELINE = range(3)
30
31 # The test list files are found in this subdirectory, which must be a sibling
32 # to this script itself.
33 TEST_FILE_DIR = 'test_lists'
34
35 # TODO(pjohnson): Find a way to avoid this duplicate code. This function has
36 # been shamelessly taken from layout_tests/layout_package.
37 _webkit_root = None
38
39 def WebKitRoot():
40 """Returns the full path to the directory containing webkit.sln. Raises
41 PathNotFound if we're unable to find webkit.sln.
42 """
43
44 global _webkit_root
45 if _webkit_root:
46 return _webkit_root
47 webkit_sln_path = google.path_utils.FindUpward(google.path_utils.ScriptDir(),
48 'webkit.sln')
49 _webkit_root = os.path.dirname(webkit_sln_path)
50 return _webkit_root
51
52 def GetAbsolutePath(path):
53 platform_util = google.platform_utils.PlatformUtility(WebKitRoot())
54 return platform_util.GetAbsolutePath(path)
55
56 # TODO(pjohnson): Find a way to avoid this duplicated code. This function has
57 # been mostly copied from another function, TestShellBinary, in
58 # layout_tests/layout_package.
59 def TestShellTestBinary(target):
60 """Gets the full path to the test_shell_tests binary for the target build
61 configuration. Raises PathNotFound if the file doesn't exist.
62 """
63
64 full_path = os.path.join(WebKitRoot(), target, 'test_shell_tests.exe')
65 if not os.path.exists(full_path):
66 # Try chrome's output directory in case test_shell was built by chrome.sln.
67 full_path = google.path_utils.FindUpward(WebKitRoot(), 'chrome', target,
68 'test_shell_tests.exe')
69 if not os.path.exists(full_path):
70 raise PathNotFound('unable to find test_shell_tests at %s' % full_path)
71 return full_path
72
73 class NodeLeakTestRunner:
74 """A class for managing running a series of node leak tests.
75 """
76
77 def __init__(self, options, urls):
78 """Collect a list of URLs to test.
79
80 Args:
81 options: a dictionary of command line options
82 urls: a list of URLs in the format:
83 (url, expected_node_leaks, expected_js_leaks) tuples
84 """
85
86 self._options = options
87 self._urls = urls
88
89 self._test_shell_test_binary = TestShellTestBinary(options.target)
90
91 self._node_leak_matcher = re.compile('LEAK: (\d+) Node')
92 self._js_leak_matcher = re.compile('Leak (\d+) JS wrappers')
93
94 def RunCommand(self, command):
95 def FindMatch(line, matcher, group_number):
96 match = matcher.match(line)
97 if match:
98 return int(match.group(group_number))
99 return 0
100
101 (code, output) = google.process_utils.RunCommandFull(command, verbose=True,
102 collect_output=True,
103 print_output=False)
104 node_leaks = 0
105 js_leaks = 0
106
107 # Print a row of dashes.
108 if code != 0:
109 print '-' * 75
110 print 'OUTPUT'
111 print
112
113 for line in output:
114 # Sometimes multiple leak lines are printed out, which is why we
115 # accumulate them here.
116 node_leaks += FindMatch(line, self._node_leak_matcher, 1)
117 js_leaks += FindMatch(line, self._js_leak_matcher, 1)
118
119 # If the code indicates there was an error, print the output to help
120 # figure out what happened.
121 if code != 0:
122 print line
123
124 # Print a row of dashes.
125 if code != 0:
126 print '-' * 75
127 print
128
129 return (code, node_leaks, js_leaks)
130
131 def RunUrl(self, test_url, expected_node_leaks, expected_js_leaks):
132 shell_args = ['--gtest_filter=NodeLeakTest.*TestURL',
133 '--time-out-ms=' + str(self._options.time_out_ms),
134 '--test-url=' + test_url,
135 '--playback-mode']
136
137 if self._options.cache_dir != '':
138 shell_args.append('--cache-dir=' + self._options.cache_dir)
139
140 command = [self._test_shell_test_binary] + shell_args
141 (exit_code, actual_node_leaks, actual_js_leaks) = self.RunCommand(command)
142
143 logging.info('%s\n' % test_url)
144
145 if exit_code != 0:
146 # There was a crash, or something else went wrong, so duck out early.
147 logging.error('Test returned: %d\n' % exit_code)
148 return FAIL
149
150 result = ('TEST RESULT\n'
151 ' Node Leaks: %d (actual), %d (expected)\n'
152 ' JS Leaks: %d (actual), %d (expected)\n' %
153 (actual_node_leaks, expected_node_leaks,
154 actual_js_leaks, expected_js_leaks))
155
156 success = (actual_node_leaks <= expected_node_leaks and
157 actual_js_leaks <= expected_js_leaks)
158
159 if success:
160 logging.info(result)
161 else:
162 logging.error(result)
163 logging.error('Unexpected leaks found!\n')
164 return FAIL
165
166 if (expected_node_leaks > actual_node_leaks or
167 expected_js_leaks > actual_js_leaks):
168 logging.warn('Expectations may need to be re-baselined.\n')
169 # TODO(pjohnson): Return REBASELINE here once bug 1177263 is fixed and
170 # the expectations have been lowered again.
171
172 return PASS
173
174 def Run(self):
175 status = PASS
176 results = [0, 0, 0]
177 failed_urls = []
178 rebaseline_urls = []
179
180 for (test_url, expected_node_leaks, expected_js_leaks) in self._urls:
181 result = self.RunUrl(test_url, expected_node_leaks, expected_js_leaks)
182 if result == PASS:
183 results[PASS] += 1
184 elif result == FAIL:
185 results[FAIL] += 1
186 failed_urls.append(test_url)
187 status = FAIL
188 elif result == REBASELINE:
189 results[REBASELINE] += 1
190 rebaseline_urls.append(test_url)
191 if status != FAIL:
192 status = REBASELINE
193 return (status, results, failed_urls, rebaseline_urls)
194
195 def main(options, args):
196 if options.seed != None:
197 random.seed(options.seed)
198
199 # Set up logging so any messages below logging.WARNING are sent to stdout,
200 # otherwise they are sent to stderr.
201 google.logging_utils.config_root(level=logging.INFO,
202 threshold=logging.WARNING)
203
204 if options.url_list == '':
205 logging.error('URL test list required')
206 sys.exit(1)
207
208 url_list = os.path.join(os.path.dirname(sys.argv[0]), TEST_FILE_DIR,
209 options.url_list)
210 url_list = GetAbsolutePath(url_list);
211
212 lines = []
213 file = None
214 try:
215 file = open(url_list, 'r')
216 lines = file.readlines()
217 finally:
218 if file != None:
219 file.close()
220
221 expected_matcher = re.compile('(\d+)\s*,\s*(\d+)')
222
223 urls = []
224 for line in lines:
225 line = line.strip()
226 if len(line) == 0 or line.startswith('#'):
227 continue
228 list = line.rsplit('=', 1)
229 if len(list) < 2:
230 logging.error('Line "%s" is not formatted correctly' % line)
231 continue
232 match = expected_matcher.match(list[1].strip())
233 if not match:
234 logging.error('Line "%s" is not formatted correctly' % line)
235 continue
236 urls.append((list[0].strip(), int(match.group(1)), int(match.group(2))))
237
238 random.shuffle(urls)
239 runner = NodeLeakTestRunner(options, urls)
240 (status, results, failed_urls, rebaseline_urls) = runner.Run()
241
242 logging.info('SUMMARY\n'
243 ' %d passed\n'
244 ' %d failed\n'
245 ' %d re-baseline\n' %
246 (results[0], results[1], results[2]))
247
248 if len(failed_urls) > 0:
249 failed_string = '\n'.join(' ' + url for url in failed_urls)
250 logging.error('FAILED URLs\n%s\n' % failed_string)
251
252 if len(rebaseline_urls) > 0:
253 rebaseline_string = '\n'.join(' ' + url for url in rebaseline_urls)
254 logging.warn('RE-BASELINE URLs\n%s\n' % rebaseline_string)
255
256 if status == FAIL:
257 return 1
258 elif status == REBASELINE:
259 return REBASELINE_EXIT_CODE
260 return 0
261
262 if '__main__' == __name__:
263 option_parser = optparse.OptionParser()
264 option_parser.add_option('', '--target', default='Debug',
265 help='build target (Debug or Release)')
266 option_parser.add_option('', '--cache-dir', default='',
267 help='use a specified cache directory')
268 option_parser.add_option('', '--url-list', default='',
269 help='URL input file, with leak expectations, '
270 'relative to webkit/tools/leak_tests')
271 option_parser.add_option('', '--time-out-ms', default=30000,
272 help='time out for each test')
273 option_parser.add_option('', '--seed', default=None,
274 help='seed for random number generator, use to '
275 'reproduce the exact same order for a '
276 'specific run')
277 options, args = option_parser.parse_args()
278 sys.exit(main(options, args))
279
OLDNEW
« no previous file with comments | « webkit/tools/layout_tests/run_http_server.py ('k') | webkit/tools/leak_tests/test_lists/alexa_100.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698