1# Copyright 2017 the V8 project authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5from functools import reduce 6 7from collections import OrderedDict, namedtuple 8import json 9import multiprocessing 10import optparse 11import os 12import shlex 13import sys 14import traceback 15 16 17 18# Add testrunner to the path. 19sys.path.insert( 20 0, 21 os.path.dirname( 22 os.path.dirname(os.path.abspath(__file__)))) 23 24 25from testrunner.local import command 26from testrunner.local import testsuite 27from testrunner.local import utils 28from testrunner.test_config import TestConfig 29from testrunner.testproc import progress 30from testrunner.testproc.rerun import RerunProc 31from testrunner.testproc.shard import ShardProc 32from testrunner.testproc.sigproc import SignalProc 33from testrunner.testproc.timeout import TimeoutProc 34from testrunner.testproc import util 35 36 37BASE_DIR = ( 38 os.path.dirname( 39 os.path.dirname( 40 os.path.dirname( 41 os.path.abspath(__file__))))) 42 43DEFAULT_OUT_GN = 'out.gn' 44 45# Map of test name synonyms to lists of test suites. Should be ordered by 46# expected runtimes (suites with slow test cases first). These groups are 47# invoked in separate steps on the bots. 48# The mapping from names used here to GN targets (which must stay in sync) 49# is defined in infra/mb/gn_isolate_map.pyl. 50TEST_MAP = { 51 # This needs to stay in sync with group("v8_bot_default") in test/BUILD.gn. 52 "bot_default": [ 53 "debugger", 54 "mjsunit", 55 "cctest", 56 "wasm-spec-tests", 57 "inspector", 58 "webkit", 59 "mkgrokdump", 60 "wasm-js", 61 "fuzzer", 62 "message", 63 "intl", 64 "unittests", 65 "wasm-api-tests", 66 ], 67 # This needs to stay in sync with group("v8_default") in test/BUILD.gn. 68 "default": [ 69 "debugger", 70 "mjsunit", 71 "cctest", 72 "wasm-spec-tests", 73 "inspector", 74 "mkgrokdump", 75 "wasm-js", 76 "fuzzer", 77 "message", 78 "intl", 79 "unittests", 80 "wasm-api-tests", 81 ], 82 # This needs to stay in sync with group("v8_d8_default") in test/BUILD.gn. 83 "d8_default": [ 84 "debugger", 85 "mjsunit", 86 "webkit", 87 "message", 88 "intl", 89 ], 90 # This needs to stay in sync with "v8_optimize_for_size" in test/BUILD.gn. 91 "optimize_for_size": [ 92 "debugger", 93 "mjsunit", 94 "cctest", 95 "inspector", 96 "webkit", 97 "intl", 98 ], 99 "unittests": [ 100 "unittests", 101 ], 102} 103 104# Increase the timeout for these: 105SLOW_ARCHS = [ 106 "arm", 107 "arm64", 108 "mips", 109 "mipsel", 110 "mips64", 111 "mips64el", 112 "s390", 113 "s390x", 114 "riscv64", 115 "loong64" 116] 117 118 119ModeConfig = namedtuple( 120 'ModeConfig', 'label flags timeout_scalefactor status_mode') 121 122DEBUG_FLAGS = ["--nohard-abort", "--enable-slow-asserts", "--verify-heap"] 123RELEASE_FLAGS = ["--nohard-abort"] 124 125DEBUG_MODE = ModeConfig( 126 label='debug', 127 flags=DEBUG_FLAGS, 128 timeout_scalefactor=4, 129 status_mode="debug", 130) 131 132RELEASE_MODE = ModeConfig( 133 label='release', 134 flags=RELEASE_FLAGS, 135 timeout_scalefactor=1, 136 status_mode="release", 137) 138 139# Normal trybot release configuration. There, dchecks are always on which 140# implies debug is set. Hence, the status file needs to assume debug-like 141# behavior/timeouts. 142TRY_RELEASE_MODE = ModeConfig( 143 label='release+dchecks', 144 flags=RELEASE_FLAGS, 145 timeout_scalefactor=4, 146 status_mode="debug", 147) 148 149PROGRESS_INDICATORS = { 150 'verbose': progress.VerboseProgressIndicator, 151 'ci': progress.CIProgressIndicator, 152 'dots': progress.DotsProgressIndicator, 153 'color': progress.ColorProgressIndicator, 154 'mono': progress.MonochromeProgressIndicator, 155 'stream': progress.StreamProgressIndicator, 156} 157 158class TestRunnerError(Exception): 159 pass 160 161 162class BuildConfig(object): 163 def __init__(self, build_config): 164 # In V8 land, GN's x86 is called ia32. 165 if build_config['v8_target_cpu'] == 'x86': 166 self.arch = 'ia32' 167 else: 168 self.arch = build_config['v8_target_cpu'] 169 170 self.asan = build_config['is_asan'] 171 self.cfi_vptr = build_config['is_cfi'] 172 self.control_flow_integrity = build_config['v8_control_flow_integrity'] 173 self.concurrent_marking = build_config['v8_enable_concurrent_marking'] 174 self.single_generation = build_config['v8_enable_single_generation'] 175 self.dcheck_always_on = build_config['dcheck_always_on'] 176 self.gcov_coverage = build_config['is_gcov_coverage'] 177 self.is_android = build_config['is_android'] 178 self.is_clang = build_config['is_clang'] 179 self.is_debug = build_config['is_debug'] 180 self.is_full_debug = build_config['is_full_debug'] 181 self.msan = build_config['is_msan'] 182 self.no_i18n = not build_config['v8_enable_i18n_support'] 183 self.predictable = build_config['v8_enable_verify_predictable'] 184 self.simulator_run = (build_config['target_cpu'] != 185 build_config['v8_target_cpu']) 186 self.tsan = build_config['is_tsan'] 187 # TODO(machenbach): We only have ubsan not ubsan_vptr. 188 self.ubsan_vptr = build_config['is_ubsan_vptr'] 189 self.verify_csa = build_config['v8_enable_verify_csa'] 190 self.lite_mode = build_config['v8_enable_lite_mode'] 191 self.pointer_compression = build_config['v8_enable_pointer_compression'] 192 self.pointer_compression_shared_cage = build_config['v8_enable_pointer_compression_shared_cage'] 193 self.shared_ro_heap = build_config['v8_enable_shared_ro_heap'] 194 self.sandbox = build_config['v8_enable_sandbox'] 195 self.third_party_heap = build_config['v8_enable_third_party_heap'] 196 self.webassembly = build_config['v8_enable_webassembly'] 197 self.dict_property_const_tracking = build_config['v8_dict_property_const_tracking'] 198 # Export only for MIPS target 199 if self.arch in ['mips', 'mipsel', 'mips64', 'mips64el']: 200 self.mips_arch_variant = build_config['mips_arch_variant'] 201 self.mips_use_msa = build_config['mips_use_msa'] 202 203 @property 204 def use_sanitizer(self): 205 return (self.asan or self.cfi_vptr or self.msan or self.tsan or 206 self.ubsan_vptr) 207 208 def __str__(self): 209 detected_options = [] 210 211 if self.asan: 212 detected_options.append('asan') 213 if self.cfi_vptr: 214 detected_options.append('cfi_vptr') 215 if self.control_flow_integrity: 216 detected_options.append('control_flow_integrity') 217 if self.dcheck_always_on: 218 detected_options.append('dcheck_always_on') 219 if self.gcov_coverage: 220 detected_options.append('gcov_coverage') 221 if self.msan: 222 detected_options.append('msan') 223 if self.no_i18n: 224 detected_options.append('no_i18n') 225 if self.predictable: 226 detected_options.append('predictable') 227 if self.tsan: 228 detected_options.append('tsan') 229 if self.ubsan_vptr: 230 detected_options.append('ubsan_vptr') 231 if self.verify_csa: 232 detected_options.append('verify_csa') 233 if self.lite_mode: 234 detected_options.append('lite_mode') 235 if self.pointer_compression: 236 detected_options.append('pointer_compression') 237 if self.pointer_compression_shared_cage: 238 detected_options.append('pointer_compression_shared_cage') 239 if self.sandbox: 240 detected_options.append('sandbox') 241 if self.third_party_heap: 242 detected_options.append('third_party_heap') 243 if self.webassembly: 244 detected_options.append('webassembly') 245 if self.dict_property_const_tracking: 246 detected_options.append('dict_property_const_tracking') 247 248 return '\n'.join(detected_options) 249 250 251def _do_load_build_config(outdir, verbose=False): 252 build_config_path = os.path.join(outdir, "v8_build_config.json") 253 if not os.path.exists(build_config_path): 254 if verbose: 255 print("Didn't find build config: %s" % build_config_path) 256 raise TestRunnerError() 257 258 with open(build_config_path) as f: 259 try: 260 build_config_json = json.load(f) 261 except Exception: # pragma: no cover 262 print("%s exists but contains invalid json. Is your build up-to-date?" 263 % build_config_path) 264 raise TestRunnerError() 265 266 return BuildConfig(build_config_json) 267 268 269class BaseTestRunner(object): 270 def __init__(self, basedir=None): 271 self.basedir = basedir or BASE_DIR 272 self.outdir = None 273 self.build_config = None 274 self.mode_options = None 275 self.target_os = None 276 self.infra_staging = False 277 278 @property 279 def framework_name(self): 280 """String name of the base-runner subclass, used in test results.""" 281 raise NotImplementedError() 282 283 def execute(self, sys_args=None): 284 if sys_args is None: # pragma: no cover 285 sys_args = sys.argv[1:] 286 try: 287 parser = self._create_parser() 288 options, args = self._parse_args(parser, sys_args) 289 self.infra_staging = options.infra_staging 290 if options.swarming: 291 # Swarming doesn't print how isolated commands are called. Lets make 292 # this less cryptic by printing it ourselves. 293 print(' '.join(sys.argv)) 294 295 # TODO(machenbach): Print used Python version until we have switched to 296 # Python3 everywhere. 297 print('Running with:') 298 print(sys.version) 299 300 # Kill stray processes from previous tasks on swarming. 301 util.kill_processes_linux() 302 303 self._load_build_config(options) 304 command.setup(self.target_os, options.device) 305 306 try: 307 self._process_default_options(options) 308 self._process_options(options) 309 except TestRunnerError: 310 parser.print_help() 311 raise 312 313 args = self._parse_test_args(args) 314 tests = self._load_testsuite_generators(args, options) 315 self._setup_env() 316 print(">>> Running tests for %s.%s" % (self.build_config.arch, 317 self.mode_options.label)) 318 exit_code = self._do_execute(tests, args, options) 319 if exit_code == utils.EXIT_CODE_FAILURES and options.json_test_results: 320 print("Force exit code 0 after failures. Json test results file " 321 "generated with failure information.") 322 exit_code = utils.EXIT_CODE_PASS 323 return exit_code 324 except TestRunnerError: 325 traceback.print_exc() 326 return utils.EXIT_CODE_INTERNAL_ERROR 327 except KeyboardInterrupt: 328 return utils.EXIT_CODE_INTERRUPTED 329 except Exception: 330 traceback.print_exc() 331 return utils.EXIT_CODE_INTERNAL_ERROR 332 finally: 333 command.tear_down() 334 335 def _create_parser(self): 336 parser = optparse.OptionParser() 337 parser.usage = '%prog [options] [tests]' 338 parser.description = """TESTS: %s""" % (TEST_MAP["default"]) 339 self._add_parser_default_options(parser) 340 self._add_parser_options(parser) 341 return parser 342 343 def _add_parser_default_options(self, parser): 344 parser.add_option("--gn", help="Scan out.gn for the last built" 345 " configuration", 346 default=False, action="store_true") 347 parser.add_option("--outdir", help="Base directory with compile output", 348 default="out") 349 parser.add_option("--arch", 350 help="The architecture to run tests for") 351 parser.add_option("--shell-dir", help="DEPRECATED! Executables from build " 352 "directory will be used") 353 parser.add_option("--test-root", help="Root directory of the test suites", 354 default=os.path.join(self.basedir, 'test')) 355 parser.add_option("--total-timeout-sec", default=0, type="int", 356 help="How long should fuzzer run") 357 parser.add_option("--swarming", default=False, action="store_true", 358 help="Indicates running test driver on swarming.") 359 parser.add_option('--infra-staging', help='Use new test runner features', 360 dest='infra_staging', default=None, 361 action='store_true') 362 parser.add_option('--no-infra-staging', 363 help='Opt out of new test runner features', 364 dest='infra_staging', default=None, 365 action='store_false') 366 367 parser.add_option("-j", help="The number of parallel tasks to run", 368 default=0, type=int) 369 parser.add_option("-d", "--device", 370 help="The device ID to run Android tests on. If not " 371 "given it will be autodetected.") 372 373 # Shard 374 parser.add_option("--shard-count", default=1, type=int, 375 help="Split tests into this number of shards") 376 parser.add_option("--shard-run", default=1, type=int, 377 help="Run this shard from the split up tests.") 378 379 # Progress 380 parser.add_option("-p", "--progress", 381 choices=list(PROGRESS_INDICATORS.keys()), default="mono", 382 help="The style of progress indicator (verbose, dots, " 383 "color, mono)") 384 parser.add_option("--json-test-results", 385 help="Path to a file for storing json results.") 386 parser.add_option('--slow-tests-cutoff', type="int", default=100, 387 help='Collect N slowest tests') 388 parser.add_option("--junitout", help="File name of the JUnit output") 389 parser.add_option("--junittestsuite", default="v8tests", 390 help="The testsuite name in the JUnit output file") 391 parser.add_option("--exit-after-n-failures", type="int", default=100, 392 help="Exit after the first N failures instead of " 393 "running all tests. Pass 0 to disable this feature.") 394 parser.add_option("--ci-test-completion", 395 help="Path to a file for logging test completion in the " 396 "context of CI progress indicator. Ignored if " 397 "progress indicator is other than 'ci'.") 398 399 # Rerun 400 parser.add_option("--rerun-failures-count", default=0, type=int, 401 help="Number of times to rerun each failing test case. " 402 "Very slow tests will be rerun only once.") 403 parser.add_option("--rerun-failures-max", default=100, type=int, 404 help="Maximum number of failing test cases to rerun") 405 406 # Test config 407 parser.add_option("--command-prefix", default="", 408 help="Prepended to each shell command used to run a test") 409 parser.add_option('--dont-skip-slow-simulator-tests', 410 help='Don\'t skip more slow tests when using a' 411 ' simulator.', default=False, action='store_true', 412 dest='dont_skip_simulator_slow_tests') 413 parser.add_option("--extra-flags", action="append", default=[], 414 help="Additional flags to pass to each test command") 415 parser.add_option("--isolates", action="store_true", default=False, 416 help="Whether to test isolates") 417 parser.add_option("--no-harness", "--noharness", 418 default=False, action="store_true", 419 help="Run without test harness of a given suite") 420 parser.add_option("--random-seed", default=0, type=int, 421 help="Default seed for initializing random generator") 422 parser.add_option("--run-skipped", help="Also run skipped tests.", 423 default=False, action="store_true") 424 parser.add_option("-t", "--timeout", default=60, type=int, 425 help="Timeout for single test in seconds") 426 parser.add_option("-v", "--verbose", default=False, action="store_true", 427 help="Verbose output") 428 parser.add_option('--regenerate-expected-files', default=False, action='store_true', 429 help='Regenerate expected files') 430 431 # TODO(machenbach): Temporary options for rolling out new test runner 432 # features. 433 parser.add_option("--mastername", default='', 434 help="Mastername property from infrastructure. Not " 435 "setting this option indicates manual usage.") 436 parser.add_option("--buildername", default='', 437 help="Buildername property from infrastructure. Not " 438 "setting this option indicates manual usage.") 439 440 def _add_parser_options(self, parser): 441 pass 442 443 def _parse_args(self, parser, sys_args): 444 options, args = parser.parse_args(sys_args) 445 446 if options.arch and ',' in options.arch: # pragma: no cover 447 print('Multiple architectures are deprecated') 448 raise TestRunnerError() 449 450 return options, args 451 452 def _load_build_config(self, options): 453 for outdir in self._possible_outdirs(options): 454 try: 455 self.build_config = _do_load_build_config(outdir, options.verbose) 456 457 # In auto-detect mode the outdir is always where we found the build config. 458 # This ensures that we'll also take the build products from there. 459 self.outdir = outdir 460 break 461 except TestRunnerError: 462 pass 463 464 if not self.build_config: # pragma: no cover 465 print('Failed to load build config') 466 raise TestRunnerError 467 468 print('Build found: %s' % self.outdir) 469 if str(self.build_config): 470 print('>>> Autodetected:') 471 print(self.build_config) 472 473 # Represents the OS where tests are run on. Same as host OS except for 474 # Android, which is determined by build output. 475 if self.build_config.is_android: 476 self.target_os = 'android' 477 else: 478 self.target_os = utils.GuessOS() 479 480 # Returns possible build paths in order: 481 # gn 482 # outdir 483 # outdir on bots 484 def _possible_outdirs(self, options): 485 def outdirs(): 486 if options.gn: 487 yield self._get_gn_outdir() 488 return 489 490 yield options.outdir 491 492 if os.path.basename(options.outdir) != 'build': 493 yield os.path.join(options.outdir, 'build') 494 495 for outdir in outdirs(): 496 yield os.path.join(self.basedir, outdir) 497 498 def _get_gn_outdir(self): 499 gn_out_dir = os.path.join(self.basedir, DEFAULT_OUT_GN) 500 latest_timestamp = -1 501 latest_config = None 502 for gn_config in os.listdir(gn_out_dir): 503 gn_config_dir = os.path.join(gn_out_dir, gn_config) 504 if not os.path.isdir(gn_config_dir): 505 continue 506 if os.path.getmtime(gn_config_dir) > latest_timestamp: 507 latest_timestamp = os.path.getmtime(gn_config_dir) 508 latest_config = gn_config 509 if latest_config: 510 print(">>> Latest GN build found: %s" % latest_config) 511 return os.path.join(DEFAULT_OUT_GN, latest_config) 512 513 def _process_default_options(self, options): 514 if self.build_config.is_debug: 515 self.mode_options = DEBUG_MODE 516 elif self.build_config.dcheck_always_on: 517 self.mode_options = TRY_RELEASE_MODE 518 else: 519 self.mode_options = RELEASE_MODE 520 521 if options.arch and options.arch != self.build_config.arch: 522 print('--arch value (%s) inconsistent with build config (%s).' % ( 523 options.arch, self.build_config.arch)) 524 raise TestRunnerError() 525 526 if options.shell_dir: # pragma: no cover 527 print('Warning: --shell-dir is deprecated. Searching for executables in ' 528 'build directory (%s) instead.' % self.outdir) 529 530 if options.j == 0: 531 if self.build_config.is_android: 532 # Adb isn't happy about multi-processed file pushing. 533 options.j = 1 534 else: 535 options.j = multiprocessing.cpu_count() 536 537 options.command_prefix = shlex.split(options.command_prefix) 538 options.extra_flags = sum(list(map(shlex.split, options.extra_flags)), []) 539 540 def _process_options(self, options): 541 pass 542 543 def _setup_env(self): 544 # Use the v8 root as cwd as some test cases use "load" with relative paths. 545 os.chdir(self.basedir) 546 547 # Many tests assume an English interface. 548 os.environ['LANG'] = 'en_US.UTF-8' 549 550 symbolizer_option = self._get_external_symbolizer_option() 551 552 if self.build_config.asan: 553 asan_options = [ 554 symbolizer_option, 555 'allow_user_segv_handler=1', 556 'allocator_may_return_null=1', 557 ] 558 if not utils.GuessOS() in ['macos', 'windows']: 559 # LSAN is not available on mac and windows. 560 asan_options.append('detect_leaks=1') 561 else: 562 asan_options.append('detect_leaks=0') 563 if utils.GuessOS() == 'windows': 564 # https://crbug.com/967663 565 asan_options.append('detect_stack_use_after_return=0') 566 os.environ['ASAN_OPTIONS'] = ":".join(asan_options) 567 568 if self.build_config.cfi_vptr: 569 os.environ['UBSAN_OPTIONS'] = ":".join([ 570 'print_stacktrace=1', 571 'print_summary=1', 572 'symbolize=1', 573 symbolizer_option, 574 ]) 575 576 if self.build_config.ubsan_vptr: 577 os.environ['UBSAN_OPTIONS'] = ":".join([ 578 'print_stacktrace=1', 579 symbolizer_option, 580 ]) 581 582 if self.build_config.msan: 583 os.environ['MSAN_OPTIONS'] = symbolizer_option 584 585 if self.build_config.tsan: 586 suppressions_file = os.path.join( 587 self.basedir, 588 'tools', 589 'sanitizers', 590 'tsan_suppressions.txt') 591 os.environ['TSAN_OPTIONS'] = " ".join([ 592 symbolizer_option, 593 'suppressions=%s' % suppressions_file, 594 'exit_code=0', 595 'report_thread_leaks=0', 596 'history_size=7', 597 'report_destroy_locked=0', 598 ]) 599 600 def _get_external_symbolizer_option(self): 601 external_symbolizer_path = os.path.join( 602 self.basedir, 603 'third_party', 604 'llvm-build', 605 'Release+Asserts', 606 'bin', 607 'llvm-symbolizer', 608 ) 609 610 if utils.IsWindows(): 611 # Quote, because sanitizers might confuse colon as option separator. 612 external_symbolizer_path = '"%s.exe"' % external_symbolizer_path 613 614 return 'external_symbolizer_path=%s' % external_symbolizer_path 615 616 def _parse_test_args(self, args): 617 if not args: 618 args = self._get_default_suite_names() 619 620 # Expand arguments with grouped tests. The args should reflect the list 621 # of suites as otherwise filters would break. 622 def expand_test_group(name): 623 return TEST_MAP.get(name, [name]) 624 625 return reduce(list.__add__, list(map(expand_test_group, args)), []) 626 627 def _args_to_suite_names(self, args, test_root): 628 # Use default tests if no test configuration was provided at the cmd line. 629 all_names = set(utils.GetSuitePaths(test_root)) 630 args_names = OrderedDict([(arg.split('/')[0], None) for arg in args]) # set 631 return [name for name in args_names if name in all_names] 632 633 def _get_default_suite_names(self): 634 return [] 635 636 def _load_testsuite_generators(self, args, options): 637 names = self._args_to_suite_names(args, options.test_root) 638 test_config = self._create_test_config(options) 639 variables = self._get_statusfile_variables(options) 640 641 # Head generator with no elements 642 test_chain = testsuite.TestGenerator(0, [], []) 643 for name in names: 644 if options.verbose: 645 print('>>> Loading test suite: %s' % name) 646 suite = testsuite.TestSuite.Load( 647 os.path.join(options.test_root, name), test_config, 648 self.framework_name) 649 650 if self._is_testsuite_supported(suite, options): 651 tests = suite.load_tests_from_disk(variables) 652 test_chain.merge(tests) 653 654 return test_chain 655 656 def _is_testsuite_supported(self, suite, options): 657 """A predicate that can be overridden to filter out unsupported TestSuite 658 instances (see NumFuzzer for usage).""" 659 return True 660 661 def _get_statusfile_variables(self, options): 662 simd_mips = ( 663 self.build_config.arch in ['mipsel', 'mips', 'mips64', 'mips64el'] and 664 self.build_config.mips_arch_variant == "r6" and 665 self.build_config.mips_use_msa) 666 667 mips_arch_variant = ( 668 self.build_config.arch in ['mipsel', 'mips', 'mips64', 'mips64el'] and 669 self.build_config.mips_arch_variant) 670 671 no_simd_hardware = any( 672 i in options.extra_flags for i in ['--noenable-sse3', 673 '--no-enable-sse3', 674 '--noenable-ssse3', 675 '--no-enable-ssse3', 676 '--noenable-sse4-1', 677 '--no-enable-sse4_1']) 678 679 # Set no_simd_hardware on architectures without Simd enabled. 680 if self.build_config.arch == 'mips64el' or \ 681 self.build_config.arch == 'mipsel': 682 no_simd_hardware = not simd_mips 683 684 if self.build_config.arch == 'loong64': 685 no_simd_hardware = True 686 687 # S390 hosts without VEF1 do not support Simd. 688 if self.build_config.arch == 's390x' and \ 689 not self.build_config.simulator_run and \ 690 not utils.IsS390SimdSupported(): 691 no_simd_hardware = True 692 693 # Ppc64 processors earlier than POWER9 do not support Simd instructions 694 if self.build_config.arch == 'ppc64' and \ 695 not self.build_config.simulator_run and \ 696 utils.GuessPowerProcessorVersion() < 9: 697 no_simd_hardware = True 698 699 return { 700 "arch": self.build_config.arch, 701 "asan": self.build_config.asan, 702 "byteorder": sys.byteorder, 703 "cfi_vptr": self.build_config.cfi_vptr, 704 "control_flow_integrity": self.build_config.control_flow_integrity, 705 "concurrent_marking": self.build_config.concurrent_marking, 706 "single_generation": self.build_config.single_generation, 707 "dcheck_always_on": self.build_config.dcheck_always_on, 708 "deopt_fuzzer": False, 709 "endurance_fuzzer": False, 710 "gc_fuzzer": False, 711 "gc_stress": False, 712 "gcov_coverage": self.build_config.gcov_coverage, 713 "has_webassembly": self.build_config.webassembly, 714 "isolates": options.isolates, 715 "is_clang": self.build_config.is_clang, 716 "is_full_debug": self.build_config.is_full_debug, 717 "mips_arch_variant": mips_arch_variant, 718 "mode": self.mode_options.status_mode, 719 "msan": self.build_config.msan, 720 "no_harness": options.no_harness, 721 "no_i18n": self.build_config.no_i18n, 722 "no_simd_hardware": no_simd_hardware, 723 "novfp3": False, 724 "optimize_for_size": "--optimize-for-size" in options.extra_flags, 725 "predictable": self.build_config.predictable, 726 "simd_mips": simd_mips, 727 "simulator_run": self.build_config.simulator_run and 728 not options.dont_skip_simulator_slow_tests, 729 "system": self.target_os, 730 "third_party_heap": self.build_config.third_party_heap, 731 "tsan": self.build_config.tsan, 732 "ubsan_vptr": self.build_config.ubsan_vptr, 733 "verify_csa": self.build_config.verify_csa, 734 "lite_mode": self.build_config.lite_mode, 735 "pointer_compression": self.build_config.pointer_compression, 736 "pointer_compression_shared_cage": self.build_config.pointer_compression_shared_cage, 737 "no_js_shared_memory": (not self.build_config.shared_ro_heap) or 738 (self.build_config.pointer_compression and 739 not self.build_config.pointer_compression_shared_cage), 740 "sandbox": self.build_config.sandbox, 741 "dict_property_const_tracking": self.build_config.dict_property_const_tracking, 742 } 743 744 def _runner_flags(self): 745 """Extra default flags specific to the test runner implementation.""" 746 return [] 747 748 def _create_test_config(self, options): 749 timeout = options.timeout * self._timeout_scalefactor(options) 750 return TestConfig( 751 command_prefix=options.command_prefix, 752 extra_flags=options.extra_flags, 753 isolates=options.isolates, 754 mode_flags=self.mode_options.flags + self._runner_flags(), 755 no_harness=options.no_harness, 756 noi18n=self.build_config.no_i18n, 757 random_seed=options.random_seed, 758 run_skipped=options.run_skipped, 759 shell_dir=self.outdir, 760 timeout=timeout, 761 verbose=options.verbose, 762 regenerate_expected_files=options.regenerate_expected_files, 763 ) 764 765 def _timeout_scalefactor(self, options): 766 """Increases timeout for slow build configurations.""" 767 factor = self.mode_options.timeout_scalefactor 768 if self.build_config.arch in SLOW_ARCHS: 769 factor *= 4.5 770 if self.build_config.lite_mode: 771 factor *= 2 772 if self.build_config.predictable: 773 factor *= 4 774 if self.build_config.tsan: 775 factor *= 2 776 if self.build_config.use_sanitizer: 777 factor *= 1.5 778 if self.build_config.is_full_debug: 779 factor *= 4 780 781 return factor 782 783 # TODO(majeski): remove options & args parameters 784 def _do_execute(self, suites, args, options): 785 raise NotImplementedError() 786 787 def _prepare_procs(self, procs): 788 procs = list([_f for _f in procs if _f]) 789 for i in range(0, len(procs) - 1): 790 procs[i].connect_to(procs[i + 1]) 791 procs[0].setup() 792 793 def _create_shard_proc(self, options): 794 myid, count = self._get_shard_info(options) 795 if count == 1: 796 return None 797 return ShardProc(myid - 1, count) 798 799 def _get_shard_info(self, options): 800 """ 801 Returns pair: 802 (id of the current shard [1; number of shards], number of shards) 803 """ 804 # Read gtest shard configuration from environment (e.g. set by swarming). 805 # If none is present, use values passed on the command line. 806 shard_count = int( 807 os.environ.get('GTEST_TOTAL_SHARDS', options.shard_count)) 808 shard_run = os.environ.get('GTEST_SHARD_INDEX') 809 if shard_run is not None: 810 # The v8 shard_run starts at 1, while GTEST_SHARD_INDEX starts at 0. 811 shard_run = int(shard_run) + 1 812 else: 813 shard_run = options.shard_run 814 815 if options.shard_count > 1: 816 # Log if a value was passed on the cmd line and it differs from the 817 # environment variables. 818 if options.shard_count != shard_count: # pragma: no cover 819 print("shard_count from cmd line differs from environment variable " 820 "GTEST_TOTAL_SHARDS") 821 if (options.shard_run > 1 and 822 options.shard_run != shard_run): # pragma: no cover 823 print("shard_run from cmd line differs from environment variable " 824 "GTEST_SHARD_INDEX") 825 826 if shard_run < 1 or shard_run > shard_count: 827 # TODO(machenbach): Turn this into an assert. If that's wrong on the 828 # bots, printing will be quite useless. Or refactor this code to make 829 # sure we get a return code != 0 after testing if we got here. 830 print("shard-run not a valid number, should be in [1:shard-count]") 831 print("defaulting back to running all tests") 832 return 1, 1 833 834 return shard_run, shard_count 835 836 def _create_progress_indicators(self, test_count, options): 837 procs = [PROGRESS_INDICATORS[options.progress]()] 838 if options.junitout: 839 procs.append(progress.JUnitTestProgressIndicator(options.junitout, 840 options.junittestsuite)) 841 if options.json_test_results: 842 procs.append(progress.JsonTestProgressIndicator(self.framework_name)) 843 844 for proc in procs: 845 proc.configure(options) 846 847 for proc in procs: 848 try: 849 proc.set_test_count(test_count) 850 except AttributeError: 851 pass 852 853 return procs 854 855 def _create_result_tracker(self, options): 856 return progress.ResultsTracker(options.exit_after_n_failures) 857 858 def _create_timeout_proc(self, options): 859 if not options.total_timeout_sec: 860 return None 861 return TimeoutProc(options.total_timeout_sec) 862 863 def _create_signal_proc(self): 864 return SignalProc() 865 866 def _create_rerun_proc(self, options): 867 if not options.rerun_failures_count: 868 return None 869 return RerunProc(options.rerun_failures_count, 870 options.rerun_failures_max) 871