OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Runs all the native unit tests. | 7 """Runs all the native unit tests. |
8 | 8 |
9 1. Copy over test binary to /data/local on device. | 9 1. Copy over test binary to /data/local on device. |
10 2. Resources: chrome/unit_tests requires resources (chrome.pak and en-US.pak) | 10 2. Resources: chrome/unit_tests requires resources (chrome.pak and en-US.pak) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 import optparse | 55 import optparse |
56 import os | 56 import os |
57 import signal | 57 import signal |
58 import subprocess | 58 import subprocess |
59 import sys | 59 import sys |
60 import time | 60 import time |
61 | 61 |
62 from pylib import android_commands | 62 from pylib import android_commands |
63 from pylib.base_test_sharder import BaseTestSharder | 63 from pylib.base_test_sharder import BaseTestSharder |
64 from pylib import buildbot_report | 64 from pylib import buildbot_report |
| 65 from pylib import cmd_helper |
65 from pylib import constants | 66 from pylib import constants |
66 from pylib import debug_info | 67 from pylib import debug_info |
67 import emulator | 68 import emulator |
68 from pylib import ports | 69 from pylib import ports |
69 from pylib import run_tests_helper | 70 from pylib import run_tests_helper |
70 from pylib import test_options_parser | 71 from pylib import test_options_parser |
71 from pylib.single_test_runner import SingleTestRunner | 72 from pylib.single_test_runner import SingleTestRunner |
72 from pylib.test_result import BaseTestResult, TestResults | 73 from pylib.test_result import BaseTestResult, TestResults |
73 | 74 |
74 | 75 |
75 _TEST_SUITES = ['base_unittests', | 76 _TEST_SUITES = ['base_unittests', |
76 'cc_unittests', | 77 'cc_unittests', |
77 'content_unittests', | 78 'content_unittests', |
78 'gpu_unittests', | 79 'gpu_unittests', |
79 'ipc_tests', | 80 'ipc_tests', |
80 'media_unittests', | 81 'media_unittests', |
81 'net_unittests', | 82 'net_unittests', |
82 'sql_unittests', | 83 'sql_unittests', |
83 'sync_unit_tests', | 84 'sync_unit_tests', |
84 'ui_unittests', | 85 'ui_unittests', |
85 'unit_tests', | 86 'unit_tests', |
86 'webkit_compositor_bindings_unittests', | 87 'webkit_compositor_bindings_unittests', |
87 ] | 88 ] |
88 | 89 |
89 | 90 |
90 def TestSuiteDir(build_type): | |
91 """Return the base directory of test suites.""" | |
92 return os.path.abspath(os.path.join(constants.CHROME_DIR, 'out', build_type)) | |
93 | |
94 def FullyQualifiedTestSuites(exe, option_test_suite, build_type): | 91 def FullyQualifiedTestSuites(exe, option_test_suite, build_type): |
95 """Return a fully qualified list | 92 """Return a fully qualified list |
96 | 93 |
97 Args: | 94 Args: |
98 exe: if True, use the executable-based test runner. | 95 exe: if True, use the executable-based test runner. |
99 option_test_suite: the test_suite specified as an option. | 96 option_test_suite: the test_suite specified as an option. |
100 build_type: 'Release' or 'Debug'. | 97 build_type: 'Release' or 'Debug'. |
101 """ | 98 """ |
102 test_suite_dir = TestSuiteDir(build_type) | 99 test_suite_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) |
103 if option_test_suite: | 100 if option_test_suite: |
104 all_test_suites = [option_test_suite] | 101 all_test_suites = [option_test_suite] |
105 else: | 102 else: |
106 all_test_suites = _TEST_SUITES | 103 all_test_suites = _TEST_SUITES |
107 | 104 |
108 if exe: | 105 if exe: |
109 qualified_test_suites = [os.path.join(test_suite_dir, t) | 106 qualified_test_suites = [os.path.join(test_suite_dir, t) |
110 for t in all_test_suites] | 107 for t in all_test_suites] |
111 else: | 108 else: |
112 # out/(Debug|Release)/$SUITE_apk/$SUITE-debug.apk | 109 # out/(Debug|Release)/$SUITE_apk/$SUITE-debug.apk |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
188 del os.environ['DISPLAY'] | 185 del os.environ['DISPLAY'] |
189 self._pid = 0 | 186 self._pid = 0 |
190 | 187 |
191 | 188 |
192 class TestSharder(BaseTestSharder): | 189 class TestSharder(BaseTestSharder): |
193 """Responsible for sharding the tests on the connected devices.""" | 190 """Responsible for sharding the tests on the connected devices.""" |
194 | 191 |
195 def __init__(self, attached_devices, test_suite, gtest_filter, | 192 def __init__(self, attached_devices, test_suite, gtest_filter, |
196 test_arguments, timeout, rebaseline, performance_test, | 193 test_arguments, timeout, rebaseline, performance_test, |
197 cleanup_test_files, tool, log_dump_name, fast_and_loose, | 194 cleanup_test_files, tool, log_dump_name, fast_and_loose, |
198 build_type): | 195 build_type, in_webkit_checkout): |
199 BaseTestSharder.__init__(self, attached_devices, build_type) | 196 BaseTestSharder.__init__(self, attached_devices, build_type) |
200 self.test_suite = test_suite | 197 self.test_suite = test_suite |
201 self.test_suite_basename = os.path.basename(test_suite) | 198 self.test_suite_basename = os.path.basename(test_suite) |
202 self.gtest_filter = gtest_filter or '' | 199 self.gtest_filter = gtest_filter or '' |
203 self.test_arguments = test_arguments | 200 self.test_arguments = test_arguments |
204 self.timeout = timeout | 201 self.timeout = timeout |
205 self.rebaseline = rebaseline | 202 self.rebaseline = rebaseline |
206 self.performance_test = performance_test | 203 self.performance_test = performance_test |
207 self.cleanup_test_files = cleanup_test_files | 204 self.cleanup_test_files = cleanup_test_files |
208 self.tool = tool | 205 self.tool = tool |
209 self.log_dump_name = log_dump_name | 206 self.log_dump_name = log_dump_name |
210 self.fast_and_loose = fast_and_loose | 207 self.fast_and_loose = fast_and_loose |
211 self.build_type = build_type | 208 self.build_type = build_type |
| 209 self.in_webkit_checkout = in_webkit_checkout |
212 self.tests = [] | 210 self.tests = [] |
213 if not self.gtest_filter: | 211 if not self.gtest_filter: |
214 # No filter has been specified, let's add all tests then. | 212 # No filter has been specified, let's add all tests then. |
215 self.tests, self.attached_devices = self._GetTests() | 213 self.tests, self.attached_devices = self._GetTests() |
216 | 214 |
217 def _GetTests(self): | 215 def _GetTests(self): |
218 """Returns a tuple of (all_tests, available_devices). | 216 """Returns a tuple of (all_tests, available_devices). |
219 | 217 |
220 Tries to obtain the list of available tests. | 218 Tries to obtain the list of available tests. |
221 Raises Exception if all devices failed. | 219 Raises Exception if all devices failed. |
222 """ | 220 """ |
223 available_devices = list(self.attached_devices) | 221 available_devices = list(self.attached_devices) |
224 while available_devices: | 222 while available_devices: |
225 try: | 223 try: |
226 logging.info('Obtaining tests from %s', available_devices[-1]) | 224 logging.info('Obtaining tests from %s', available_devices[-1]) |
227 all_tests = self._GetTestsFromDevice(available_devices[-1]) | 225 all_tests = self._GetTestsFromDevice(available_devices[-1]) |
228 return all_tests, available_devices | 226 return all_tests, available_devices |
229 except Exception as e: | 227 except Exception as e: |
230 logging.info('Failed obtaining tests from %s %s', | 228 logging.info('Failed obtaining tests from %s %s', |
231 available_devices[-1], e) | 229 available_devices[-1], e) |
232 available_devices.pop() | 230 available_devices.pop() |
233 raise Exception('No device available to get the list of tests.') | 231 raise Exception('No device available to get the list of tests.') |
234 | 232 |
235 def _GetTestsFromDevice(self, device): | 233 def _GetTestsFromDevice(self, device): |
236 test = SingleTestRunner(device, self.test_suite, self.gtest_filter, | 234 test = SingleTestRunner(device, self.test_suite, self.gtest_filter, |
237 self.test_arguments, self.timeout, self.rebaseline, | 235 self.test_arguments, self.timeout, self.rebaseline, |
238 self.performance_test, self.cleanup_test_files, | 236 self.performance_test, self.cleanup_test_files, |
239 self.tool, 0, | 237 self.tool, 0, |
240 not not self.log_dump_name, self.fast_and_loose, | 238 not not self.log_dump_name, self.fast_and_loose, |
241 self.build_type) | 239 self.build_type, self.in_webkit_checkout) |
242 # The executable/apk needs to be copied before we can call GetAllTests. | 240 # The executable/apk needs to be copied before we can call GetAllTests. |
243 test.test_package.StripAndCopyExecutable() | 241 test.test_package.StripAndCopyExecutable() |
244 all_tests = test.test_package.GetAllTests() | 242 all_tests = test.test_package.GetAllTests() |
245 if not self.rebaseline: | 243 if not self.rebaseline: |
246 disabled_list = test.GetDisabledTests() | 244 disabled_list = test.GetDisabledTests() |
247 # Only includes tests that do not have any match in the disabled list. | 245 # Only includes tests that do not have any match in the disabled list. |
248 all_tests = filter(lambda t: | 246 all_tests = filter(lambda t: |
249 not any([fnmatch.fnmatch(t, disabled_pattern) | 247 not any([fnmatch.fnmatch(t, disabled_pattern) |
250 for disabled_pattern in disabled_list]), | 248 for disabled_pattern in disabled_list]), |
251 all_tests) | 249 all_tests) |
(...skipping 11 matching lines...) Expand all Loading... |
263 """ | 261 """ |
264 device_num = len(self.attached_devices) | 262 device_num = len(self.attached_devices) |
265 shard_size = (len(self.tests) + device_num - 1) / device_num | 263 shard_size = (len(self.tests) + device_num - 1) / device_num |
266 shard_test_list = self.tests[index * shard_size : (index + 1) * shard_size] | 264 shard_test_list = self.tests[index * shard_size : (index + 1) * shard_size] |
267 test_filter = ':'.join(shard_test_list) + self.gtest_filter | 265 test_filter = ':'.join(shard_test_list) + self.gtest_filter |
268 return SingleTestRunner(device, self.test_suite, | 266 return SingleTestRunner(device, self.test_suite, |
269 test_filter, self.test_arguments, self.timeout, | 267 test_filter, self.test_arguments, self.timeout, |
270 self.rebaseline, self.performance_test, | 268 self.rebaseline, self.performance_test, |
271 self.cleanup_test_files, self.tool, index, | 269 self.cleanup_test_files, self.tool, index, |
272 not not self.log_dump_name, self.fast_and_loose, | 270 not not self.log_dump_name, self.fast_and_loose, |
273 self.build_type) | 271 self.build_type, self.in_webkit_checkout) |
274 | 272 |
275 def OnTestsCompleted(self, test_runners, test_results): | 273 def OnTestsCompleted(self, test_runners, test_results): |
276 """Notifies that we completed the tests.""" | 274 """Notifies that we completed the tests.""" |
277 test_results.LogFull('Unit test', os.path.basename(self.test_suite), | 275 test_results.LogFull('Unit test', os.path.basename(self.test_suite), |
278 self.build_type, self.tests) | 276 self.build_type, self.tests) |
279 test_results.PrintAnnotation() | 277 test_results.PrintAnnotation() |
280 if test_results.failed and self.rebaseline: | 278 if test_results.failed and self.rebaseline: |
281 test_runners[0].UpdateFilter(test_results.failed) | 279 test_runners[0].UpdateFilter(test_results.failed) |
282 if self.log_dump_name: | 280 if self.log_dump_name: |
283 # Zip all debug info outputs into a file named by log_dump_name. | 281 # Zip all debug info outputs into a file named by log_dump_name. |
284 debug_info.GTestDebugInfo.ZipAndCleanResults( | 282 debug_info.GTestDebugInfo.ZipAndCleanResults( |
285 os.path.join(TestSuiteDir(self.build_type), 'debug_info_dumps'), | 283 os.path.join(cmd_helper.OutDirectory.get(), self.build_type, |
| 284 'debug_info_dumps'), |
286 self.log_dump_name) | 285 self.log_dump_name) |
287 | 286 |
288 | 287 |
289 def _RunATestSuite(options): | 288 def _RunATestSuite(options): |
290 """Run a single test suite. | 289 """Run a single test suite. |
291 | 290 |
292 Helper for Dispatch() to allow stop/restart of the emulator across | 291 Helper for Dispatch() to allow stop/restart of the emulator across |
293 test bundles. If using the emulator, we start it on entry and stop | 292 test bundles. If using the emulator, we start it on entry and stop |
294 it on exit. | 293 it on exit. |
295 | 294 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 | 335 |
337 if options.performance_test or options.gtest_filter: | 336 if options.performance_test or options.gtest_filter: |
338 # These configuration can't be split in multiple devices. | 337 # These configuration can't be split in multiple devices. |
339 attached_devices = [attached_devices[0]] | 338 attached_devices = [attached_devices[0]] |
340 sharder = TestSharder(attached_devices, options.test_suite, | 339 sharder = TestSharder(attached_devices, options.test_suite, |
341 options.gtest_filter, options.test_arguments, | 340 options.gtest_filter, options.test_arguments, |
342 options.timeout, options.rebaseline, | 341 options.timeout, options.rebaseline, |
343 options.performance_test, | 342 options.performance_test, |
344 options.cleanup_test_files, options.tool, | 343 options.cleanup_test_files, options.tool, |
345 options.log_dump, options.fast_and_loose, | 344 options.log_dump, options.fast_and_loose, |
346 options.build_type) | 345 options.build_type, options.webkit) |
347 test_results = sharder.RunShardedTests() | 346 test_results = sharder.RunShardedTests() |
348 | 347 |
349 for buildbot_emulator in buildbot_emulators: | 348 for buildbot_emulator in buildbot_emulators: |
350 buildbot_emulator.Shutdown() | 349 buildbot_emulator.Shutdown() |
351 | 350 |
352 return len(test_results.failed) | 351 return len(test_results.failed) |
353 | 352 |
354 | 353 |
355 def Dispatch(options): | 354 def Dispatch(options): |
356 """Dispatches the tests, sharding if possible. | 355 """Dispatches the tests, sharding if possible. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 for test_suite in _TEST_SUITES: | 391 for test_suite in _TEST_SUITES: |
393 print test_suite | 392 print test_suite |
394 | 393 |
395 | 394 |
396 def main(argv): | 395 def main(argv): |
397 option_parser = optparse.OptionParser() | 396 option_parser = optparse.OptionParser() |
398 test_options_parser.AddTestRunnerOptions(option_parser, default_timeout=0) | 397 test_options_parser.AddTestRunnerOptions(option_parser, default_timeout=0) |
399 option_parser.add_option('-s', '--suite', dest='test_suite', | 398 option_parser.add_option('-s', '--suite', dest='test_suite', |
400 help='Executable name of the test suite to run ' | 399 help='Executable name of the test suite to run ' |
401 '(use -s help to list them)') | 400 '(use -s help to list them)') |
| 401 option_parser.add_option('--out-directory', dest='out_directory', |
| 402 help='Path to the out/ directory, irrespective of ' |
| 403 'the build type. Only for non-Chromium uses.') |
402 option_parser.add_option('-d', '--device', dest='test_device', | 404 option_parser.add_option('-d', '--device', dest='test_device', |
403 help='Target device the test suite to run ') | 405 help='Target device the test suite to run ') |
404 option_parser.add_option('-r', dest='rebaseline', | 406 option_parser.add_option('-r', dest='rebaseline', |
405 help='Rebaseline and update *testsuite_disabled', | 407 help='Rebaseline and update *testsuite_disabled', |
406 action='store_true') | 408 action='store_true') |
407 option_parser.add_option('-f', '--gtest_filter', dest='gtest_filter', | 409 option_parser.add_option('-f', '--gtest_filter', dest='gtest_filter', |
408 help='gtest filter') | 410 help='gtest filter') |
409 option_parser.add_option('-a', '--test_arguments', dest='test_arguments', | 411 option_parser.add_option('-a', '--test_arguments', dest='test_arguments', |
410 help='Additional arguments to pass to the test') | 412 help='Additional arguments to pass to the test') |
411 option_parser.add_option('-p', dest='performance_test', | 413 option_parser.add_option('-p', dest='performance_test', |
412 help='Indicator of performance test', | 414 help='Indicator of performance test', |
413 action='store_true') | 415 action='store_true') |
414 option_parser.add_option('-L', dest='log_dump', | 416 option_parser.add_option('-L', dest='log_dump', |
415 help='file name of log dump, which will be put in ' | 417 help='file name of log dump, which will be put in ' |
416 'subfolder debug_info_dumps under the same ' | 418 'subfolder debug_info_dumps under the same ' |
417 'directory in where the test_suite exists.') | 419 'directory in where the test_suite exists.') |
418 option_parser.add_option('-e', '--emulator', dest='use_emulator', | 420 option_parser.add_option('-e', '--emulator', dest='use_emulator', |
419 action='store_true', | 421 action='store_true', |
420 help='Run tests in a new instance of emulator') | 422 help='Run tests in a new instance of emulator') |
421 option_parser.add_option('-n', '--emulator_count', | 423 option_parser.add_option('-n', '--emulator_count', |
422 type='int', default=1, | 424 type='int', default=1, |
423 help='Number of emulators to launch for running the ' | 425 help='Number of emulators to launch for running the ' |
424 'tests.') | 426 'tests.') |
425 option_parser.add_option('-x', '--xvfb', dest='use_xvfb', | 427 option_parser.add_option('-x', '--xvfb', dest='use_xvfb', |
426 action='store_true', | 428 action='store_true', |
427 help='Use Xvfb around tests (ignored if not Linux)') | 429 help='Use Xvfb around tests (ignored if not Linux)') |
| 430 option_parser.add_option('--webkit', action='store_true', |
| 431 help='Run the tests from a WebKit checkout.') |
428 option_parser.add_option('--fast', '--fast_and_loose', dest='fast_and_loose', | 432 option_parser.add_option('--fast', '--fast_and_loose', dest='fast_and_loose', |
429 action='store_true', | 433 action='store_true', |
430 help='Go faster (but be less stable), ' | 434 help='Go faster (but be less stable), ' |
431 'for quick testing. Example: when tracking down ' | 435 'for quick testing. Example: when tracking down ' |
432 'tests that hang to add to the disabled list, ' | 436 'tests that hang to add to the disabled list, ' |
433 'there is no need to redeploy the test binary ' | 437 'there is no need to redeploy the test binary ' |
434 'or data to the device again. ' | 438 'or data to the device again. ' |
435 'Don\'t use on bots by default!') | 439 'Don\'t use on bots by default!') |
436 option_parser.add_option('--repeat', dest='repeat', type='int', | 440 option_parser.add_option('--repeat', dest='repeat', type='int', |
437 default=2, | 441 default=2, |
438 help='Repeat count on test timeout') | 442 help='Repeat count on test timeout') |
439 option_parser.add_option('--exit_code', action='store_true', | 443 option_parser.add_option('--exit_code', action='store_true', |
440 help='If set, the exit code will be total number ' | 444 help='If set, the exit code will be total number ' |
441 'of failures.') | 445 'of failures.') |
442 option_parser.add_option('--exe', action='store_true', | 446 option_parser.add_option('--exe', action='store_true', |
443 help='If set, use the exe test runner instead of ' | 447 help='If set, use the exe test runner instead of ' |
444 'the APK.') | 448 'the APK.') |
445 | 449 |
446 options, args = option_parser.parse_args(argv) | 450 options, args = option_parser.parse_args(argv) |
447 if len(args) > 1: | 451 if len(args) > 1: |
448 print 'Unknown argument:', args[1:] | 452 print 'Unknown argument:', args[1:] |
449 option_parser.print_usage() | 453 option_parser.print_usage() |
450 sys.exit(1) | 454 sys.exit(1) |
451 run_tests_helper.SetLogLevel(options.verbose_count) | 455 run_tests_helper.SetLogLevel(options.verbose_count) |
| 456 if options.out_directory: |
| 457 cmd_helper.OutDirectory.set(options.out_directory) |
452 emulator.DeleteAllTempAVDs() | 458 emulator.DeleteAllTempAVDs() |
453 failed_tests_count = Dispatch(options) | 459 failed_tests_count = Dispatch(options) |
454 | 460 |
455 # Failures of individual test suites are communicated by printing a | 461 # Failures of individual test suites are communicated by printing a |
456 # STEP_FAILURE message. | 462 # STEP_FAILURE message. |
457 # Returning a success exit status also prevents the buildbot from incorrectly | 463 # Returning a success exit status also prevents the buildbot from incorrectly |
458 # marking the last suite as failed if there were failures in other suites in | 464 # marking the last suite as failed if there were failures in other suites in |
459 # the batch (this happens because the exit status is a sum of all failures | 465 # the batch (this happens because the exit status is a sum of all failures |
460 # from all suites, but the buildbot associates the exit status only with the | 466 # from all suites, but the buildbot associates the exit status only with the |
461 # most recent step). | 467 # most recent step). |
462 if options.exit_code: | 468 if options.exit_code: |
463 return failed_tests_count | 469 return failed_tests_count |
464 return 0 | 470 return 0 |
465 | 471 |
466 | 472 |
467 if __name__ == '__main__': | 473 if __name__ == '__main__': |
468 sys.exit(main(sys.argv)) | 474 sys.exit(main(sys.argv)) |
OLD | NEW |