|
6 | 6 | from __future__ import print_function |
7 | 7 | from functools import reduce |
8 | 8 |
|
9 | | -from collections import OrderedDict |
| 9 | +from collections import OrderedDict, namedtuple |
10 | 10 | import json |
11 | 11 | import multiprocessing |
12 | 12 | import optparse |
|
115 | 115 | ] |
116 | 116 |
|
117 | 117 |
|
118 | | -class ModeConfig(object): |
119 | | - def __init__(self, flags, timeout_scalefactor, status_mode, execution_mode): |
120 | | - self.flags = flags |
121 | | - self.timeout_scalefactor = timeout_scalefactor |
122 | | - self.status_mode = status_mode |
123 | | - self.execution_mode = execution_mode |
124 | | - |
| 118 | +ModeConfig = namedtuple( |
| 119 | + 'ModeConfig', 'label flags timeout_scalefactor status_mode') |
125 | 120 |
|
126 | 121 | DEBUG_FLAGS = ["--nohard-abort", "--enable-slow-asserts", "--verify-heap"] |
127 | 122 | RELEASE_FLAGS = ["--nohard-abort"] |
128 | | -MODES = { |
129 | | - "debug": ModeConfig( |
130 | | - flags=DEBUG_FLAGS, |
131 | | - timeout_scalefactor=4, |
132 | | - status_mode="debug", |
133 | | - execution_mode="debug", |
134 | | - ), |
135 | | - "optdebug": ModeConfig( |
| 123 | + |
| 124 | +DEBUG_MODE = ModeConfig( |
| 125 | + label='debug', |
136 | 126 | flags=DEBUG_FLAGS, |
137 | 127 | timeout_scalefactor=4, |
138 | 128 | status_mode="debug", |
139 | | - execution_mode="debug", |
140 | | - ), |
141 | | - "release": ModeConfig( |
| 129 | +) |
| 130 | + |
| 131 | +RELEASE_MODE = ModeConfig( |
| 132 | + label='release', |
142 | 133 | flags=RELEASE_FLAGS, |
143 | 134 | timeout_scalefactor=1, |
144 | 135 | status_mode="release", |
145 | | - execution_mode="release", |
146 | | - ), |
147 | | - # Normal trybot release configuration. There, dchecks are always on which |
148 | | - # implies debug is set. Hence, the status file needs to assume debug-like |
149 | | - # behavior/timeouts. |
150 | | - "tryrelease": ModeConfig( |
| 136 | +) |
| 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 | +TRY_RELEASE_MODE = ModeConfig( |
| 142 | + label='release+dchecks', |
151 | 143 | flags=RELEASE_FLAGS, |
152 | | - timeout_scalefactor=1, |
153 | | - status_mode="debug", |
154 | | - execution_mode="release", |
155 | | - ), |
156 | | - # This mode requires v8 to be compiled with dchecks and slow dchecks. |
157 | | - "slowrelease": ModeConfig( |
158 | | - flags=RELEASE_FLAGS + ["--enable-slow-asserts"], |
159 | | - timeout_scalefactor=2, |
| 144 | + timeout_scalefactor=4, |
160 | 145 | status_mode="debug", |
161 | | - execution_mode="release", |
162 | | - ), |
163 | | -} |
| 146 | +) |
164 | 147 |
|
165 | 148 | PROGRESS_INDICATORS = { |
166 | 149 | 'verbose': progress.VerboseProgressIndicator, |
@@ -240,12 +223,29 @@ def __str__(self): |
240 | 223 | return '\n'.join(detected_options) |
241 | 224 |
|
242 | 225 |
|
| 226 | +def _do_load_build_config(outdir, verbose=False): |
| 227 | + build_config_path = os.path.join(outdir, "v8_build_config.json") |
| 228 | + if not os.path.exists(build_config_path): |
| 229 | + if verbose: |
| 230 | + print("Didn't find build config: %s" % build_config_path) |
| 231 | + raise TestRunnerError() |
| 232 | + |
| 233 | + with open(build_config_path) as f: |
| 234 | + try: |
| 235 | + build_config_json = json.load(f) |
| 236 | + except Exception: # pragma: no cover |
| 237 | + print("%s exists but contains invalid json. Is your build up-to-date?" |
| 238 | + % build_config_path) |
| 239 | + raise TestRunnerError() |
| 240 | + |
| 241 | + return BuildConfig(build_config_json) |
| 242 | + |
| 243 | + |
243 | 244 | class BaseTestRunner(object): |
244 | 245 | def __init__(self, basedir=None): |
245 | 246 | self.basedir = basedir or BASE_DIR |
246 | 247 | self.outdir = None |
247 | 248 | self.build_config = None |
248 | | - self.mode_name = None |
249 | 249 | self.mode_options = None |
250 | 250 | self.target_os = None |
251 | 251 |
|
@@ -279,7 +279,7 @@ def execute(self, sys_args=None): |
279 | 279 | tests = self._load_testsuite_generators(args, options) |
280 | 280 | self._setup_env() |
281 | 281 | print(">>> Running tests for %s.%s" % (self.build_config.arch, |
282 | | - self.mode_name)) |
| 282 | + self.mode_options.label)) |
283 | 283 | exit_code = self._do_execute(tests, args, options) |
284 | 284 | if exit_code == utils.EXIT_CODE_FAILURES and options.json_test_results: |
285 | 285 | print("Force exit code 0 after failures. Json test results file " |
@@ -313,9 +313,6 @@ def _add_parser_default_options(self, parser): |
313 | 313 | default="out") |
314 | 314 | parser.add_option("--arch", |
315 | 315 | help="The architecture to run tests for") |
316 | | - parser.add_option("-m", "--mode", |
317 | | - help="The test mode in which to run (uppercase for builds" |
318 | | - " in CI): %s" % MODES.keys()) |
319 | 316 | parser.add_option("--shell-dir", help="DEPRECATED! Executables from build " |
320 | 317 | "directory will be used") |
321 | 318 | parser.add_option("--test-root", help="Root directory of the test suites", |
@@ -400,17 +397,21 @@ def _add_parser_options(self, parser): |
400 | 397 | def _parse_args(self, parser, sys_args): |
401 | 398 | options, args = parser.parse_args(sys_args) |
402 | 399 |
|
403 | | - if any(map(lambda v: v and ',' in v, |
404 | | - [options.arch, options.mode])): # pragma: no cover |
405 | | - print('Multiple arch/mode are deprecated') |
| 400 | + if options.arch and ',' in options.arch: # pragma: no cover |
| 401 | + print('Multiple architectures are deprecated') |
406 | 402 | raise TestRunnerError() |
407 | 403 |
|
408 | 404 | return options, args |
409 | 405 |
|
410 | 406 | def _load_build_config(self, options): |
411 | 407 | for outdir in self._possible_outdirs(options): |
412 | 408 | try: |
413 | | - self.build_config = self._do_load_build_config(outdir, options.verbose) |
| 409 | + self.build_config = _do_load_build_config(outdir, options.verbose) |
| 410 | + |
| 411 | + # In auto-detect mode the outdir is always where we found the build config. |
| 412 | + # This ensures that we'll also take the build products from there. |
| 413 | + self.outdir = outdir |
| 414 | + break |
414 | 415 | except TestRunnerError: |
415 | 416 | pass |
416 | 417 |
|
@@ -433,26 +434,21 @@ def _load_build_config(self, options): |
433 | 434 | # Returns possible build paths in order: |
434 | 435 | # gn |
435 | 436 | # outdir |
436 | | - # outdir/arch.mode |
437 | | - # Each path is provided in two versions: <path> and <path>/mode for bots. |
| 437 | + # outdir on bots |
438 | 438 | def _possible_outdirs(self, options): |
439 | 439 | def outdirs(): |
440 | 440 | if options.gn: |
441 | 441 | yield self._get_gn_outdir() |
442 | 442 | return |
443 | 443 |
|
444 | 444 | yield options.outdir |
445 | | - if options.arch and options.mode: |
446 | | - yield os.path.join(options.outdir, |
447 | | - '%s.%s' % (options.arch, options.mode)) |
| 445 | + |
| 446 | + if os.path.basename(options.outdir) != 'build': |
| 447 | + yield os.path.join(options.outdir, 'build') |
448 | 448 |
|
449 | 449 | for outdir in outdirs(): |
450 | 450 | yield os.path.join(self.basedir, outdir) |
451 | 451 |
|
452 | | - # bot option |
453 | | - if options.mode: |
454 | | - yield os.path.join(self.basedir, outdir, options.mode) |
455 | | - |
456 | 452 | def _get_gn_outdir(self): |
457 | 453 | gn_out_dir = os.path.join(self.basedir, DEFAULT_OUT_GN) |
458 | 454 | latest_timestamp = -1 |
@@ -468,51 +464,13 @@ def _get_gn_outdir(self): |
468 | 464 | print(">>> Latest GN build found: %s" % latest_config) |
469 | 465 | return os.path.join(DEFAULT_OUT_GN, latest_config) |
470 | 466 |
|
471 | | - def _do_load_build_config(self, outdir, verbose=False): |
472 | | - build_config_path = os.path.join(outdir, "v8_build_config.json") |
473 | | - if not os.path.exists(build_config_path): |
474 | | - if verbose: |
475 | | - print("Didn't find build config: %s" % build_config_path) |
476 | | - raise TestRunnerError() |
477 | | - |
478 | | - with open(build_config_path) as f: |
479 | | - try: |
480 | | - build_config_json = json.load(f) |
481 | | - except Exception: # pragma: no cover |
482 | | - print("%s exists but contains invalid json. Is your build up-to-date?" |
483 | | - % build_config_path) |
484 | | - raise TestRunnerError() |
485 | | - |
486 | | - # In auto-detect mode the outdir is always where we found the build config. |
487 | | - # This ensures that we'll also take the build products from there. |
488 | | - self.outdir = os.path.dirname(build_config_path) |
489 | | - |
490 | | - return BuildConfig(build_config_json) |
491 | | - |
492 | 467 | def _process_default_options(self, options): |
493 | | - # We don't use the mode for more path-magic. |
494 | | - # Therefore transform the bot mode here to fix build_config value. |
495 | | - if options.mode: |
496 | | - options.mode = self._bot_to_v8_mode(options.mode) |
497 | | - |
498 | | - build_config_mode = 'debug' if self.build_config.is_debug else 'release' |
499 | | - if options.mode: |
500 | | - if options.mode not in MODES: # pragma: no cover |
501 | | - print('%s mode is invalid' % options.mode) |
502 | | - raise TestRunnerError() |
503 | | - if MODES[options.mode].execution_mode != build_config_mode: |
504 | | - print ('execution mode (%s) for %s is inconsistent with build config ' |
505 | | - '(%s)' % ( |
506 | | - MODES[options.mode].execution_mode, |
507 | | - options.mode, |
508 | | - build_config_mode)) |
509 | | - raise TestRunnerError() |
510 | | - |
511 | | - self.mode_name = options.mode |
| 468 | + if self.build_config.is_debug: |
| 469 | + self.mode_options = DEBUG_MODE |
| 470 | + elif self.build_config.dcheck_always_on: |
| 471 | + self.mode_options = TRY_RELEASE_MODE |
512 | 472 | else: |
513 | | - self.mode_name = build_config_mode |
514 | | - |
515 | | - self.mode_options = MODES[self.mode_name] |
| 473 | + self.mode_options = RELEASE_MODE |
516 | 474 |
|
517 | 475 | if options.arch and options.arch != self.build_config.arch: |
518 | 476 | print('--arch value (%s) inconsistent with build config (%s).' % ( |
@@ -533,15 +491,6 @@ def _process_default_options(self, options): |
533 | 491 | options.command_prefix = shlex.split(options.command_prefix) |
534 | 492 | options.extra_flags = sum(map(shlex.split, options.extra_flags), []) |
535 | 493 |
|
536 | | - def _bot_to_v8_mode(self, config): |
537 | | - """Convert build configs from bots to configs understood by the v8 runner. |
538 | | -
|
539 | | - V8 configs are always lower case and without the additional _x64 suffix |
540 | | - for 64 bit builds on windows with ninja. |
541 | | - """ |
542 | | - mode = config[:-4] if config.endswith('_x64') else config |
543 | | - return mode.lower() |
544 | | - |
545 | 494 | def _process_options(self, options): |
546 | 495 | pass |
547 | 496 |
|
@@ -689,9 +638,7 @@ def _get_statusfile_variables(self, options): |
689 | 638 | "is_clang": self.build_config.is_clang, |
690 | 639 | "is_full_debug": self.build_config.is_full_debug, |
691 | 640 | "mips_arch_variant": mips_arch_variant, |
692 | | - "mode": self.mode_options.status_mode |
693 | | - if not self.build_config.dcheck_always_on |
694 | | - else "debug", |
| 641 | + "mode": self.mode_options.status_mode, |
695 | 642 | "msan": self.build_config.msan, |
696 | 643 | "no_harness": options.no_harness, |
697 | 644 | "no_i18n": self.build_config.no_i18n, |
@@ -804,10 +751,7 @@ def _create_progress_indicators(self, test_count, options): |
804 | 751 | procs.append(progress.JUnitTestProgressIndicator(options.junitout, |
805 | 752 | options.junittestsuite)) |
806 | 753 | if options.json_test_results: |
807 | | - procs.append(progress.JsonTestProgressIndicator( |
808 | | - self.framework_name, |
809 | | - self.build_config.arch, |
810 | | - self.mode_options.execution_mode)) |
| 754 | + procs.append(progress.JsonTestProgressIndicator(self.framework_name)) |
811 | 755 |
|
812 | 756 | for proc in procs: |
813 | 757 | proc.configure(options) |
|