| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """A tool to run a chrome test executable, used by the buildbot slaves. | 6 """A tool to run a chrome test executable, used by the buildbot slaves. |
| 7 | 7 |
| 8 When this is run, the current directory (cwd) should be the outer build | 8 When this is run, the current directory (cwd) should be the outer build |
| 9 directory (e.g., chrome-release/build/). | 9 directory (e.g., chrome-release/build/). |
| 10 | 10 |
| 11 For a list of command-line options, call this script with '--help'. | 11 For a list of command-line options, call this script with '--help'. |
| 12 """ | 12 """ |
| 13 | 13 |
| 14 import copy | 14 import copy |
| 15 import logging | 15 import logging |
| 16 import optparse | 16 import optparse |
| 17 import os | 17 import os |
| 18 import re |
| 18 import stat | 19 import stat |
| 19 import sys | 20 import sys |
| 20 import tempfile | 21 import tempfile |
| 21 | 22 |
| 22 # sys.path needs to be modified here because python2.6 automatically adds the | 23 # sys.path needs to be modified here because python2.6 automatically adds the |
| 23 # system "google" module (/usr/lib/pymodules/python2.6/google) to sys.modules | 24 # system "google" module (/usr/lib/pymodules/python2.6/google) to sys.modules |
| 24 # when we import "chromium_config" (I don't know why it does this). This causes | 25 # when we import "chromium_config" (I don't know why it does this). This causes |
| 25 # the import of our local "google.*" modules to fail because python seems to | 26 # the import of our local "google.*" modules to fail because python seems to |
| 26 # only look for a system "google.*", even if our path is in sys.path before | 27 # only look for a system "google.*", even if our path is in sys.path before |
| 27 # importing "google.*". If we modify sys.path here, before importing | 28 # importing "google.*". If we modify sys.path here, before importing |
| 28 # "chromium_config", python2.6 properly uses our path to find our "google.*" | 29 # "chromium_config", python2.6 properly uses our path to find our "google.*" |
| 29 # (even though it still automatically adds the system "google" module to | 30 # (even though it still automatically adds the system "google" module to |
| 30 # sys.modules, and probably should still be using that to resolve "google.*", | 31 # sys.modules, and probably should still be using that to resolve "google.*", |
| 31 # which I really don't understand). | 32 # which I really don't understand). |
| 32 sys.path.insert(0, os.path.abspath('src/tools/python')) | 33 sys.path.insert(0, os.path.abspath('src/tools/python')) |
| 33 | 34 |
| 34 # Because of this dependency on a chromium checkout, we need to disable some | 35 # Because of this dependency on a chromium checkout, we need to disable some |
| 35 # pylint checks. | 36 # pylint checks. |
| 36 # pylint: disable=E0611 | 37 # pylint: disable=E0611 |
| 37 # pylint: disable=E1101 | 38 # pylint: disable=E1101 |
| 39 from buildbot.status import builder |
| 40 |
| 38 from common import chromium_utils | 41 from common import chromium_utils |
| 42 from common import gtest_utils |
| 39 from slave import gtest_slave_utils | 43 from slave import gtest_slave_utils |
| 40 from slave import slave_utils | 44 from slave import slave_utils |
| 41 from slave import xvfb | 45 from slave import xvfb |
| 42 import config | 46 import config |
| 43 | 47 |
| 44 USAGE = '%s [options] test.exe [test args]' % os.path.basename(sys.argv[0]) | 48 USAGE = '%s [options] test.exe [test args]' % os.path.basename(sys.argv[0]) |
| 45 | 49 |
| 46 CHROME_SANDBOX_PATH = '/opt/chromium/chrome_sandbox' | 50 CHROME_SANDBOX_PATH = '/opt/chromium/chrome_sandbox' |
| 47 | 51 |
| 48 DEST_DIR = 'gtest_results' | 52 DEST_DIR = 'gtest_results' |
| 49 | 53 |
| 50 HTTPD_CONF = { | 54 HTTPD_CONF = { |
| 51 'linux': 'httpd2_linux.conf', | 55 'linux': 'httpd2_linux.conf', |
| 52 'mac': 'httpd2_mac.conf', | 56 'mac': 'httpd2_mac.conf', |
| 53 'win': 'httpd.conf' | 57 'win': 'httpd.conf' |
| 54 } | 58 } |
| 55 | 59 |
| 60 |
| 56 def should_enable_sandbox(sandbox_path): | 61 def should_enable_sandbox(sandbox_path): |
| 57 """Return a boolean indicating that the current slave is capable of using the | 62 """Return a boolean indicating that the current slave is capable of using the |
| 58 sandbox and should enable it. This should return True iff the slave is a | 63 sandbox and should enable it. This should return True iff the slave is a |
| 59 Linux host with the sandbox file present and configured correctly.""" | 64 Linux host with the sandbox file present and configured correctly.""" |
| 60 if not (sys.platform.startswith('linux') and | 65 if not (sys.platform.startswith('linux') and |
| 61 os.path.exists(sandbox_path)): | 66 os.path.exists(sandbox_path)): |
| 62 return False | 67 return False |
| 63 sandbox_stat = os.stat(sandbox_path) | 68 sandbox_stat = os.stat(sandbox_path) |
| 64 if ((sandbox_stat.st_mode & stat.S_ISUID) and | 69 if ((sandbox_stat.st_mode & stat.S_ISUID) and |
| 65 (sandbox_stat.st_mode & stat.S_IRUSR) and | 70 (sandbox_stat.st_mode & stat.S_IRUSR) and |
| 66 (sandbox_stat.st_mode & stat.S_IXUSR) and | 71 (sandbox_stat.st_mode & stat.S_IXUSR) and |
| 67 (sandbox_stat.st_uid == 0)): | 72 (sandbox_stat.st_uid == 0)): |
| 68 return True | 73 return True |
| 69 return False | 74 return False |
| 70 | 75 |
| 76 |
| 71 def get_temp_count(): | 77 def get_temp_count(): |
| 72 """Returns the number of files and directories inside the temporary dir.""" | 78 """Returns the number of files and directories inside the temporary dir.""" |
| 73 return len(os.listdir(tempfile.gettempdir())) | 79 return len(os.listdir(tempfile.gettempdir())) |
| 74 | 80 |
| 75 | 81 |
| 76 def _RunGTestCommand(command, results_tracker=None, pipes=None): | 82 def _RunGTestCommand(command, results_tracker=None, pipes=None): |
| 77 if results_tracker and pipes: | 83 if results_tracker and pipes: |
| 78 # This is not supported by RunCommand. | 84 # This is not supported by RunCommand. |
| 79 print 'Invalid test invocation. (results_tracker and pipes)' | 85 print 'Invalid test invocation. (results_tracker and pipes)' |
| 80 return 1 | 86 return 1 |
| 81 if results_tracker: | 87 if results_tracker: |
| 82 return chromium_utils.RunCommand( | 88 return chromium_utils.RunCommand( |
| 83 command, parser_func=results_tracker.OnReceiveLine) | 89 command, parser_func=results_tracker.ProcessLine) |
| 84 else: | 90 else: |
| 85 return chromium_utils.RunCommand(command, pipes=pipes) | 91 return chromium_utils.RunCommand(command, pipes=pipes) |
| 86 | 92 |
| 87 | 93 |
| 88 def _GenerateJSONForTestResults(options, results_tracker): | 94 def _GenerateJSONForTestResults(options, results_tracker): |
| 89 """Generate (update) a JSON file from the gtest results XML and | 95 """Generate (update) a JSON file from the gtest results XML and |
| 90 upload the file to the archive server. | 96 upload the file to the archive server. |
| 91 The archived JSON file will be placed at: | 97 The archived JSON file will be placed at: |
| 92 www-dir/DEST_DIR/buildname/testname/results.json | 98 www-dir/DEST_DIR/buildname/testname/results.json |
| 93 on the archive server (NOTE: this is to be deprecated). | 99 on the archive server (NOTE: this is to be deprecated). |
| 94 Note that it adds slave's WebKit/Tools/Scripts to the PYTHONPATH | 100 Note that it adds slave's WebKit/Tools/Scripts to the PYTHONPATH |
| 95 to run the JSON generator. | 101 to run the JSON generator. |
| 96 | 102 |
| 97 Args: | 103 Args: |
| 98 options: command-line options that are supposed to have build_dir, | 104 options: command-line options that are supposed to have build_dir, |
| 99 results_directory, builder_name, build_name and test_output_xml values. | 105 results_directory, builder_name, build_name and test_output_xml values. |
| 100 """ | 106 """ |
| 101 # pylint: disable=W0703 | 107 # pylint: disable=W0703 |
| 102 results_map = None | 108 results_map = None |
| 103 try: | 109 try: |
| 104 if os.path.exists(options.test_output_xml): | 110 if os.path.exists(options.test_output_xml): |
| 105 results_map = gtest_slave_utils.GetResultsMapFromXML( | 111 results_map = gtest_slave_utils.GetResultsMapFromXML( |
| 106 options.test_output_xml) | 112 options.test_output_xml) |
| 107 else: | 113 else: |
| 108 sys.stderr.write('Unable to generate JSON from XML, using log output.') | 114 sys.stderr.write('Unable to generate JSON from XML, using log output.') |
| 109 # The file did not get generated. See if we can generate a results map | 115 # The file did not get generated. See if we can generate a results map |
| 110 # from the log output. | 116 # from the log output. |
| 111 results_map = results_tracker.GetResultsMap() | 117 results_map = gtest_slave_utils.GetResultsMap(results_tracker) |
| 112 except Exception, e: | 118 except Exception, e: |
| 113 # This error will be caught by the following 'not results_map' statement. | 119 # This error will be caught by the following 'not results_map' statement. |
| 114 print 'Error: ', e | 120 print 'Error: ', e |
| 115 | 121 |
| 116 if not results_map: | 122 if not results_map: |
| 117 print 'No data was available to update the JSON results' | 123 print 'No data was available to update the JSON results' |
| 118 return | 124 return |
| 119 | 125 |
| 120 build_dir = os.path.abspath(options.build_dir) | 126 build_dir = os.path.abspath(options.build_dir) |
| 121 slave_name = slave_utils.SlaveBuildName(build_dir) | 127 slave_name = slave_utils.SlaveBuildName(build_dir) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 140 | 146 |
| 141 # Generate results JSON file and upload it to the appspot server. | 147 # Generate results JSON file and upload it to the appspot server. |
| 142 gtest_slave_utils.GenerateAndUploadJSONResults( | 148 gtest_slave_utils.GenerateAndUploadJSONResults( |
| 143 results_map, generate_json_options) | 149 results_map, generate_json_options) |
| 144 | 150 |
| 145 # The code can throw all sorts of exceptions, including | 151 # The code can throw all sorts of exceptions, including |
| 146 # slave.gtest.networktransaction.NetworkTimeout so just trap everything. | 152 # slave.gtest.networktransaction.NetworkTimeout so just trap everything. |
| 147 except: # pylint: disable=W0702 | 153 except: # pylint: disable=W0702 |
| 148 print 'Unexpected error while generating JSON' | 154 print 'Unexpected error while generating JSON' |
| 149 | 155 |
| 156 |
| 150 def _BuildParallelCommand(build_dir, test_exe_path, options): | 157 def _BuildParallelCommand(build_dir, test_exe_path, options): |
| 151 supervisor_path = os.path.join(build_dir, '..', 'tools', | 158 supervisor_path = os.path.join(build_dir, '..', 'tools', |
| 152 'sharding_supervisor', | 159 'sharding_supervisor', |
| 153 'sharding_supervisor.py') | 160 'sharding_supervisor.py') |
| 154 supervisor_args = ['--no-color'] | 161 supervisor_args = ['--no-color'] |
| 155 if options.factory_properties.get('retry_failed', True): | 162 if options.factory_properties.get('retry_failed', True): |
| 156 supervisor_args.append('--retry-failed') | 163 supervisor_args.append('--retry-failed') |
| 157 if options.total_shards and options.shard_index: | 164 if options.total_shards and options.shard_index: |
| 158 supervisor_args.extend(['--total-slaves', str(options.total_shards), | 165 supervisor_args.extend(['--total-slaves', str(options.total_shards), |
| 159 '--slave-index', str(options.shard_index - 1)]) | 166 '--slave-index', str(options.shard_index - 1)]) |
| 160 if options.sharding_args: | 167 if options.sharding_args: |
| 161 supervisor_args.extend(options.sharding_args.split()) | 168 supervisor_args.extend(options.sharding_args.split()) |
| 162 command = [sys.executable, supervisor_path] | 169 command = [sys.executable, supervisor_path] |
| 163 command.extend(supervisor_args) | 170 command.extend(supervisor_args) |
| 164 command.append(test_exe_path) | 171 command.append(test_exe_path) |
| 165 return command | 172 return command |
| 166 | 173 |
| 174 |
| 167 def start_http_server(platform, build_dir, test_exe_path, document_root): | 175 def start_http_server(platform, build_dir, test_exe_path, document_root): |
| 168 # pylint: disable=F0401 | 176 # pylint: disable=F0401 |
| 169 import google.httpd_utils | 177 import google.httpd_utils |
| 170 import google.platform_utils | 178 import google.platform_utils |
| 171 platform_util = google.platform_utils.PlatformUtility(build_dir) | 179 platform_util = google.platform_utils.PlatformUtility(build_dir) |
| 172 | 180 |
| 173 # Name the output directory for the exe, without its path or suffix. | 181 # Name the output directory for the exe, without its path or suffix. |
| 174 # e.g., chrome-release/httpd_logs/unit_tests/ | 182 # e.g., chrome-release/httpd_logs/unit_tests/ |
| 175 test_exe_name = os.path.splitext(os.path.basename(test_exe_path))[0] | 183 test_exe_name = os.path.splitext(os.path.basename(test_exe_path))[0] |
| 176 output_dir = os.path.join(slave_utils.SlaveBaseDir(build_dir), | 184 output_dir = os.path.join(slave_utils.SlaveBaseDir(build_dir), |
| (...skipping 22 matching lines...) Expand all Loading... |
| 199 document_root) | 207 document_root) |
| 200 stop_cmd = platform_util.GetStopHttpdCommand() | 208 stop_cmd = platform_util.GetStopHttpdCommand() |
| 201 http_server = google.httpd_utils.ApacheHttpd(start_cmd, stop_cmd, [8000]) | 209 http_server = google.httpd_utils.ApacheHttpd(start_cmd, stop_cmd, [8000]) |
| 202 try: | 210 try: |
| 203 http_server.StartServer() | 211 http_server.StartServer() |
| 204 except google.httpd_utils.HttpdNotStarted, e: | 212 except google.httpd_utils.HttpdNotStarted, e: |
| 205 raise google.httpd_utils.HttpdNotStarted('%s. See log file in %s' % | 213 raise google.httpd_utils.HttpdNotStarted('%s. See log file in %s' % |
| 206 (e, output_dir)) | 214 (e, output_dir)) |
| 207 return http_server | 215 return http_server |
| 208 | 216 |
| 217 |
| 218 def getText(result, observer, name): |
| 219 """Generate a text summary for the waterfall. |
| 220 |
| 221 Updates the waterfall with any unusual test output, with a link to logs of |
| 222 failed test steps. |
| 223 """ |
| 224 GTEST_DASHBOARD_BASE = ('http://test-results.appspot.com' |
| 225 '/dashboards/flakiness_dashboard.html') |
| 226 |
| 227 # basic_info is an array of lines to display on the waterfall |
| 228 basic_info = [name] |
| 229 |
| 230 disabled = observer.DisabledTests() |
| 231 if disabled: |
| 232 basic_info.append('%s disabled' % str(disabled)) |
| 233 |
| 234 flaky = observer.FlakyTests() |
| 235 if flaky: |
| 236 basic_info.append('%s flaky' % str(flaky)) |
| 237 |
| 238 failed_test_count = len(observer.FailedTests()) |
| 239 |
| 240 if failed_test_count == 0: |
| 241 if result is builder.SUCCESS: |
| 242 return basic_info |
| 243 elif result is builder.WARNINGS: |
| 244 return basic_info + ['warnings'] |
| 245 |
| 246 if observer.RunningTests(): |
| 247 |
| 248 basic_info += ['did not complete'] |
| 249 |
| 250 # TODO(xusydoc): see if 'crashed or hung' should be tracked by RunningTests() |
| 251 if failed_test_count: |
| 252 failure_text = ['failed %d' % failed_test_count] |
| 253 if observer.master_name: |
| 254 # Include the link to the flakiness dashboard |
| 255 failure_text.append('<div class="BuildResultInfo">') |
| 256 failure_text.append('<a href="%s#master=%s&testType=%s' |
| 257 '&tests=%s">' % ( |
| 258 GTEST_DASHBOARD_BASE, observer.master_name, |
| 259 name, |
| 260 ','.join(observer.FailedTests()))) |
| 261 failure_text.append('Flakiness dashboard') |
| 262 failure_text.append('</a>') |
| 263 failure_text.append('</div>') |
| 264 else: |
| 265 failure_text = ['crashed or hung'] |
| 266 return basic_info + failure_text |
| 267 |
| 268 |
| 269 def annotate(test_name, result, results_tracker): |
| 270 """Given a test result and tracker, update the waterfall with test results.""" |
| 271 get_text_result = builder.SUCCESS |
| 272 |
| 273 for failure in sorted(results_tracker.FailedTests()): |
| 274 testabbr = re.sub(r'[^\w\.\-]', '_', failure.split('.')[-1]) |
| 275 for line in results_tracker.FailureDescription(failure): |
| 276 print '@@@STEP_LOG_LINE@%s@%s@@@' % (testabbr, line) |
| 277 print '@@@STEP_LOG_END@%s@@@' % testabbr |
| 278 |
| 279 for suppression_hash in sorted(results_tracker.SuppressionHashes()): |
| 280 for line in results_tracker.Suppression(suppression_hash): |
| 281 print '@@@STEP_LOG_LINE@%s@%s@@@' % (testabbr, line) |
| 282 print '@@@STEP_LOG_END@%s@@@' % testabbr |
| 283 |
| 284 if results_tracker.ParsingErrors(): |
| 285 # Generate a log file containing the list of errors. |
| 286 for line in results_tracker.ParsingErrors(): |
| 287 print '@@@STEP_LOG_LINE@%s@%s@@@' % ('log parsing error(s)', line) |
| 288 |
| 289 print '@@@STEP_LOG_END@%s@@@' % 'log parsing error(s)' |
| 290 results_tracker.ClearParsingErrors() |
| 291 |
| 292 if result is builder.SUCCESS: |
| 293 if (len(results_tracker.ParsingErrors()) or |
| 294 len(results_tracker.FailedTests()) or |
| 295 len(results_tracker.SuppressionHashes())): |
| 296 print '@@@STEP_WARNINGS@@@' |
| 297 get_text_result = builder.WARNING |
| 298 else: |
| 299 print '@@@STEP_FAILURE@@@' |
| 300 get_text_result = builder.FAILURE |
| 301 |
| 302 for desc in getText(get_text_result, results_tracker, test_name): |
| 303 print '@@@STEP_TEXT@%s@@@' % desc |
| 304 |
| 305 |
| 209 def main_mac(options, args): | 306 def main_mac(options, args): |
| 210 if len(args) < 1: | 307 if len(args) < 1: |
| 211 raise chromium_utils.MissingArgument('Usage: %s' % USAGE) | 308 raise chromium_utils.MissingArgument('Usage: %s' % USAGE) |
| 212 | 309 |
| 213 test_exe = args[0] | 310 test_exe = args[0] |
| 214 build_dir = os.path.normpath(os.path.abspath(options.build_dir)) | 311 build_dir = os.path.normpath(os.path.abspath(options.build_dir)) |
| 215 test_exe_path = os.path.join(build_dir, options.target, test_exe) | 312 test_exe_path = os.path.join(build_dir, options.target, test_exe) |
| 216 if not os.path.exists(test_exe_path): | 313 if not os.path.exists(test_exe_path): |
| 217 pre = 'Unable to find %s\n' % test_exe_path | 314 pre = 'Unable to find %s\n' % test_exe_path |
| 218 | 315 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 241 command = _BuildParallelCommand(build_dir, test_exe_path, options) | 338 command = _BuildParallelCommand(build_dir, test_exe_path, options) |
| 242 elif options.run_shell_script: | 339 elif options.run_shell_script: |
| 243 command = ['bash', test_exe_path] | 340 command = ['bash', test_exe_path] |
| 244 elif options.run_python_script: | 341 elif options.run_python_script: |
| 245 command = [sys.executable, test_exe] | 342 command = [sys.executable, test_exe] |
| 246 else: | 343 else: |
| 247 command = [test_exe_path] | 344 command = [test_exe_path] |
| 248 command.extend(args[1:]) | 345 command.extend(args[1:]) |
| 249 | 346 |
| 250 results_tracker = None | 347 results_tracker = None |
| 348 if options.generate_json_file or options.annotate: |
| 349 results_tracker = gtest_utils.GTestLogParser() |
| 350 |
| 251 if options.generate_json_file: | 351 if options.generate_json_file: |
| 252 results_tracker = gtest_slave_utils.GTestUnexpectedDeathTracker() | |
| 253 | |
| 254 if os.path.exists(options.test_output_xml): | 352 if os.path.exists(options.test_output_xml): |
| 255 # remove the old XML output file. | 353 # remove the old XML output file. |
| 256 os.remove(options.test_output_xml) | 354 os.remove(options.test_output_xml) |
| 257 | 355 |
| 258 try: | 356 try: |
| 259 http_server = None | 357 http_server = None |
| 260 if options.document_root: | 358 if options.document_root: |
| 261 http_server = start_http_server('mac', build_dir=build_dir, | 359 http_server = start_http_server('mac', build_dir=build_dir, |
| 262 test_exe_path=test_exe_path, | 360 test_exe_path=test_exe_path, |
| 263 document_root=options.document_root) | 361 document_root=options.document_root) |
| 264 if options.factory_properties.get('asan', False): | 362 if options.factory_properties.get('asan', False): |
| 265 symbolize = os.path.abspath(os.path.join('src', 'tools', 'valgrind', | 363 symbolize = os.path.abspath(os.path.join('src', 'tools', 'valgrind', |
| 266 'asan', 'asan_symbolize.py')) | 364 'asan', 'asan_symbolize.py')) |
| 267 pipes = [[sys.executable, symbolize], ['c++filt']] | 365 pipes = [[sys.executable, symbolize], ['c++filt']] |
| 268 result = _RunGTestCommand(command, pipes=pipes) | 366 result = _RunGTestCommand(command, pipes=pipes) |
| 269 else: | 367 else: |
| 270 result = _RunGTestCommand(command, results_tracker) | 368 result = _RunGTestCommand(command, results_tracker) |
| 271 finally: | 369 finally: |
| 272 if http_server: | 370 if http_server: |
| 273 http_server.StopServer() | 371 http_server.StopServer() |
| 274 | 372 |
| 275 if options.generate_json_file: | 373 if options.generate_json_file: |
| 276 _GenerateJSONForTestResults(options, results_tracker) | 374 _GenerateJSONForTestResults(options, results_tracker) |
| 277 | 375 |
| 376 if options.annotate: |
| 377 annotate(options.test_type, result, results_tracker) |
| 378 |
| 278 return result | 379 return result |
| 279 | 380 |
| 381 |
| 280 def main_linux(options, args): | 382 def main_linux(options, args): |
| 281 if len(args) < 1: | 383 if len(args) < 1: |
| 282 raise chromium_utils.MissingArgument('Usage: %s' % USAGE) | 384 raise chromium_utils.MissingArgument('Usage: %s' % USAGE) |
| 283 | 385 |
| 284 build_dir = os.path.normpath(os.path.abspath(options.build_dir)) | 386 build_dir = os.path.normpath(os.path.abspath(options.build_dir)) |
| 285 slave_name = slave_utils.SlaveBuildName(build_dir) | 387 slave_name = slave_utils.SlaveBuildName(build_dir) |
| 286 # If this is a sub-project build (i.e. there's a 'sconsbuild' in build_dir), | 388 # If this is a sub-project build (i.e. there's a 'sconsbuild' in build_dir), |
| 287 # look for the test binaries there, otherwise look for the top-level build | 389 # look for the test binaries there, otherwise look for the top-level build |
| 288 # output. | 390 # output. |
| 289 # This assumes we never pass a build_dir which might contain build output that | 391 # This assumes we never pass a build_dir which might contain build output that |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 command = _BuildParallelCommand(build_dir, test_exe_path, options) | 455 command = _BuildParallelCommand(build_dir, test_exe_path, options) |
| 354 elif options.run_shell_script: | 456 elif options.run_shell_script: |
| 355 command = ['bash', test_exe_path] | 457 command = ['bash', test_exe_path] |
| 356 elif options.run_python_script: | 458 elif options.run_python_script: |
| 357 command = [sys.executable, test_exe] | 459 command = [sys.executable, test_exe] |
| 358 else: | 460 else: |
| 359 command = [test_exe_path] | 461 command = [test_exe_path] |
| 360 command.extend(args[1:]) | 462 command.extend(args[1:]) |
| 361 | 463 |
| 362 results_tracker = None | 464 results_tracker = None |
| 465 if options.generate_json_file or options.annotate: |
| 466 results_tracker = gtest_utils.GTestLogParser() |
| 467 |
| 363 if options.generate_json_file: | 468 if options.generate_json_file: |
| 364 results_tracker = gtest_slave_utils.GTestUnexpectedDeathTracker() | |
| 365 | |
| 366 if os.path.exists(options.test_output_xml): | 469 if os.path.exists(options.test_output_xml): |
| 367 # remove the old XML output file. | 470 # remove the old XML output file. |
| 368 os.remove(options.test_output_xml) | 471 os.remove(options.test_output_xml) |
| 369 | 472 |
| 370 try: | 473 try: |
| 371 http_server = None | 474 http_server = None |
| 372 if options.document_root: | 475 if options.document_root: |
| 373 http_server = start_http_server('linux', build_dir=build_dir, | 476 http_server = start_http_server('linux', build_dir=build_dir, |
| 374 test_exe_path=test_exe_path, | 477 test_exe_path=test_exe_path, |
| 375 document_root=options.document_root) | 478 document_root=options.document_root) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 387 result = _RunGTestCommand(command, results_tracker) | 490 result = _RunGTestCommand(command, results_tracker) |
| 388 finally: | 491 finally: |
| 389 if http_server: | 492 if http_server: |
| 390 http_server.StopServer() | 493 http_server.StopServer() |
| 391 if options.xvfb: | 494 if options.xvfb: |
| 392 xvfb.StopVirtualX(slave_name) | 495 xvfb.StopVirtualX(slave_name) |
| 393 | 496 |
| 394 if options.generate_json_file: | 497 if options.generate_json_file: |
| 395 _GenerateJSONForTestResults(options, results_tracker) | 498 _GenerateJSONForTestResults(options, results_tracker) |
| 396 | 499 |
| 500 if options.annotate: |
| 501 annotate(options.test_type, result, results_tracker) |
| 502 |
| 397 return result | 503 return result |
| 398 | 504 |
| 505 |
| 399 def main_win(options, args): | 506 def main_win(options, args): |
| 400 """Using the target build configuration, run the executable given in the | 507 """Using the target build configuration, run the executable given in the |
| 401 first non-option argument, passing any following arguments to that | 508 first non-option argument, passing any following arguments to that |
| 402 executable. | 509 executable. |
| 403 """ | 510 """ |
| 404 if len(args) < 1: | 511 if len(args) < 1: |
| 405 raise chromium_utils.MissingArgument('Usage: %s' % USAGE) | 512 raise chromium_utils.MissingArgument('Usage: %s' % USAGE) |
| 406 | 513 |
| 407 test_exe = args[0] | 514 test_exe = args[0] |
| 408 build_dir = os.path.abspath(options.build_dir) | 515 build_dir = os.path.abspath(options.build_dir) |
| (...skipping 14 matching lines...) Expand all Loading... |
| 423 command = [sys.executable, test_exe] | 530 command = [sys.executable, test_exe] |
| 424 else: | 531 else: |
| 425 command = [test_exe_path] | 532 command = [test_exe_path] |
| 426 command.extend(args[1:]) | 533 command.extend(args[1:]) |
| 427 | 534 |
| 428 # Nuke anything that appears to be stale chrome items in the temporary | 535 # Nuke anything that appears to be stale chrome items in the temporary |
| 429 # directory from previous test runs (i.e.- from crashes or unittest leaks). | 536 # directory from previous test runs (i.e.- from crashes or unittest leaks). |
| 430 slave_utils.RemoveChromeTemporaryFiles() | 537 slave_utils.RemoveChromeTemporaryFiles() |
| 431 | 538 |
| 432 results_tracker = None | 539 results_tracker = None |
| 540 if options.generate_json_file or options.annotate: |
| 541 results_tracker = gtest_utils.GTestLogParser() |
| 542 |
| 433 if options.generate_json_file: | 543 if options.generate_json_file: |
| 434 results_tracker = gtest_slave_utils.GTestUnexpectedDeathTracker() | |
| 435 | |
| 436 if os.path.exists(options.test_output_xml): | 544 if os.path.exists(options.test_output_xml): |
| 437 # remove the old XML output file. | 545 # remove the old XML output file. |
| 438 os.remove(options.test_output_xml) | 546 os.remove(options.test_output_xml) |
| 439 | 547 |
| 440 try: | 548 try: |
| 441 http_server = None | 549 http_server = None |
| 442 if options.document_root: | 550 if options.document_root: |
| 443 http_server = start_http_server('win', build_dir=build_dir, | 551 http_server = start_http_server('win', build_dir=build_dir, |
| 444 test_exe_path=test_exe_path, | 552 test_exe_path=test_exe_path, |
| 445 document_root=options.document_root) | 553 document_root=options.document_root) |
| 446 result = _RunGTestCommand(command, results_tracker) | 554 result = _RunGTestCommand(command, results_tracker) |
| 447 finally: | 555 finally: |
| 448 if http_server: | 556 if http_server: |
| 449 http_server.StopServer() | 557 http_server.StopServer() |
| 450 | 558 |
| 451 if options.enable_pageheap: | 559 if options.enable_pageheap: |
| 452 slave_utils.SetPageHeap(build_dir, 'chrome.exe', False) | 560 slave_utils.SetPageHeap(build_dir, 'chrome.exe', False) |
| 453 | 561 |
| 454 if options.generate_json_file: | 562 if options.generate_json_file: |
| 455 _GenerateJSONForTestResults(options, results_tracker) | 563 _GenerateJSONForTestResults(options, results_tracker) |
| 456 | 564 |
| 565 if options.annotate: |
| 566 annotate(options.test_type, result, results_tracker) |
| 567 |
| 457 return result | 568 return result |
| 458 | 569 |
| 459 | 570 |
| 460 def main(): | 571 def main(): |
| 461 import platform | 572 import platform |
| 462 | 573 |
| 463 xvfb_path = os.path.join(os.path.dirname(sys.argv[0]), '..', '..', | 574 xvfb_path = os.path.join(os.path.dirname(sys.argv[0]), '..', '..', |
| 464 'third_party', 'xvfb', platform.architecture()[0]) | 575 'third_party', 'xvfb', platform.architecture()[0]) |
| 465 | 576 |
| 466 # Initialize logging. | 577 # Initialize logging. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 544 help="The name of the builder running this script.") | 655 help="The name of the builder running this script.") |
| 545 option_parser.add_option("", "--build-number", default=None, | 656 option_parser.add_option("", "--build-number", default=None, |
| 546 help=("The build number of the builder running" | 657 help=("The build number of the builder running" |
| 547 "this script.")) | 658 "this script.")) |
| 548 option_parser.add_option("", "--test-type", default='', | 659 option_parser.add_option("", "--test-type", default='', |
| 549 help="The test name that identifies the test, " | 660 help="The test name that identifies the test, " |
| 550 "e.g. 'unit-tests'") | 661 "e.g. 'unit-tests'") |
| 551 option_parser.add_option("", "--test-results-server", default='', | 662 option_parser.add_option("", "--test-results-server", default='', |
| 552 help="The test results server to upload the " | 663 help="The test results server to upload the " |
| 553 "results.") | 664 "results.") |
| 665 option_parser.add_option('', '--annotate', action='store_true', |
| 666 dest = 'annotate', default=False, |
| 667 help='Annotate output when run as a buildstep.') |
| 554 chromium_utils.AddPropertiesOptions(option_parser) | 668 chromium_utils.AddPropertiesOptions(option_parser) |
| 555 options, args = option_parser.parse_args() | 669 options, args = option_parser.parse_args() |
| 556 | 670 |
| 557 if options.run_shell_script and options.run_python_script: | 671 if options.run_shell_script and options.run_python_script: |
| 558 sys.stderr.write('Use either --run-shell-script OR --run-python-script, ' | 672 sys.stderr.write('Use either --run-shell-script OR --run-python-script, ' |
| 559 'not both.') | 673 'not both.') |
| 560 return 1 | 674 return 1 |
| 561 | 675 |
| 562 # Print out builder name for log_parser | 676 # Print out builder name for log_parser |
| 563 print '[Running on builder: "%s"]' % options.builder_name | 677 print '[Running on builder: "%s"]' % options.builder_name |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 598 '%d new files were left in %s: Fix the tests to clean up themselves.' | 712 '%d new files were left in %s: Fix the tests to clean up themselves.' |
| 599 ) % ((new_temp_files - temp_files), tempfile.gettempdir()) | 713 ) % ((new_temp_files - temp_files), tempfile.gettempdir()) |
| 600 # TODO(maruel): Make it an error soon. Not yet since I want to iron out all | 714 # TODO(maruel): Make it an error soon. Not yet since I want to iron out all |
| 601 # the remaining cases before. | 715 # the remaining cases before. |
| 602 #result = 1 | 716 #result = 1 |
| 603 return result | 717 return result |
| 604 | 718 |
| 605 | 719 |
| 606 if '__main__' == __name__: | 720 if '__main__' == __name__: |
| 607 sys.exit(main()) | 721 sys.exit(main()) |
| OLD | NEW |