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 5 6from collections import OrderedDict 7import json 8import multiprocessing 9import optparse 10import os 11import shlex 12import sys 13 14 15# Add testrunner to the path. 16sys.path.insert( 17 0, 18 os.path.dirname( 19 os.path.dirname(os.path.abspath(__file__)))) 20 21 22from testrunner.local import command 23from testrunner.local import testsuite 24from testrunner.local import utils 25from testrunner.test_config import TestConfig 26from testrunner.testproc import progress 27from testrunner.testproc.rerun import RerunProc 28from testrunner.testproc.shard import ShardProc 29from testrunner.testproc.sigproc import SignalProc 30from testrunner.testproc.timeout import TimeoutProc 31 32 33BASE_DIR = ( 34 os.path.dirname( 35 os.path.dirname( 36 os.path.dirname( 37 os.path.abspath(__file__))))) 38 39DEFAULT_OUT_GN = 'out.gn' 40 41# Map of test name synonyms to lists of test suites. Should be ordered by 42# expected runtimes (suites with slow test cases first). These groups are 43# invoked in separate steps on the bots. 44TEST_MAP = { 45 # This needs to stay in sync with test/bot_default.isolate. 46 "bot_default": [ 47 "debugger", 48 "mjsunit", 49 "cctest", 50 "wasm-spec-tests", 51 "inspector", 52 "webkit", 53 "mkgrokdump", 54 "fuzzer", 55 "message", 56 "preparser", 57 "intl", 58 "unittests", 59 ], 60 # This needs to stay in sync with test/default.isolate. 61 "default": [ 62 "debugger", 63 "mjsunit", 64 "cctest", 65 "wasm-spec-tests", 66 "inspector", 67 "mkgrokdump", 68 "fuzzer", 69 "message", 70 "preparser", 71 "intl", 72 "unittests", 73 ], 74 # This needs to stay in sync with test/d8_default.isolate. 75 "d8_default": [ 76 # TODO(machenbach): uncomment after infra side lands. 77 #"debugger", 78 "mjsunit", 79 "webkit", 80 #"message", 81 #"preparser", 82 #"intl", 83 ], 84 # This needs to stay in sync with test/optimize_for_size.isolate. 85 "optimize_for_size": [ 86 "debugger", 87 "mjsunit", 88 "cctest", 89 "inspector", 90 "webkit", 91 "intl", 92 ], 93 "unittests": [ 94 "unittests", 95 ], 96} 97 98# Double the timeout for these: 99SLOW_ARCHS = ["arm", 100 "mips", 101 "mipsel", 102 "mips64", 103 "mips64el", 104 "s390", 105 "s390x", 106 "arm64"] 107 108 109class ModeConfig(object): 110 def __init__(self, flags, timeout_scalefactor, status_mode, execution_mode): 111 self.flags = flags 112 self.timeout_scalefactor = timeout_scalefactor 113 self.status_mode = status_mode 114 self.execution_mode = execution_mode 115 116 117DEBUG_FLAGS = ["--nohard-abort", "--enable-slow-asserts", "--verify-heap"] 118RELEASE_FLAGS = ["--nohard-abort"] 119MODES = { 120 "debug": ModeConfig( 121 flags=DEBUG_FLAGS, 122 timeout_scalefactor=4, 123 status_mode="debug", 124 execution_mode="debug", 125 ), 126 "optdebug": ModeConfig( 127 flags=DEBUG_FLAGS, 128 timeout_scalefactor=4, 129 status_mode="debug", 130 execution_mode="debug", 131 ), 132 "release": ModeConfig( 133 flags=RELEASE_FLAGS, 134 timeout_scalefactor=1, 135 status_mode="release", 136 execution_mode="release", 137 ), 138 # Normal trybot release configuration. There, dchecks are always on which 139 # implies debug is set. Hence, the status file needs to assume debug-like 140 # behavior/timeouts. 141 "tryrelease": ModeConfig( 142 flags=RELEASE_FLAGS, 143 timeout_scalefactor=1, 144 status_mode="debug", 145 execution_mode="release", 146 ), 147 # This mode requires v8 to be compiled with dchecks and slow dchecks. 148 "slowrelease": ModeConfig( 149 flags=RELEASE_FLAGS + ["--enable-slow-asserts"], 150 timeout_scalefactor=2, 151 status_mode="debug", 152 execution_mode="release", 153 ), 154} 155 156PROGRESS_INDICATORS = { 157 'verbose': progress.VerboseProgressIndicator, 158 'dots': progress.DotsProgressIndicator, 159 'color': progress.ColorProgressIndicator, 160 'mono': progress.MonochromeProgressIndicator, 161} 162 163class TestRunnerError(Exception): 164 pass 165 166 167class BuildConfig(object): 168 def __init__(self, build_config): 169 # In V8 land, GN's x86 is called ia32. 170 if build_config['v8_target_cpu'] == 'x86': 171 self.arch = 'ia32' 172 else: 173 self.arch = build_config['v8_target_cpu'] 174 175 self.asan = build_config['is_asan'] 176 self.cfi_vptr = build_config['is_cfi'] 177 self.dcheck_always_on = build_config['dcheck_always_on'] 178 self.gcov_coverage = build_config['is_gcov_coverage'] 179 self.is_android = build_config['is_android'] 180 self.is_debug = build_config['is_debug'] 181 self.msan = build_config['is_msan'] 182 self.no_i18n = not build_config['v8_enable_i18n_support'] 183 self.no_snap = not build_config['v8_use_snapshot'] 184 self.predictable = build_config['v8_enable_verify_predictable'] 185 self.tsan = build_config['is_tsan'] 186 self.ubsan_vptr = build_config['is_ubsan_vptr'] 187 # Export only for MIPS target 188 if self.arch in ['mips', 'mipsel', 'mips64', 'mips64el']: 189 self.mips_arch_variant = build_config['mips_arch_variant'] 190 self.mips_use_msa = build_config['mips_use_msa'] 191 192 def __str__(self): 193 detected_options = [] 194 195 if self.asan: 196 detected_options.append('asan') 197 if self.cfi_vptr: 198 detected_options.append('cfi_vptr') 199 if self.dcheck_always_on: 200 detected_options.append('dcheck_always_on') 201 if self.gcov_coverage: 202 detected_options.append('gcov_coverage') 203 if self.msan: 204 detected_options.append('msan') 205 if self.no_i18n: 206 detected_options.append('no_i18n') 207 if self.no_snap: 208 detected_options.append('no_snap') 209 if self.predictable: 210 detected_options.append('predictable') 211 if self.tsan: 212 detected_options.append('tsan') 213 if self.ubsan_vptr: 214 detected_options.append('ubsan_vptr') 215 216 return '\n'.join(detected_options) 217 218 219class BaseTestRunner(object): 220 def __init__(self, basedir=None): 221 self.basedir = basedir or BASE_DIR 222 self.outdir = None 223 self.build_config = None 224 self.mode_name = None 225 self.mode_options = None 226 self.target_os = None 227 228 def execute(self, sys_args=None): 229 if sys_args is None: # pragma: no cover 230 sys_args = sys.argv[1:] 231 try: 232 parser = self._create_parser() 233 options, args = self._parse_args(parser, sys_args) 234 if options.swarming: 235 # Swarming doesn't print how isolated commands are called. Lets make 236 # this less cryptic by printing it ourselves. 237 print ' '.join(sys.argv) 238 239 self._load_build_config(options) 240 command.setup(self.target_os) 241 242 try: 243 self._process_default_options(options) 244 self._process_options(options) 245 except TestRunnerError: 246 parser.print_help() 247 raise 248 249 args = self._parse_test_args(args) 250 suites = self._get_suites(args, options) 251 self._prepare_suites(suites, options) 252 253 self._setup_env() 254 255 print(">>> Running tests for %s.%s" % (self.build_config.arch, 256 self.mode_name)) 257 tests = [t for s in suites for t in s.tests] 258 return self._do_execute(tests, args, options) 259 except TestRunnerError: 260 return utils.EXIT_CODE_INTERNAL_ERROR 261 except KeyboardInterrupt: 262 return utils.EXIT_CODE_INTERRUPTED 263 finally: 264 command.tear_down() 265 266 def _create_parser(self): 267 parser = optparse.OptionParser() 268 parser.usage = '%prog [options] [tests]' 269 parser.description = """TESTS: %s""" % (TEST_MAP["default"]) 270 self._add_parser_default_options(parser) 271 self._add_parser_options(parser) 272 return parser 273 274 def _add_parser_default_options(self, parser): 275 parser.add_option("--gn", help="Scan out.gn for the last built" 276 " configuration", 277 default=False, action="store_true") 278 parser.add_option("--outdir", help="Base directory with compile output", 279 default="out") 280 parser.add_option("--buildbot", help="DEPRECATED!", 281 default=False, action="store_true") 282 parser.add_option("--arch", 283 help="The architecture to run tests for") 284 parser.add_option("-m", "--mode", 285 help="The test mode in which to run (uppercase for ninja" 286 " and buildbot builds): %s" % MODES.keys()) 287 parser.add_option("--shell-dir", help="DEPRECATED! Executables from build " 288 "directory will be used") 289 parser.add_option("--test-root", help="Root directory of the test suites", 290 default=os.path.join(self.basedir, 'test')) 291 parser.add_option("--total-timeout-sec", default=0, type="int", 292 help="How long should fuzzer run") 293 parser.add_option("--swarming", default=False, action="store_true", 294 help="Indicates running test driver on swarming.") 295 296 parser.add_option("-j", help="The number of parallel tasks to run", 297 default=0, type=int) 298 299 # Shard 300 parser.add_option("--shard-count", default=1, type=int, 301 help="Split tests into this number of shards") 302 parser.add_option("--shard-run", default=1, type=int, 303 help="Run this shard from the split up tests.") 304 305 # Progress 306 parser.add_option("-p", "--progress", 307 choices=PROGRESS_INDICATORS.keys(), default="mono", 308 help="The style of progress indicator (verbose, dots, " 309 "color, mono)") 310 parser.add_option("--json-test-results", 311 help="Path to a file for storing json results.") 312 parser.add_option("--junitout", help="File name of the JUnit output") 313 parser.add_option("--junittestsuite", default="v8tests", 314 help="The testsuite name in the JUnit output file") 315 316 # Rerun 317 parser.add_option("--rerun-failures-count", default=0, type=int, 318 help="Number of times to rerun each failing test case. " 319 "Very slow tests will be rerun only once.") 320 parser.add_option("--rerun-failures-max", default=100, type=int, 321 help="Maximum number of failing test cases to rerun") 322 323 # Test config 324 parser.add_option("--command-prefix", default="", 325 help="Prepended to each shell command used to run a test") 326 parser.add_option("--extra-flags", action="append", default=[], 327 help="Additional flags to pass to each test command") 328 parser.add_option("--isolates", action="store_true", default=False, 329 help="Whether to test isolates") 330 parser.add_option("--no-harness", "--noharness", 331 default=False, action="store_true", 332 help="Run without test harness of a given suite") 333 parser.add_option("--random-seed", default=0, type=int, 334 help="Default seed for initializing random generator") 335 parser.add_option("-t", "--timeout", default=60, type=int, 336 help="Timeout for single test in seconds") 337 parser.add_option("-v", "--verbose", default=False, action="store_true", 338 help="Verbose output") 339 340 # TODO(machenbach): Temporary options for rolling out new test runner 341 # features. 342 parser.add_option("--mastername", default='', 343 help="Mastername property from infrastructure. Not " 344 "setting this option indicates manual usage.") 345 parser.add_option("--buildername", default='', 346 help="Buildername property from infrastructure. Not " 347 "setting this option indicates manual usage.") 348 349 def _add_parser_options(self, parser): 350 pass 351 352 def _parse_args(self, parser, sys_args): 353 options, args = parser.parse_args(sys_args) 354 355 if any(map(lambda v: v and ',' in v, 356 [options.arch, options.mode])): # pragma: no cover 357 print 'Multiple arch/mode are deprecated' 358 raise TestRunnerError() 359 360 return options, args 361 362 def _load_build_config(self, options): 363 for outdir in self._possible_outdirs(options): 364 try: 365 self.build_config = self._do_load_build_config(outdir, options.verbose) 366 except TestRunnerError: 367 pass 368 369 if not self.build_config: # pragma: no cover 370 print 'Failed to load build config' 371 raise TestRunnerError 372 373 print 'Build found: %s' % self.outdir 374 if str(self.build_config): 375 print '>>> Autodetected:' 376 print self.build_config 377 378 # Represents the OS where tests are run on. Same as host OS except for 379 # Android, which is determined by build output. 380 if self.build_config.is_android: 381 self.target_os = 'android' 382 else: 383 self.target_os = utils.GuessOS() 384 385 # Returns possible build paths in order: 386 # gn 387 # outdir 388 # outdir/arch.mode 389 # Each path is provided in two versions: <path> and <path>/mode for buildbot. 390 def _possible_outdirs(self, options): 391 def outdirs(): 392 if options.gn: 393 yield self._get_gn_outdir() 394 return 395 396 yield options.outdir 397 if options.arch and options.mode: 398 yield os.path.join(options.outdir, 399 '%s.%s' % (options.arch, options.mode)) 400 401 for outdir in outdirs(): 402 yield os.path.join(self.basedir, outdir) 403 404 # buildbot option 405 if options.mode: 406 yield os.path.join(self.basedir, outdir, options.mode) 407 408 def _get_gn_outdir(self): 409 gn_out_dir = os.path.join(self.basedir, DEFAULT_OUT_GN) 410 latest_timestamp = -1 411 latest_config = None 412 for gn_config in os.listdir(gn_out_dir): 413 gn_config_dir = os.path.join(gn_out_dir, gn_config) 414 if not os.path.isdir(gn_config_dir): 415 continue 416 if os.path.getmtime(gn_config_dir) > latest_timestamp: 417 latest_timestamp = os.path.getmtime(gn_config_dir) 418 latest_config = gn_config 419 if latest_config: 420 print(">>> Latest GN build found: %s" % latest_config) 421 return os.path.join(DEFAULT_OUT_GN, latest_config) 422 423 def _do_load_build_config(self, outdir, verbose=False): 424 build_config_path = os.path.join(outdir, "v8_build_config.json") 425 if not os.path.exists(build_config_path): 426 if verbose: 427 print("Didn't find build config: %s" % build_config_path) 428 raise TestRunnerError() 429 430 with open(build_config_path) as f: 431 try: 432 build_config_json = json.load(f) 433 except Exception: # pragma: no cover 434 print("%s exists but contains invalid json. Is your build up-to-date?" 435 % build_config_path) 436 raise TestRunnerError() 437 438 # In auto-detect mode the outdir is always where we found the build config. 439 # This ensures that we'll also take the build products from there. 440 self.outdir = os.path.dirname(build_config_path) 441 442 return BuildConfig(build_config_json) 443 444 def _process_default_options(self, options): 445 # We don't use the mode for more path-magic. 446 # Therefore transform the buildbot mode here to fix build_config value. 447 if options.mode: 448 options.mode = self._buildbot_to_v8_mode(options.mode) 449 450 build_config_mode = 'debug' if self.build_config.is_debug else 'release' 451 if options.mode: 452 if options.mode not in MODES: # pragma: no cover 453 print '%s mode is invalid' % options.mode 454 raise TestRunnerError() 455 if MODES[options.mode].execution_mode != build_config_mode: 456 print ('execution mode (%s) for %s is inconsistent with build config ' 457 '(%s)' % ( 458 MODES[options.mode].execution_mode, 459 options.mode, 460 build_config_mode)) 461 raise TestRunnerError() 462 463 self.mode_name = options.mode 464 else: 465 self.mode_name = build_config_mode 466 467 self.mode_options = MODES[self.mode_name] 468 469 if options.arch and options.arch != self.build_config.arch: 470 print('--arch value (%s) inconsistent with build config (%s).' % ( 471 options.arch, self.build_config.arch)) 472 raise TestRunnerError() 473 474 if options.shell_dir: # pragma: no cover 475 print('Warning: --shell-dir is deprecated. Searching for executables in ' 476 'build directory (%s) instead.' % self.outdir) 477 478 if options.j == 0: 479 if self.build_config.is_android: 480 # Adb isn't happy about multi-processed file pushing. 481 options.j = 1 482 else: 483 options.j = multiprocessing.cpu_count() 484 485 options.command_prefix = shlex.split(options.command_prefix) 486 options.extra_flags = sum(map(shlex.split, options.extra_flags), []) 487 488 def _buildbot_to_v8_mode(self, config): 489 """Convert buildbot build configs to configs understood by the v8 runner. 490 491 V8 configs are always lower case and without the additional _x64 suffix 492 for 64 bit builds on windows with ninja. 493 """ 494 mode = config[:-4] if config.endswith('_x64') else config 495 return mode.lower() 496 497 def _process_options(self, options): 498 pass 499 500 def _setup_env(self): 501 # Use the v8 root as cwd as some test cases use "load" with relative paths. 502 os.chdir(self.basedir) 503 504 # Many tests assume an English interface. 505 os.environ['LANG'] = 'en_US.UTF-8' 506 507 symbolizer_option = self._get_external_symbolizer_option() 508 509 if self.build_config.asan: 510 asan_options = [ 511 symbolizer_option, 512 'allow_user_segv_handler=1', 513 'allocator_may_return_null=1', 514 ] 515 if not utils.GuessOS() in ['macos', 'windows']: 516 # LSAN is not available on mac and windows. 517 asan_options.append('detect_leaks=1') 518 else: 519 asan_options.append('detect_leaks=0') 520 os.environ['ASAN_OPTIONS'] = ":".join(asan_options) 521 522 if self.build_config.cfi_vptr: 523 os.environ['UBSAN_OPTIONS'] = ":".join([ 524 'print_stacktrace=1', 525 'print_summary=1', 526 'symbolize=1', 527 symbolizer_option, 528 ]) 529 530 if self.build_config.ubsan_vptr: 531 os.environ['UBSAN_OPTIONS'] = ":".join([ 532 'print_stacktrace=1', 533 symbolizer_option, 534 ]) 535 536 if self.build_config.msan: 537 os.environ['MSAN_OPTIONS'] = symbolizer_option 538 539 if self.build_config.tsan: 540 suppressions_file = os.path.join( 541 self.basedir, 542 'tools', 543 'sanitizers', 544 'tsan_suppressions.txt') 545 os.environ['TSAN_OPTIONS'] = " ".join([ 546 symbolizer_option, 547 'suppressions=%s' % suppressions_file, 548 'exit_code=0', 549 'report_thread_leaks=0', 550 'history_size=7', 551 'report_destroy_locked=0', 552 ]) 553 554 def _get_external_symbolizer_option(self): 555 external_symbolizer_path = os.path.join( 556 self.basedir, 557 'third_party', 558 'llvm-build', 559 'Release+Asserts', 560 'bin', 561 'llvm-symbolizer', 562 ) 563 564 if utils.IsWindows(): 565 # Quote, because sanitizers might confuse colon as option separator. 566 external_symbolizer_path = '"%s.exe"' % external_symbolizer_path 567 568 return 'external_symbolizer_path=%s' % external_symbolizer_path 569 570 def _parse_test_args(self, args): 571 if not args: 572 args = self._get_default_suite_names() 573 574 # Expand arguments with grouped tests. The args should reflect the list 575 # of suites as otherwise filters would break. 576 def expand_test_group(name): 577 return TEST_MAP.get(name, [name]) 578 579 return reduce(list.__add__, map(expand_test_group, args), []) 580 581 def _get_suites(self, args, options): 582 names = self._args_to_suite_names(args, options.test_root) 583 return self._load_suites(names, options) 584 585 def _args_to_suite_names(self, args, test_root): 586 # Use default tests if no test configuration was provided at the cmd line. 587 all_names = set(utils.GetSuitePaths(test_root)) 588 args_names = OrderedDict([(arg.split('/')[0], None) for arg in args]) # set 589 return [name for name in args_names if name in all_names] 590 591 def _get_default_suite_names(self): 592 return [] 593 594 def _load_suites(self, names, options): 595 test_config = self._create_test_config(options) 596 def load_suite(name): 597 if options.verbose: 598 print '>>> Loading test suite: %s' % name 599 return testsuite.TestSuite.LoadTestSuite( 600 os.path.join(options.test_root, name), 601 test_config) 602 return map(load_suite, names) 603 604 def _prepare_suites(self, suites, options): 605 self._load_status_files(suites, options) 606 for s in suites: 607 s.ReadTestCases() 608 609 def _load_status_files(self, suites, options): 610 # simd_mips is true if SIMD is fully supported on MIPS 611 variables = self._get_statusfile_variables(options) 612 for s in suites: 613 s.ReadStatusFile(variables) 614 615 def _get_statusfile_variables(self, options): 616 simd_mips = ( 617 self.build_config.arch in ['mipsel', 'mips', 'mips64', 'mips64el'] and 618 self.build_config.mips_arch_variant == "r6" and 619 self.build_config.mips_use_msa) 620 621 mips_arch_variant = ( 622 self.build_config.arch in ['mipsel', 'mips', 'mips64', 'mips64el'] and 623 self.build_config.mips_arch_variant) 624 625 # TODO(all): Combine "simulator" and "simulator_run". 626 # TODO(machenbach): In GN we can derive simulator run from 627 # target_arch != v8_target_arch in the dumped build config. 628 return { 629 "arch": self.build_config.arch, 630 "asan": self.build_config.asan, 631 "byteorder": sys.byteorder, 632 "dcheck_always_on": self.build_config.dcheck_always_on, 633 "deopt_fuzzer": False, 634 "endurance_fuzzer": False, 635 "gc_fuzzer": False, 636 "gc_stress": False, 637 "gcov_coverage": self.build_config.gcov_coverage, 638 "isolates": options.isolates, 639 "mips_arch_variant": mips_arch_variant, 640 "mode": self.mode_options.status_mode, 641 "msan": self.build_config.msan, 642 "no_harness": options.no_harness, 643 "no_i18n": self.build_config.no_i18n, 644 "no_snap": self.build_config.no_snap, 645 "novfp3": False, 646 "predictable": self.build_config.predictable, 647 "simd_mips": simd_mips, 648 "simulator": utils.UseSimulator(self.build_config.arch), 649 "simulator_run": False, 650 "system": self.target_os, 651 "tsan": self.build_config.tsan, 652 "ubsan_vptr": self.build_config.ubsan_vptr, 653 } 654 655 def _create_test_config(self, options): 656 timeout = options.timeout * self._timeout_scalefactor(options) 657 return TestConfig( 658 command_prefix=options.command_prefix, 659 extra_flags=options.extra_flags, 660 isolates=options.isolates, 661 mode_flags=self.mode_options.flags, 662 no_harness=options.no_harness, 663 noi18n=self.build_config.no_i18n, 664 random_seed=options.random_seed, 665 shell_dir=self.outdir, 666 timeout=timeout, 667 verbose=options.verbose, 668 ) 669 670 def _timeout_scalefactor(self, options): 671 factor = self.mode_options.timeout_scalefactor 672 673 # Simulators are slow, therefore allow a longer timeout. 674 if self.build_config.arch in SLOW_ARCHS: 675 factor *= 2 676 677 # Predictable mode is slower. 678 if self.build_config.predictable: 679 factor *= 2 680 681 return factor 682 683 # TODO(majeski): remove options & args parameters 684 def _do_execute(self, suites, args, options): 685 raise NotImplementedError() 686 687 def _prepare_procs(self, procs): 688 procs = filter(None, procs) 689 for i in xrange(0, len(procs) - 1): 690 procs[i].connect_to(procs[i + 1]) 691 procs[0].setup() 692 693 def _create_shard_proc(self, options): 694 myid, count = self._get_shard_info(options) 695 if count == 1: 696 return None 697 return ShardProc(myid - 1, count) 698 699 def _get_shard_info(self, options): 700 """ 701 Returns pair: 702 (id of the current shard [1; number of shards], number of shards) 703 """ 704 # Read gtest shard configuration from environment (e.g. set by swarming). 705 # If none is present, use values passed on the command line. 706 shard_count = int( 707 os.environ.get('GTEST_TOTAL_SHARDS', options.shard_count)) 708 shard_run = os.environ.get('GTEST_SHARD_INDEX') 709 if shard_run is not None: 710 # The v8 shard_run starts at 1, while GTEST_SHARD_INDEX starts at 0. 711 shard_run = int(shard_run) + 1 712 else: 713 shard_run = options.shard_run 714 715 if options.shard_count > 1: 716 # Log if a value was passed on the cmd line and it differs from the 717 # environment variables. 718 if options.shard_count != shard_count: # pragma: no cover 719 print("shard_count from cmd line differs from environment variable " 720 "GTEST_TOTAL_SHARDS") 721 if (options.shard_run > 1 and 722 options.shard_run != shard_run): # pragma: no cover 723 print("shard_run from cmd line differs from environment variable " 724 "GTEST_SHARD_INDEX") 725 726 if shard_run < 1 or shard_run > shard_count: 727 # TODO(machenbach): Turn this into an assert. If that's wrong on the 728 # bots, printing will be quite useless. Or refactor this code to make 729 # sure we get a return code != 0 after testing if we got here. 730 print "shard-run not a valid number, should be in [1:shard-count]" 731 print "defaulting back to running all tests" 732 return 1, 1 733 734 return shard_run, shard_count 735 736 def _create_progress_indicators(self, options): 737 procs = [PROGRESS_INDICATORS[options.progress]()] 738 if options.junitout: 739 procs.append(progress.JUnitTestProgressIndicator(options.junitout, 740 options.junittestsuite)) 741 if options.json_test_results: 742 procs.append(progress.JsonTestProgressIndicator( 743 options.json_test_results, 744 self.build_config.arch, 745 self.mode_options.execution_mode)) 746 return procs 747 748 def _create_timeout_proc(self, options): 749 if not options.total_timeout_sec: 750 return None 751 return TimeoutProc(options.total_timeout_sec) 752 753 def _create_signal_proc(self): 754 return SignalProc() 755 756 def _create_rerun_proc(self, options): 757 if not options.rerun_failures_count: 758 return None 759 return RerunProc(options.rerun_failures_count, 760 options.rerun_failures_max) 761