2 # Copyright (c) 2013 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.
19 sys
.path
.append(os
.path
.join(os
.path
.dirname(__file__
), '..'))
20 import provision_devices
21 from pylib
import constants
22 from pylib
.device
import device_utils
23 from pylib
.gtest
import gtest_config
25 CHROME_SRC_DIR
= bb_utils
.CHROME_SRC
26 DIR_BUILD_ROOT
= os
.path
.dirname(CHROME_SRC_DIR
)
27 CHROME_OUT_DIR
= bb_utils
.CHROME_OUT_DIR
28 BLINK_SCRIPTS_DIR
= 'third_party/WebKit/Tools/Scripts'
30 SLAVE_SCRIPTS_DIR
= os
.path
.join(bb_utils
.BB_BUILD_DIR
, 'scripts', 'slave')
31 LOGCAT_DIR
= os
.path
.join(bb_utils
.CHROME_OUT_DIR
, 'logcat')
32 GS_URL
= 'https://storage.googleapis.com'
33 GS_AUTH_URL
= 'https://storage.cloud.google.com'
35 # Describes an instrumation test suite:
36 # test: Name of test we're running.
37 # apk: apk to be installed.
38 # apk_package: package for the apk to be installed.
39 # test_apk: apk to run tests on.
40 # test_data: data folder in format destination:source.
41 # host_driven_root: The host-driven test root directory.
42 # annotation: Annotation of the tests to include.
43 # exclude_annotation: The annotation of the tests to exclude.
44 I_TEST
= collections
.namedtuple('InstrumentationTest', [
45 'name', 'apk', 'apk_package', 'test_apk', 'test_data', 'isolate_file_path',
46 'host_driven_root', 'annotation', 'exclude_annotation', 'extra_flags'])
50 return os
.path
.join(CHROME_SRC_DIR
, *path
)
53 def I(name
, apk
, apk_package
, test_apk
, test_data
, isolate_file_path
=None,
54 host_driven_root
=None, annotation
=None, exclude_annotation
=None,
56 return I_TEST(name
, apk
, apk_package
, test_apk
, test_data
, isolate_file_path
,
57 host_driven_root
, annotation
, exclude_annotation
, extra_flags
)
59 INSTRUMENTATION_TESTS
= dict((suite
.name
, suite
) for suite
in [
62 'org.chromium.content_shell_apk',
64 'content:content/test/data/android/device_files',
65 isolate_file_path
='content/content_shell_test_apk.isolate'),
68 'org.chromium.chrome.shell',
70 'chrome:chrome/test/data/android/device_files',
71 isolate_file_path
='chrome/chrome_shell_test_apk.isolate'),
74 'org.chromium.android_webview.shell',
76 'webview:android_webview/test/data/device_files',
77 isolate_file_path
='android_webview/android_webview_test_apk.isolate'),
79 'ChromeSyncShell.apk',
80 'org.chromium.chrome.browser.sync',
81 'ChromeSyncShellTest',
85 InstallablePackage
= collections
.namedtuple('InstallablePackage', [
86 'name', 'apk', 'apk_package'])
88 INSTALLABLE_PACKAGES
= dict((package
.name
, package
) for package
in (
89 [InstallablePackage(i
.name
, i
.apk
, i
.apk_package
)
90 for i
in INSTRUMENTATION_TESTS
.itervalues()] +
91 [InstallablePackage('ChromeDriverWebViewShell',
92 'ChromeDriverWebViewShell.apk',
93 'org.chromium.chromedriver_webview_shell')]))
99 'components_browsertests',
104 'telemetry_unittests',
105 'telemetry_perf_unittests',
112 RunCmd
= bb_utils
.RunCmd
115 def _GetRevision(options
):
116 """Get the SVN revision number.
119 options: options object.
124 revision
= options
.build_properties
.get('got_revision')
126 revision
= options
.build_properties
.get('revision', 'testing')
130 def _RunTest(options
, cmd
, suite
):
131 """Run test command with runtest.py.
134 options: options object.
135 cmd: the command to run.
138 property_args
= bb_utils
.EncodeProperties(options
)
139 args
= [os
.path
.join(SLAVE_SCRIPTS_DIR
, 'runtest.py')] + property_args
140 args
+= ['--test-platform', 'android']
141 if options
.factory_properties
.get('generate_gtest_json'):
142 args
.append('--generate-json-file')
143 args
+= ['-o', 'gtest-results/%s' % suite
,
144 '--annotate', 'gtest',
145 '--build-number', str(options
.build_properties
.get('buildnumber',
147 '--builder-name', options
.build_properties
.get('buildername', '')]
148 if options
.target
== 'Release':
149 args
+= ['--target', 'Release']
151 args
+= ['--target', 'Debug']
152 if options
.flakiness_server
:
153 args
+= ['--flakiness-dashboard-server=%s' %
154 options
.flakiness_server
]
156 RunCmd(args
, cwd
=DIR_BUILD_ROOT
)
159 def RunTestSuites(options
, suites
, suites_options
=None):
160 """Manages an invocation of test_runner.py for gtests.
163 options: options object.
164 suites: List of suite names to run.
165 suites_options: Command line options dictionary for particular suites.
167 {'content_browsertests', ['--num_retries=1', '--release']}
168 will add the options only to content_browsertests.
171 if not suites_options
:
175 if options
.target
== 'Release':
176 args
.append('--release')
178 args
.append('--tool=asan')
179 if options
.gtest_filter
:
180 args
.append('--gtest-filter=%s' % options
.gtest_filter
)
183 bb_annotations
.PrintNamedStep(suite
)
185 cmd
+= suites_options
.get(suite
, [])
186 if suite
== 'content_browsertests' or suite
== 'components_browsertests':
187 cmd
.append('--num_retries=1')
188 _RunTest(options
, cmd
, suite
)
191 def RunJunitSuite(suite
):
192 bb_annotations
.PrintNamedStep(suite
)
193 RunCmd(['build/android/test_runner.py', 'junit', '-s', suite
])
196 def RunChromeDriverTests(options
):
197 """Run all the steps for running chromedriver tests."""
198 bb_annotations
.PrintNamedStep('chromedriver_annotation')
199 RunCmd(['chrome/test/chromedriver/run_buildbot_steps.py',
200 '--android-packages=%s,%s,%s,%s' %
204 'chromedriver_webview_shell'),
205 '--revision=%s' % _GetRevision(options
),
208 def RunChromeProxyTests(options
):
209 """Run the chrome_proxy tests.
212 options: options object.
214 InstallApk(options
, INSTRUMENTATION_TESTS
['ChromeShell'], False)
215 args
= ['--browser', 'android-chrome-shell']
216 devices
= device_utils
.DeviceUtils
.HealthyDevices()
218 args
= args
+ ['--device', devices
[0].adb
.GetDeviceSerial()]
219 bb_annotations
.PrintNamedStep('chrome_proxy')
220 RunCmd(['tools/chrome_proxy/run_tests'] + args
)
223 def RunTelemetryTests(options
, step_name
, run_tests_path
):
224 """Runs either telemetry_perf_unittests or telemetry_unittests.
227 options: options object.
228 step_name: either 'telemetry_unittests' or 'telemetry_perf_unittests'
229 run_tests_path: path to run_tests script (tools/perf/run_tests for
230 perf_unittests and tools/telemetry/run_tests for
233 InstallApk(options
, INSTRUMENTATION_TESTS
['ChromeShell'], False)
234 args
= ['--browser', 'android-chrome-shell']
235 devices
= device_utils
.DeviceUtils
.HealthyDevices()
237 args
= args
+ ['--device', 'android']
238 bb_annotations
.PrintNamedStep(step_name
)
239 RunCmd([run_tests_path
] + args
)
242 def InstallApk(options
, test
, print_step
=False):
243 """Install an apk to all phones.
246 options: options object
247 test: An I_TEST namedtuple
248 print_step: Print a buildbot step
251 bb_annotations
.PrintNamedStep('install_%s' % test
.name
.lower())
253 args
= ['--apk_package', test
.apk_package
]
254 if options
.target
== 'Release':
255 args
.append('--release')
256 args
.append(test
.apk
)
258 RunCmd(['build/android/adb_install_apk.py'] + args
, halt_on_failure
=True)
261 def RunInstrumentationSuite(options
, test
, flunk_on_failure
=True,
262 python_only
=False, official_build
=False):
263 """Manages an invocation of test_runner.py for instrumentation tests.
266 options: options object
267 test: An I_TEST namedtuple
268 flunk_on_failure: Flunk the step if tests fail.
269 Python: Run only host driven Python tests.
270 official_build: Run official-build tests.
272 bb_annotations
.PrintNamedStep('%s_instrumentation_tests' % test
.name
.lower())
275 InstallApk(options
, test
)
276 args
= ['--test-apk', test
.test_apk
, '--verbose']
278 args
.extend(['--test_data', test
.test_data
])
279 if options
.target
== 'Release':
280 args
.append('--release')
282 args
.append('--tool=asan')
283 if options
.flakiness_server
:
284 args
.append('--flakiness-dashboard-server=%s' %
285 options
.flakiness_server
)
286 if options
.coverage_bucket
:
287 args
.append('--coverage-dir=%s' % options
.coverage_dir
)
288 if test
.isolate_file_path
:
289 args
.append('--isolate-file-path=%s' % test
.isolate_file_path
)
290 if test
.host_driven_root
:
291 args
.append('--host-driven-root=%s' % test
.host_driven_root
)
293 args
.extend(['-A', test
.annotation
])
294 if test
.exclude_annotation
:
295 args
.extend(['-E', test
.exclude_annotation
])
297 args
.extend(test
.extra_flags
)
301 # The option needs to be assigned 'True' as it does not have an action
302 # associated with it.
303 args
.append('--official-build')
305 RunCmd(['build/android/test_runner.py', 'instrumentation'] + args
,
306 flunk_on_failure
=flunk_on_failure
)
310 """Lint WebKit's TestExpectation files."""
311 bb_annotations
.PrintNamedStep('webkit_lint')
312 RunCmd([SrcPath(os
.path
.join(BLINK_SCRIPTS_DIR
, 'lint-test-expectations'))])
315 def RunWebkitLayoutTests(options
):
316 """Run layout tests on an actual device."""
317 bb_annotations
.PrintNamedStep('webkit_tests')
320 '--no-new-test-results',
321 '--full-results-html',
322 '--clobber-old-results',
323 '--exit-after-n-failures', '5000',
324 '--exit-after-n-crashes-or-timeouts', '100',
325 '--debug-rwt-logging',
326 '--results-directory', '../layout-test-results',
327 '--target', options
.target
,
328 '--builder-name', options
.build_properties
.get('buildername', ''),
329 '--build-number', str(options
.build_properties
.get('buildnumber', '')),
330 '--master-name', 'ChromiumWebkit', # TODO: Get this from the cfg.
331 '--build-name', options
.build_properties
.get('buildername', ''),
332 '--platform=android']
334 for flag
in 'test_results_server', 'driver_name', 'additional_driver_flag':
335 if flag
in options
.factory_properties
:
336 cmd_args
.extend(['--%s' % flag
.replace('_', '-'),
337 options
.factory_properties
.get(flag
)])
339 for f
in options
.factory_properties
.get('additional_expectations', []):
341 ['--additional-expectations=%s' % os
.path
.join(CHROME_SRC_DIR
, *f
)])
343 # TODO(dpranke): Remove this block after
344 # https://codereview.chromium.org/12927002/ lands.
345 for f
in options
.factory_properties
.get('additional_expectations_files', []):
347 ['--additional-expectations=%s' % os
.path
.join(CHROME_SRC_DIR
, *f
)])
350 [SrcPath(os
.path
.join(BLINK_SCRIPTS_DIR
, 'run-webkit-tests'))] + cmd_args
)
351 if exit_code
== 255: # test_run_results.UNEXPECTED_ERROR_EXIT_STATUS
352 bb_annotations
.PrintMsg('?? (crashed or hung)')
353 elif exit_code
== 254: # test_run_results.NO_DEVICES_EXIT_STATUS
354 bb_annotations
.PrintMsg('?? (no devices found)')
355 elif exit_code
== 253: # test_run_results.NO_TESTS_EXIT_STATUS
356 bb_annotations
.PrintMsg('?? (no tests found)')
358 full_results_path
= os
.path
.join('..', 'layout-test-results',
360 if os
.path
.exists(full_results_path
):
361 full_results
= json
.load(open(full_results_path
))
362 unexpected_passes
, unexpected_failures
, unexpected_flakes
= (
363 _ParseLayoutTestResults(full_results
))
364 if unexpected_failures
:
365 _PrintDashboardLink('failed', unexpected_failures
.keys(),
367 elif unexpected_passes
:
368 _PrintDashboardLink('unexpected passes', unexpected_passes
.keys(),
370 if unexpected_flakes
:
371 _PrintDashboardLink('unexpected flakes', unexpected_flakes
.keys(),
374 if exit_code
== 0 and (unexpected_passes
or unexpected_flakes
):
375 # If exit_code != 0, RunCmd() will have already printed an error.
376 bb_annotations
.PrintWarning()
378 bb_annotations
.PrintError()
379 bb_annotations
.PrintMsg('?? (results missing)')
381 if options
.factory_properties
.get('archive_webkit_results', False):
382 bb_annotations
.PrintNamedStep('archive_webkit_results')
383 base
= 'https://storage.googleapis.com/chromium-layout-test-archives'
384 builder_name
= options
.build_properties
.get('buildername', '')
385 build_number
= str(options
.build_properties
.get('buildnumber', ''))
386 results_link
= '%s/%s/%s/layout-test-results/results.html' % (
387 base
, EscapeBuilderName(builder_name
), build_number
)
388 bb_annotations
.PrintLink('results', results_link
)
389 bb_annotations
.PrintLink('(zip)', '%s/%s/%s/layout-test-results.zip' % (
390 base
, EscapeBuilderName(builder_name
), build_number
))
391 gs_bucket
= 'gs://chromium-layout-test-archives'
392 RunCmd([os
.path
.join(SLAVE_SCRIPTS_DIR
, 'chromium',
393 'archive_layout_test_results.py'),
394 '--results-dir', '../../layout-test-results',
395 '--build-number', build_number
,
396 '--builder-name', builder_name
,
397 '--gs-bucket', gs_bucket
],
401 def _ParseLayoutTestResults(results
):
402 """Extract the failures from the test run."""
403 # Cloned from third_party/WebKit/Tools/Scripts/print-json-test-results
404 tests
= _ConvertTrieToFlatPaths(results
['tests'])
408 for (test
, result
) in tests
.iteritems():
409 if result
.get('is_unexpected'):
410 actual_results
= result
['actual'].split()
411 expected_results
= result
['expected'].split()
412 if len(actual_results
) > 1:
413 # We report the first failure type back, even if the second
415 if actual_results
[1] in expected_results
:
416 flakes
[test
] = actual_results
[0]
418 failures
[test
] = actual_results
[0]
419 elif actual_results
[0] == 'PASS':
420 passes
[test
] = result
422 failures
[test
] = actual_results
[0]
424 return (passes
, failures
, flakes
)
427 def _ConvertTrieToFlatPaths(trie
, prefix
=None):
428 """Flatten the trie of failures into a list."""
429 # Cloned from third_party/WebKit/Tools/Scripts/print-json-test-results
431 for name
, data
in trie
.iteritems():
433 name
= prefix
+ '/' + name
435 if len(data
) and 'actual' not in data
and 'expected' not in data
:
436 result
.update(_ConvertTrieToFlatPaths(data
, name
))
443 def _PrintDashboardLink(link_text
, tests
, max_tests
):
444 """Add a link to the flakiness dashboard in the step annotations."""
445 if len(tests
) > max_tests
:
446 test_list_text
= ' '.join(tests
[:max_tests
]) + ' and more'
448 test_list_text
= ' '.join(tests
)
450 dashboard_base
= ('http://test-results.appspot.com'
451 '/dashboards/flakiness_dashboard.html#'
452 'master=ChromiumWebkit&tests=')
454 bb_annotations
.PrintLink('%d %s: %s' %
455 (len(tests
), link_text
, test_list_text
),
456 dashboard_base
+ ','.join(tests
))
459 def EscapeBuilderName(builder_name
):
460 return re
.sub('[ ()]', '_', builder_name
)
463 def SpawnLogcatMonitor():
464 shutil
.rmtree(LOGCAT_DIR
, ignore_errors
=True)
466 os
.path
.join(CHROME_SRC_DIR
, 'build', 'android', 'adb_logcat_monitor.py'),
469 # Wait for logcat_monitor to pull existing logcat
470 RunCmd(['sleep', '5'])
473 def ProvisionDevices(options
):
474 bb_annotations
.PrintNamedStep('provision_devices')
476 if not bb_utils
.TESTING
:
477 # Restart adb to work around bugs, sleep to wait for usb discovery.
478 device_utils
.RestartServer()
479 RunCmd(['sleep', '1'])
480 provision_cmd
= ['build/android/provision_devices.py', '-t', options
.target
]
481 if options
.auto_reconnect
:
482 provision_cmd
.append('--auto-reconnect')
483 if options
.skip_wipe
:
484 provision_cmd
.append('--skip-wipe')
485 if options
.disable_location
:
486 provision_cmd
.append('--disable-location')
487 RunCmd(provision_cmd
, halt_on_failure
=True)
490 def DeviceStatusCheck(options
):
491 bb_annotations
.PrintNamedStep('device_status_check')
492 cmd
= ['build/android/buildbot/bb_device_status_check.py']
493 if options
.restart_usb
:
494 cmd
.append('--restart-usb')
495 RunCmd(cmd
, halt_on_failure
=True)
498 def GetDeviceSetupStepCmds():
500 ('device_status_check', DeviceStatusCheck
),
501 ('provision_devices', ProvisionDevices
),
505 def RunUnitTests(options
):
506 suites
= gtest_config
.STABLE_TEST_SUITES
508 suites
= [s
for s
in suites
509 if s
not in gtest_config
.ASAN_EXCLUDED_TEST_SUITES
]
510 RunTestSuites(options
, suites
)
513 def RunTelemetryUnitTests(options
):
514 RunTelemetryTests(options
, 'telemetry_unittests', 'tools/telemetry/run_tests')
517 def RunTelemetryPerfUnitTests(options
):
518 RunTelemetryTests(options
, 'telemetry_perf_unittests', 'tools/perf/run_tests')
521 def RunInstrumentationTests(options
):
522 for test
in INSTRUMENTATION_TESTS
.itervalues():
523 RunInstrumentationSuite(options
, test
)
526 def RunWebkitTests(options
):
527 RunTestSuites(options
, ['webkit_unit_tests', 'blink_heap_unittests'])
531 def RunGPUTests(options
):
532 revision
= _GetRevision(options
)
533 builder_name
= options
.build_properties
.get('buildername', 'noname')
535 bb_annotations
.PrintNamedStep('pixel_tests')
536 RunCmd(['content/test/gpu/run_gpu_test.py',
539 'android-content-shell',
542 '--upload-refimg-to-cloud-storage',
543 '--refimg-cloud-storage-bucket',
544 'chromium-gpu-archive/reference-images',
547 '--test-machine-name',
548 EscapeBuilderName(builder_name
)])
550 bb_annotations
.PrintNamedStep('webgl_conformance_tests')
551 RunCmd(['content/test/gpu/run_gpu_test.py', '-v',
552 '--browser=android-content-shell', 'webgl_conformance',
553 '--webgl-conformance-version=1.0.1'])
555 bb_annotations
.PrintNamedStep('android_webview_webgl_conformance_tests')
556 RunCmd(['content/test/gpu/run_gpu_test.py', '-v',
557 '--browser=android-webview-shell', 'webgl_conformance',
558 '--webgl-conformance-version=1.0.1'])
560 bb_annotations
.PrintNamedStep('gpu_rasterization_tests')
561 RunCmd(['content/test/gpu/run_gpu_test.py',
562 'gpu_rasterization', '-v',
564 'android-content-shell',
567 '--test-machine-name',
568 EscapeBuilderName(builder_name
)])
571 def RunPythonUnitTests(_options
):
572 for suite
in constants
.PYTHON_UNIT_TEST_SUITES
:
573 bb_annotations
.PrintNamedStep(suite
)
574 RunCmd(['build/android/test_runner.py', 'python', '-s', suite
])
577 def GetTestStepCmds():
580 lambda _options
: RunJunitSuite('base_junit_tests')),
581 ('chromedriver', RunChromeDriverTests
),
582 ('chrome_proxy', RunChromeProxyTests
),
583 ('components_browsertests',
584 lambda options
: RunTestSuites(options
, ['components_browsertests'])),
586 lambda options
: RunTestSuites(options
, ['gfx_unittests'])),
588 lambda options
: RunTestSuites(options
, ['gl_unittests'])),
589 ('gpu', RunGPUTests
),
590 ('python_unittests', RunPythonUnitTests
),
591 ('telemetry_unittests', RunTelemetryUnitTests
),
592 ('telemetry_perf_unittests', RunTelemetryPerfUnitTests
),
593 ('ui', RunInstrumentationTests
),
594 ('unit', RunUnitTests
),
595 ('webkit', RunWebkitTests
),
596 ('webkit_layout', RunWebkitLayoutTests
),
600 def MakeGSPath(options
, gs_base_dir
):
601 revision
= _GetRevision(options
)
602 bot_id
= options
.build_properties
.get('buildername', 'testing')
603 randhash
= hashlib
.sha1(str(random
.random())).hexdigest()
604 gs_path
= '%s/%s/%s/%s' % (gs_base_dir
, bot_id
, revision
, randhash
)
605 # remove double slashes, happens with blank revisions and confuses gsutil
606 gs_path
= re
.sub('/+', '/', gs_path
)
609 def UploadHTML(options
, gs_base_dir
, dir_to_upload
, link_text
,
610 link_rel_path
='index.html', gs_url
=GS_URL
):
611 """Uploads directory at |dir_to_upload| to Google Storage and output a link.
614 options: Command line options.
615 gs_base_dir: The Google Storage base directory (e.g.
616 'chromium-code-coverage/java')
617 dir_to_upload: Absolute path to the directory to be uploaded.
618 link_text: Link text to be displayed on the step.
619 link_rel_path: Link path relative to |dir_to_upload|.
620 gs_url: Google storage URL.
622 gs_path
= MakeGSPath(options
, gs_base_dir
)
623 RunCmd([bb_utils
.GSUTIL_PATH
, 'cp', '-R', dir_to_upload
, 'gs://%s' % gs_path
])
624 bb_annotations
.PrintLink(link_text
,
625 '%s/%s/%s' % (gs_url
, gs_path
, link_rel_path
))
628 def GenerateJavaCoverageReport(options
):
629 """Generates an HTML coverage report using EMMA and uploads it."""
630 bb_annotations
.PrintNamedStep('java_coverage_report')
632 coverage_html
= os
.path
.join(options
.coverage_dir
, 'coverage_html')
633 RunCmd(['build/android/generate_emma_html.py',
634 '--coverage-dir', options
.coverage_dir
,
635 '--metadata-dir', os
.path
.join(CHROME_OUT_DIR
, options
.target
),
637 '--output', os
.path
.join(coverage_html
, 'index.html')])
641 def LogcatDump(options
):
642 # Print logcat, kill logcat monitor
643 bb_annotations
.PrintNamedStep('logcat_dump')
644 logcat_file
= os
.path
.join(CHROME_OUT_DIR
, options
.target
, 'full_log.txt')
645 RunCmd([SrcPath('build', 'android', 'adb_logcat_printer.py'),
646 '--output-path', logcat_file
, LOGCAT_DIR
])
647 gs_path
= MakeGSPath(options
, 'chromium-android/logcat_dumps')
648 RunCmd([bb_utils
.GSUTIL_PATH
, 'cp', '-z', 'txt', logcat_file
,
649 'gs://%s' % gs_path
])
650 bb_annotations
.PrintLink('logcat dump', '%s/%s' % (GS_AUTH_URL
, gs_path
))
653 def RunStackToolSteps(options
):
654 """Run stack tool steps.
656 Stack tool is run for logcat dump, optionally for ASAN.
658 bb_annotations
.PrintNamedStep('Run stack tool with logcat dump')
659 logcat_file
= os
.path
.join(CHROME_OUT_DIR
, options
.target
, 'full_log.txt')
660 RunCmd([os
.path
.join(CHROME_SRC_DIR
, 'third_party', 'android_platform',
661 'development', 'scripts', 'stack'),
662 '--more-info', logcat_file
])
663 if options
.asan_symbolize
:
664 bb_annotations
.PrintNamedStep('Run stack tool for ASAN')
666 os
.path
.join(CHROME_SRC_DIR
, 'build', 'android', 'asan_symbolize.py'),
670 def GenerateTestReport(options
):
671 bb_annotations
.PrintNamedStep('test_report')
672 for report
in glob
.glob(
673 os
.path
.join(CHROME_OUT_DIR
, options
.target
, 'test_logs', '*.log')):
674 RunCmd(['cat', report
])
678 def MainTestWrapper(options
):
680 # Spawn logcat monitor
683 # Run all device setup steps
684 for _
, cmd
in GetDeviceSetupStepCmds():
688 for i
in options
.install
:
689 install_obj
= INSTALLABLE_PACKAGES
[i
]
690 InstallApk(options
, install_obj
, print_step
=True)
692 if options
.test_filter
:
693 bb_utils
.RunSteps(options
.test_filter
, GetTestStepCmds(), options
)
695 if options
.coverage_bucket
:
696 coverage_html
= GenerateJavaCoverageReport(options
)
697 UploadHTML(options
, '%s/java' % options
.coverage_bucket
, coverage_html
,
699 shutil
.rmtree(coverage_html
, ignore_errors
=True)
701 if options
.experimental
:
702 RunTestSuites(options
, gtest_config
.EXPERIMENTAL_TEST_SUITES
)
705 # Run all post test steps
707 if not options
.disable_stack_tool
:
708 RunStackToolSteps(options
)
709 GenerateTestReport(options
)
710 # KillHostHeartbeat() has logic to check if heartbeat process is running,
711 # and kills only if it finds the process is running on the host.
712 provision_devices
.KillHostHeartbeat()
714 shutil
.rmtree(os
.path
.join(CHROME_OUT_DIR
, options
.target
),
718 def GetDeviceStepsOptParser():
719 parser
= bb_utils
.GetParser()
720 parser
.add_option('--experimental', action
='store_true',
721 help='Run experiemental tests')
722 parser
.add_option('-f', '--test-filter', metavar
='<filter>', default
=[],
724 help=('Run a test suite. Test suites: "%s"' %
725 '", "'.join(VALID_TESTS
)))
726 parser
.add_option('--gtest-filter',
727 help='Filter for running a subset of tests of a gtest test')
728 parser
.add_option('--asan', action
='store_true', help='Run tests with asan.')
729 parser
.add_option('--install', metavar
='<apk name>', action
="append",
730 help='Install an apk by name')
731 parser
.add_option('--no-reboot', action
='store_true',
732 help='Do not reboot devices during provisioning.')
733 parser
.add_option('--coverage-bucket',
734 help=('Bucket name to store coverage results. Coverage is '
735 'only run if this is set.'))
736 parser
.add_option('--restart-usb', action
='store_true',
737 help='Restart usb ports before device status check.')
739 '--flakiness-server',
740 help=('The flakiness dashboard server to which the results should be '
743 '--auto-reconnect', action
='store_true',
744 help='Push script to device which restarts adbd on disconnections.')
745 parser
.add_option('--skip-wipe', action
='store_true',
746 help='Do not wipe devices during provisioning.')
747 parser
.add_option('--disable-location', action
='store_true',
748 help='Disable location settings.')
750 '--logcat-dump-output',
751 help='The logcat dump output will be "tee"-ed into this file')
752 # During processing perf bisects, a seperate working directory created under
753 # which builds are produced. Therefore we should look for relevent output
754 # file under this directory.(/b/build/slave/<slave_name>/build/bisect/src/out)
756 '--chrome-output-dir',
757 help='Chrome output directory to be used while bisecting.')
759 parser
.add_option('--disable-stack-tool', action
='store_true',
760 help='Do not run stack tool.')
761 parser
.add_option('--asan-symbolize', action
='store_true',
762 help='Run stack tool for ASAN')
763 parser
.add_option('--cleanup', action
='store_true',
764 help='Delete out/<target> directory at the end of the run.')
769 parser
= GetDeviceStepsOptParser()
770 options
, args
= parser
.parse_args(argv
[1:])
773 return sys
.exit('Unused args %s' % args
)
775 unknown_tests
= set(options
.test_filter
) - VALID_TESTS
777 return sys
.exit('Unknown tests %s' % list(unknown_tests
))
779 setattr(options
, 'target', options
.factory_properties
.get('target', 'Debug'))
781 if options
.chrome_output_dir
:
782 global CHROME_OUT_DIR
784 CHROME_OUT_DIR
= options
.chrome_output_dir
785 LOGCAT_DIR
= os
.path
.join(CHROME_OUT_DIR
, 'logcat')
787 if options
.coverage_bucket
:
788 setattr(options
, 'coverage_dir',
789 os
.path
.join(CHROME_OUT_DIR
, options
.target
, 'coverage'))
791 MainTestWrapper(options
)
794 if __name__
== '__main__':
795 sys
.exit(main(sys
.argv
))