Chromium Code Reviews| 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 used to run a Chrome test executable and process the output. | 6 """A tool used to run a Chrome test executable and process the output. |
| 7 | 7 |
| 8 This script is used by the buildbot slaves. It must be run from the outer | 8 This script is used by the buildbot slaves. It must be run from the outer |
| 9 build directory, e.g. chrome-release/build/. | 9 build directory, e.g. chrome-release/build/. |
| 10 | 10 |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 except OSError as e: | 166 except OSError as e: |
| 167 print ' error killing dbus-daemon with PID %s: %s' % (dbus_pid, e) | 167 print ' error killing dbus-daemon with PID %s: %s' % (dbus_pid, e) |
| 168 # Try to clean up any stray DBUS_SESSION_BUS_ADDRESS environment | 168 # Try to clean up any stray DBUS_SESSION_BUS_ADDRESS environment |
| 169 # variable too. Some of the bots seem to re-invoke runtest.py in a | 169 # variable too. Some of the bots seem to re-invoke runtest.py in a |
| 170 # way that this variable sticks around from run to run. | 170 # way that this variable sticks around from run to run. |
| 171 if 'DBUS_SESSION_BUS_ADDRESS' in os.environ: | 171 if 'DBUS_SESSION_BUS_ADDRESS' in os.environ: |
| 172 del os.environ['DBUS_SESSION_BUS_ADDRESS'] | 172 del os.environ['DBUS_SESSION_BUS_ADDRESS'] |
| 173 print ' cleared DBUS_SESSION_BUS_ADDRESS environment variable' | 173 print ' cleared DBUS_SESSION_BUS_ADDRESS environment variable' |
| 174 | 174 |
| 175 | 175 |
| 176 def _RunGTestCommand(command, extra_env, log_processor=None, pipes=None): | 176 def _RunGTestCommand( |
| 177 options, command, extra_env, log_processor=None, pipes=None): | |
| 177 """Runs a test, printing and possibly processing the output. | 178 """Runs a test, printing and possibly processing the output. |
| 178 | 179 |
| 179 Args: | 180 Args: |
| 181 options: Options passed for this invocation of runtest.py. | |
| 180 command: A list of strings in a command (the command and its arguments). | 182 command: A list of strings in a command (the command and its arguments). |
| 181 extra_env: A dictionary of extra environment variables to set. | 183 extra_env: A dictionary of extra environment variables to set. |
| 182 log_processor: A log processor instance which has the ProcessLine method. | 184 log_processor: A log processor instance which has the ProcessLine method. |
| 183 pipes: A list of command string lists which the output will be piped to. | 185 pipes: A list of command string lists which the output will be piped to. |
| 184 | 186 |
| 185 Returns: | 187 Returns: |
| 186 The process return code. | 188 The process return code. |
| 187 """ | 189 """ |
| 188 env = os.environ.copy() | 190 env = os.environ.copy() |
| 189 if extra_env: | 191 if extra_env: |
| 190 print 'Additional test environment:' | 192 print 'Additional test environment:' |
| 191 for k, v in sorted(extra_env.items()): | 193 for k, v in sorted(extra_env.items()): |
| 192 print ' %s=%s' % (k, v) | 194 print ' %s=%s' % (k, v) |
| 193 env.update(extra_env or {}) | 195 env.update(extra_env or {}) |
| 194 | 196 |
| 195 # Trigger bot mode (test retries, redirection of stdio, possibly faster, | 197 # Trigger bot mode (test retries, redirection of stdio, possibly faster, |
| 196 # etc.) - using an environment variable instead of command-line flags because | 198 # etc.) - using an environment variable instead of command-line flags because |
| 197 # some internal waterfalls run this (_RunGTestCommand) for totally non-gtest | 199 # some internal waterfalls run this (_RunGTestCommand) for totally non-gtest |
| 198 # code. | 200 # code. |
| 199 # TODO(phajdan.jr): Clean this up when internal waterfalls are fixed. | 201 # TODO(phajdan.jr): Clean this up when internal waterfalls are fixed. |
| 200 env.update({'CHROMIUM_TEST_LAUNCHER_BOT_MODE': '1'}) | 202 env.update({'CHROMIUM_TEST_LAUNCHER_BOT_MODE': '1'}) |
| 201 | 203 |
| 204 log_processors = {} | |
| 202 if log_processor: | 205 if log_processor: |
| 203 return chromium_utils.RunCommand( | 206 log_processors[log_processor.__class__.__name__] = log_processor |
| 204 command, pipes=pipes, parser_func=log_processor.ProcessLine, env=env) | 207 |
| 205 else: | 208 if not 'GTestLogParser' in log_processors and options.gtest_output_file: |
| 206 return chromium_utils.RunCommand(command, pipes=pipes, env=env) | 209 log_processors['GTestLogParser'] = gtest_utils.GTestLogParser() |
| 210 | |
| 211 def _ProcessLine(line): | |
| 212 for current_log_processor in log_processors.values(): | |
| 213 current_log_processor.ProcessLine(line) | |
| 214 | |
| 215 result = chromium_utils.RunCommand( | |
| 216 command, pipes=pipes, parser_func=_ProcessLine, env=env) | |
| 217 | |
| 218 if options.gtest_output_file: | |
|
Paweł Hajdan Jr.
2015/01/30 21:20:30
Let's call the option log_processor_output_file.
shatch
2015/02/09 21:23:59
Done.
| |
| 219 _WriteLogProcessorResultsToOutput( | |
| 220 log_processors['GTestLogParser'], options.gtest_output_file) | |
| 221 | |
| 222 return result | |
| 207 | 223 |
| 208 | 224 |
| 209 def _GetMaster(): | 225 def _GetMaster(): |
| 210 """Return the master name for the current host.""" | 226 """Return the master name for the current host.""" |
| 211 return chromium_utils.GetActiveMaster() | 227 return chromium_utils.GetActiveMaster() |
| 212 | 228 |
| 213 | 229 |
| 214 def _GetMasterString(master): | 230 def _GetMasterString(master): |
| 215 """Returns a message describing what the master is.""" | 231 """Returns a message describing what the master is.""" |
| 216 return '[Running for master: "%s"]' % master | 232 return '[Running for master: "%s"]' % master |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 716 chart_json = log_processor.ChartJson() | 732 chart_json = log_processor.ChartJson() |
| 717 if chart_json: | 733 if chart_json: |
| 718 return results_dashboard.MakeDashboardJsonV1( | 734 return results_dashboard.MakeDashboardJsonV1( |
| 719 chart_json, | 735 chart_json, |
| 720 args['revisions'], args['system'], args['mastername'], | 736 args['revisions'], args['system'], args['mastername'], |
| 721 args['buildername'], args['buildnumber'], | 737 args['buildername'], args['buildnumber'], |
| 722 args['supplemental_columns'], log_processor.IsReferenceBuild()) | 738 args['supplemental_columns'], log_processor.IsReferenceBuild()) |
| 723 return None | 739 return None |
| 724 | 740 |
| 725 | 741 |
| 742 def _WriteLogProcessorResultsToOutput(log_processor, log_output_file): | |
| 743 """Writes the log processor's results to a file. | |
| 744 | |
| 745 Args: | |
| 746 chartjson_file: Path to the file to write the results. | |
| 747 log_processor: An instance of a log processor class, which has been used to | |
| 748 process the test output, so it contains the test results. | |
| 749 """ | |
| 750 with open(log_output_file, 'w') as f: | |
| 751 results = { | |
| 752 'passed': log_processor.PassedTests(), | |
| 753 'failed': log_processor.FailedTests(), | |
| 754 'flakes': log_processor.FlakyTests(), | |
| 755 } | |
| 756 json.dump(results, f) | |
| 757 | |
| 758 | |
| 726 def _WriteChartJsonToOutput(chartjson_file, log_processor, args): | 759 def _WriteChartJsonToOutput(chartjson_file, log_processor, args): |
| 727 """Writes the dashboard chartjson to a file for display in the waterfall. | 760 """Writes the dashboard chartjson to a file for display in the waterfall. |
| 728 | 761 |
| 729 Args: | 762 Args: |
| 730 chartjson_file: Path to the file to write the chartjson. | 763 chartjson_file: Path to the file to write the chartjson. |
| 731 log_processor: An instance of a log processor class, which has been used to | 764 log_processor: An instance of a log processor class, which has been used to |
| 732 process the test output, so it contains the test results. | 765 process the test output, so it contains the test results. |
| 733 args: Dict of additional args to send to results_dashboard. | 766 args: Dict of additional args to send to results_dashboard. |
| 734 """ | 767 """ |
| 735 assert log_processor.IsChartJson() | 768 assert log_processor.IsChartJson() |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1160 options.test_launcher_summary_output) | 1193 options.test_launcher_summary_output) |
| 1161 command.append('--test-launcher-summary-output=%s' % json_file_name) | 1194 command.append('--test-launcher-summary-output=%s' % json_file_name) |
| 1162 | 1195 |
| 1163 pipes = [] | 1196 pipes = [] |
| 1164 if options.enable_asan: | 1197 if options.enable_asan: |
| 1165 symbolize_command = _GetSanitizerSymbolizeCommand() | 1198 symbolize_command = _GetSanitizerSymbolizeCommand() |
| 1166 pipes = [symbolize_command, ['c++filt']] | 1199 pipes = [symbolize_command, ['c++filt']] |
| 1167 | 1200 |
| 1168 command = _GenerateRunIsolatedCommand(build_dir, test_exe_path, options, | 1201 command = _GenerateRunIsolatedCommand(build_dir, test_exe_path, options, |
| 1169 command) | 1202 command) |
| 1170 result = _RunGTestCommand(command, extra_env, pipes=pipes, | 1203 result = _RunGTestCommand(options, command, extra_env, pipes=pipes, |
| 1171 log_processor=log_processor) | 1204 log_processor=log_processor) |
| 1172 finally: | 1205 finally: |
| 1173 if http_server: | 1206 if http_server: |
| 1174 http_server.StopServer() | 1207 http_server.StopServer() |
| 1175 if _UsingGtestJson(options): | 1208 if _UsingGtestJson(options): |
| 1176 _UploadGtestJsonSummary(json_file_name, | 1209 _UploadGtestJsonSummary(json_file_name, |
| 1177 options.build_properties, | 1210 options.build_properties, |
| 1178 test_exe) | 1211 test_exe) |
| 1179 log_processor.ProcessJSONFile(options.build_dir) | 1212 log_processor.ProcessJSONFile(options.build_dir) |
| 1180 | 1213 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1267 | 1300 |
| 1268 # Nuke anything that appears to be stale chrome items in the temporary | 1301 # Nuke anything that appears to be stale chrome items in the temporary |
| 1269 # directory from previous test runs (i.e.- from crashes or unittest leaks). | 1302 # directory from previous test runs (i.e.- from crashes or unittest leaks). |
| 1270 slave_utils.RemoveChromeTemporaryFiles() | 1303 slave_utils.RemoveChromeTemporaryFiles() |
| 1271 | 1304 |
| 1272 dirs_to_cleanup = [tmpdir] | 1305 dirs_to_cleanup = [tmpdir] |
| 1273 crash_files_before = set([]) | 1306 crash_files_before = set([]) |
| 1274 crash_files_after = set([]) | 1307 crash_files_after = set([]) |
| 1275 crash_files_before = set(crash_utils.list_crash_logs()) | 1308 crash_files_before = set(crash_utils.list_crash_logs()) |
| 1276 | 1309 |
| 1277 result = _RunGTestCommand(command, extra_env, log_processor) | 1310 result = _RunGTestCommand(options, command, extra_env, log_processor) |
| 1278 | 1311 |
| 1279 # Because test apps kill themselves, iossim sometimes returns non-zero | 1312 # Because test apps kill themselves, iossim sometimes returns non-zero |
| 1280 # status even though all tests have passed. Check the log_processor to | 1313 # status even though all tests have passed. Check the log_processor to |
| 1281 # see if the test run was successful. | 1314 # see if the test run was successful. |
| 1282 if log_processor.CompletedWithoutFailure(): | 1315 if log_processor.CompletedWithoutFailure(): |
| 1283 result = 0 | 1316 result = 0 |
| 1284 else: | 1317 else: |
| 1285 result = 1 | 1318 result = 1 |
| 1286 | 1319 |
| 1287 if result != 0: | 1320 if result != 0: |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1433 | 1466 |
| 1434 pipes = [] | 1467 pipes = [] |
| 1435 # See the comment in main() regarding offline symbolization. | 1468 # See the comment in main() regarding offline symbolization. |
| 1436 if options.use_symbolization_script: | 1469 if options.use_symbolization_script: |
| 1437 symbolize_command = _GetSanitizerSymbolizeCommand( | 1470 symbolize_command = _GetSanitizerSymbolizeCommand( |
| 1438 strip_path_prefix=options.strip_path_prefix) | 1471 strip_path_prefix=options.strip_path_prefix) |
| 1439 pipes = [symbolize_command] | 1472 pipes = [symbolize_command] |
| 1440 | 1473 |
| 1441 command = _GenerateRunIsolatedCommand(build_dir, test_exe_path, options, | 1474 command = _GenerateRunIsolatedCommand(build_dir, test_exe_path, options, |
| 1442 command) | 1475 command) |
| 1443 result = _RunGTestCommand(command, extra_env, pipes=pipes, | 1476 result = _RunGTestCommand(options, command, extra_env, pipes=pipes, |
| 1444 log_processor=log_processor) | 1477 log_processor=log_processor) |
| 1445 finally: | 1478 finally: |
| 1446 if http_server: | 1479 if http_server: |
| 1447 http_server.StopServer() | 1480 http_server.StopServer() |
| 1448 if start_xvfb: | 1481 if start_xvfb: |
| 1449 xvfb.StopVirtualX(slave_name) | 1482 xvfb.StopVirtualX(slave_name) |
| 1450 if _UsingGtestJson(options): | 1483 if _UsingGtestJson(options): |
| 1451 if options.use_symbolization_script: | 1484 if options.use_symbolization_script: |
| 1452 _SymbolizeSnippetsInJSON(options, json_file_name) | 1485 _SymbolizeSnippetsInJSON(options, json_file_name) |
| 1453 if json_file_name: | 1486 if json_file_name: |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1560 test_exe_path=test_exe_path, | 1593 test_exe_path=test_exe_path, |
| 1561 document_root=options.document_root) | 1594 document_root=options.document_root) |
| 1562 | 1595 |
| 1563 if _UsingGtestJson(options): | 1596 if _UsingGtestJson(options): |
| 1564 json_file_name = log_processor.PrepareJSONFile( | 1597 json_file_name = log_processor.PrepareJSONFile( |
| 1565 options.test_launcher_summary_output) | 1598 options.test_launcher_summary_output) |
| 1566 command.append('--test-launcher-summary-output=%s' % json_file_name) | 1599 command.append('--test-launcher-summary-output=%s' % json_file_name) |
| 1567 | 1600 |
| 1568 command = _GenerateRunIsolatedCommand(build_dir, test_exe_path, options, | 1601 command = _GenerateRunIsolatedCommand(build_dir, test_exe_path, options, |
| 1569 command) | 1602 command) |
| 1570 result = _RunGTestCommand(command, extra_env, log_processor) | 1603 result = _RunGTestCommand(options, command, extra_env, log_processor) |
| 1571 finally: | 1604 finally: |
| 1572 if http_server: | 1605 if http_server: |
| 1573 http_server.StopServer() | 1606 http_server.StopServer() |
| 1574 if _UsingGtestJson(options): | 1607 if _UsingGtestJson(options): |
| 1575 _UploadGtestJsonSummary(json_file_name, | 1608 _UploadGtestJsonSummary(json_file_name, |
| 1576 options.build_properties, | 1609 options.build_properties, |
| 1577 test_exe) | 1610 test_exe) |
| 1578 log_processor.ProcessJSONFile(options.build_dir) | 1611 log_processor.ProcessJSONFile(options.build_dir) |
| 1579 | 1612 |
| 1580 if options.enable_pageheap: | 1613 if options.enable_pageheap: |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1639 run_test_target_option = '--release' | 1672 run_test_target_option = '--release' |
| 1640 if options.target == 'Debug': | 1673 if options.target == 'Debug': |
| 1641 run_test_target_option = '--debug' | 1674 run_test_target_option = '--debug' |
| 1642 command = ['src/build/android/test_runner.py', 'gtest', | 1675 command = ['src/build/android/test_runner.py', 'gtest', |
| 1643 run_test_target_option, '-s', test_suite] | 1676 run_test_target_option, '-s', test_suite] |
| 1644 | 1677 |
| 1645 if options.flakiness_dashboard_server: | 1678 if options.flakiness_dashboard_server: |
| 1646 command += ['--flakiness-dashboard-server=%s' % | 1679 command += ['--flakiness-dashboard-server=%s' % |
| 1647 options.flakiness_dashboard_server] | 1680 options.flakiness_dashboard_server] |
| 1648 | 1681 |
| 1649 result = _RunGTestCommand(command, extra_env, log_processor=log_processor) | 1682 result = _RunGTestCommand( |
| 1683 options, command, extra_env, log_processor=log_processor) | |
| 1650 | 1684 |
| 1651 if options.generate_json_file: | 1685 if options.generate_json_file: |
| 1652 if not _GenerateJSONForTestResults(options, log_processor): | 1686 if not _GenerateJSONForTestResults(options, log_processor): |
| 1653 return 1 | 1687 return 1 |
| 1654 | 1688 |
| 1655 if options.annotate: | 1689 if options.annotate: |
| 1656 annotation_utils.annotate( | 1690 annotation_utils.annotate( |
| 1657 options.test_type, result, log_processor, | 1691 options.test_type, result, log_processor, |
| 1658 options.factory_properties.get('full_test_name'), | 1692 options.factory_properties.get('full_test_name'), |
| 1659 perf_dashboard_id=options.perf_dashboard_id) | 1693 perf_dashboard_id=options.perf_dashboard_id) |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1784 help='Start virtual X server on Linux.') | 1818 help='Start virtual X server on Linux.') |
| 1785 option_parser.add_option('--no-xvfb', action='store_false', dest='xvfb', | 1819 option_parser.add_option('--no-xvfb', action='store_false', dest='xvfb', |
| 1786 help='Do not start virtual X server on Linux.') | 1820 help='Do not start virtual X server on Linux.') |
| 1787 option_parser.add_option('--sharding-args', dest='sharding_args', | 1821 option_parser.add_option('--sharding-args', dest='sharding_args', |
| 1788 default='', | 1822 default='', |
| 1789 help='Options to pass to sharding_supervisor.') | 1823 help='Options to pass to sharding_supervisor.') |
| 1790 option_parser.add_option('-o', '--results-directory', default='', | 1824 option_parser.add_option('-o', '--results-directory', default='', |
| 1791 help='output results directory for JSON file.') | 1825 help='output results directory for JSON file.') |
| 1792 option_parser.add_option('--chartjson-file', default='', | 1826 option_parser.add_option('--chartjson-file', default='', |
| 1793 help='File to dump chartjson results.') | 1827 help='File to dump chartjson results.') |
| 1828 option_parser.add_option('--gtest-output-file', default='', | |
| 1829 help='File to dump gtest log processor results.') | |
| 1794 option_parser.add_option('--builder-name', default=None, | 1830 option_parser.add_option('--builder-name', default=None, |
| 1795 help='The name of the builder running this script.') | 1831 help='The name of the builder running this script.') |
| 1796 option_parser.add_option('--slave-name', default=None, | 1832 option_parser.add_option('--slave-name', default=None, |
| 1797 help='The name of the slave running this script.') | 1833 help='The name of the slave running this script.') |
| 1798 option_parser.add_option('--master-class-name', default=None, | 1834 option_parser.add_option('--master-class-name', default=None, |
| 1799 help='The class name of the buildbot master running ' | 1835 help='The class name of the buildbot master running ' |
| 1800 'this script: examples include "Chromium", ' | 1836 'this script: examples include "Chromium", ' |
| 1801 '"ChromiumWebkit", and "ChromiumGPU". The ' | 1837 '"ChromiumWebkit", and "ChromiumGPU". The ' |
| 1802 'flakiness dashboard uses this value to ' | 1838 'flakiness dashboard uses this value to ' |
| 1803 'categorize results. See buildershandler.py ' | 1839 'categorize results. See buildershandler.py ' |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2120 finally: | 2156 finally: |
| 2121 if did_launch_dbus: | 2157 if did_launch_dbus: |
| 2122 # It looks like the command line argument --exit-with-session | 2158 # It looks like the command line argument --exit-with-session |
| 2123 # isn't working to clean up the spawned dbus-daemon. Kill it | 2159 # isn't working to clean up the spawned dbus-daemon. Kill it |
| 2124 # manually. | 2160 # manually. |
| 2125 _ShutdownDBus() | 2161 _ShutdownDBus() |
| 2126 | 2162 |
| 2127 | 2163 |
| 2128 if '__main__' == __name__: | 2164 if '__main__' == __name__: |
| 2129 sys.exit(main()) | 2165 sys.exit(main()) |
| OLD | NEW |