| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2012 the V8 project authors. All rights reserved. | 3 # Copyright 2012 the V8 project authors. All rights reserved. |
| 4 # Redistribution and use in source and binary forms, with or without | 4 # Redistribution and use in source and binary forms, with or without |
| 5 # modification, are permitted provided that the following conditions are | 5 # modification, are permitted provided that the following conditions are |
| 6 # met: | 6 # met: |
| 7 # | 7 # |
| 8 # * Redistributions of source code must retain the above copyright | 8 # * Redistributions of source code must retain the above copyright |
| 9 # notice, this list of conditions and the following disclaimer. | 9 # notice, this list of conditions and the following disclaimer. |
| 10 # * Redistributions in binary form must reproduce the above | 10 # * Redistributions in binary form must reproduce the above |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | 29 |
| 30 | 30 |
| 31 import itertools |
| 31 import multiprocessing | 32 import multiprocessing |
| 32 import optparse | 33 import optparse |
| 33 import os | 34 import os |
| 34 from os.path import join | 35 from os.path import join |
| 35 import shlex | 36 import shlex |
| 36 import subprocess | 37 import subprocess |
| 37 import sys | 38 import sys |
| 38 import time | 39 import time |
| 39 | 40 |
| 40 from testrunner.local import execution | 41 from testrunner.local import execution |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 help="Architecture and mode in the format 'arch.mode'", | 89 help="Architecture and mode in the format 'arch.mode'", |
| 89 default=None) | 90 default=None) |
| 90 result.add_option("--buildbot", | 91 result.add_option("--buildbot", |
| 91 help="Adapt to path structure used on buildbots", | 92 help="Adapt to path structure used on buildbots", |
| 92 default=False, action="store_true") | 93 default=False, action="store_true") |
| 93 result.add_option("--cat", help="Print the source of the tests", | 94 result.add_option("--cat", help="Print the source of the tests", |
| 94 default=False, action="store_true") | 95 default=False, action="store_true") |
| 95 result.add_option("--flaky-tests", | 96 result.add_option("--flaky-tests", |
| 96 help="Regard tests marked as flaky (run|skip|dontcare)", | 97 help="Regard tests marked as flaky (run|skip|dontcare)", |
| 97 default="dontcare") | 98 default="dontcare") |
| 99 result.add_option("--slow-tests", |
| 100 help="Regard slow tests (run|skip|dontcare)", |
| 101 default="dontcare") |
| 102 result.add_option("--pass-fail-tests", |
| 103 help="Regard pass|fail tests (run|skip|dontcare)", |
| 104 default="dontcare") |
| 98 result.add_option("--command-prefix", | 105 result.add_option("--command-prefix", |
| 99 help="Prepended to each shell command used to run a test", | 106 help="Prepended to each shell command used to run a test", |
| 100 default="") | 107 default="") |
| 101 result.add_option("--download-data", help="Download missing test suite data", | 108 result.add_option("--download-data", help="Download missing test suite data", |
| 102 default=False, action="store_true") | 109 default=False, action="store_true") |
| 103 result.add_option("--extra-flags", | 110 result.add_option("--extra-flags", |
| 104 help="Additional flags to pass to each test command", | 111 help="Additional flags to pass to each test command", |
| 105 default="") | 112 default="") |
| 106 result.add_option("--isolates", help="Whether to test isolates", | 113 result.add_option("--isolates", help="Whether to test isolates", |
| 107 default=False, action="store_true") | 114 default=False, action="store_true") |
| (...skipping 11 matching lines...) Expand all Loading... |
| 119 dest="no_network", action="store_true") | 126 dest="no_network", action="store_true") |
| 120 result.add_option("--no-presubmit", "--nopresubmit", | 127 result.add_option("--no-presubmit", "--nopresubmit", |
| 121 help='Skip presubmit checks', | 128 help='Skip presubmit checks', |
| 122 default=False, dest="no_presubmit", action="store_true") | 129 default=False, dest="no_presubmit", action="store_true") |
| 123 result.add_option("--no-stress", "--nostress", | 130 result.add_option("--no-stress", "--nostress", |
| 124 help="Don't run crankshaft --always-opt --stress-op test", | 131 help="Don't run crankshaft --always-opt --stress-op test", |
| 125 default=False, dest="no_stress", action="store_true") | 132 default=False, dest="no_stress", action="store_true") |
| 126 result.add_option("--no-variants", "--novariants", | 133 result.add_option("--no-variants", "--novariants", |
| 127 help="Don't run any testing variants", | 134 help="Don't run any testing variants", |
| 128 default=False, dest="no_variants", action="store_true") | 135 default=False, dest="no_variants", action="store_true") |
| 136 result.add_option("--variants", |
| 137 help="Comma-separated list of testing variants") |
| 129 result.add_option("--outdir", help="Base directory with compile output", | 138 result.add_option("--outdir", help="Base directory with compile output", |
| 130 default="out") | 139 default="out") |
| 131 result.add_option("-p", "--progress", | 140 result.add_option("-p", "--progress", |
| 132 help=("The style of progress indicator" | 141 help=("The style of progress indicator" |
| 133 " (verbose, dots, color, mono)"), | 142 " (verbose, dots, color, mono)"), |
| 134 choices=progress.PROGRESS_INDICATORS.keys(), default="mono") | 143 choices=progress.PROGRESS_INDICATORS.keys(), default="mono") |
| 144 result.add_option("--quickcheck", default=False, action="store_true", |
| 145 help=("Quick check mode (skip slow/flaky tests)")) |
| 135 result.add_option("--report", help="Print a summary of the tests to be run", | 146 result.add_option("--report", help="Print a summary of the tests to be run", |
| 136 default=False, action="store_true") | 147 default=False, action="store_true") |
| 137 result.add_option("--shard-count", | 148 result.add_option("--shard-count", |
| 138 help="Split testsuites into this number of shards", | 149 help="Split testsuites into this number of shards", |
| 139 default=1, type="int") | 150 default=1, type="int") |
| 140 result.add_option("--shard-run", | 151 result.add_option("--shard-run", |
| 141 help="Run this shard from the split up tests.", | 152 help="Run this shard from the split up tests.", |
| 142 default=1, type="int") | 153 default=1, type="int") |
| 143 result.add_option("--shell", help="DEPRECATED! use --shell-dir", default="") | 154 result.add_option("--shell", help="DEPRECATED! use --shell-dir", default="") |
| 144 result.add_option("--shell-dir", help="Directory containing executables", | 155 result.add_option("--shell-dir", help="Directory containing executables", |
| (...skipping 13 matching lines...) Expand all Loading... |
| 158 default=False, action="store_true") | 169 default=False, action="store_true") |
| 159 result.add_option("--junitout", help="File name of the JUnit output") | 170 result.add_option("--junitout", help="File name of the JUnit output") |
| 160 result.add_option("--junittestsuite", | 171 result.add_option("--junittestsuite", |
| 161 help="The testsuite name in the JUnit output file", | 172 help="The testsuite name in the JUnit output file", |
| 162 default="v8tests") | 173 default="v8tests") |
| 163 return result | 174 return result |
| 164 | 175 |
| 165 | 176 |
| 166 def ProcessOptions(options): | 177 def ProcessOptions(options): |
| 167 global VARIANT_FLAGS | 178 global VARIANT_FLAGS |
| 179 global VARIANTS |
| 168 | 180 |
| 169 # Architecture and mode related stuff. | 181 # Architecture and mode related stuff. |
| 170 if options.arch_and_mode: | 182 if options.arch_and_mode: |
| 171 tokens = options.arch_and_mode.split(".") | 183 options.arch_and_mode = [arch_and_mode.split(".") |
| 172 options.arch = tokens[0] | 184 for arch_and_mode in options.arch_and_mode.split(",")] |
| 173 options.mode = tokens[1] | 185 options.arch = ",".join([tokens[0] for tokens in options.arch_and_mode]) |
| 186 options.mode = ",".join([tokens[1] for tokens in options.arch_and_mode]) |
| 174 options.mode = options.mode.split(",") | 187 options.mode = options.mode.split(",") |
| 175 for mode in options.mode: | 188 for mode in options.mode: |
| 176 if not mode.lower() in ["debug", "release"]: | 189 if not mode.lower() in ["debug", "release", "optdebug"]: |
| 177 print "Unknown mode %s" % mode | 190 print "Unknown mode %s" % mode |
| 178 return False | 191 return False |
| 179 if options.arch in ["auto", "native"]: | 192 if options.arch in ["auto", "native"]: |
| 180 options.arch = ARCH_GUESS | 193 options.arch = ARCH_GUESS |
| 181 options.arch = options.arch.split(",") | 194 options.arch = options.arch.split(",") |
| 182 for arch in options.arch: | 195 for arch in options.arch: |
| 183 if not arch in SUPPORTED_ARCHS: | 196 if not arch in SUPPORTED_ARCHS: |
| 184 print "Unknown architecture %s" % arch | 197 print "Unknown architecture %s" % arch |
| 185 return False | 198 return False |
| 186 | 199 |
| 200 # Store the final configuration in arch_and_mode list. Don't overwrite |
| 201 # predefined arch_and_mode since it is more expressive than arch and mode. |
| 202 if not options.arch_and_mode: |
| 203 options.arch_and_mode = itertools.product(options.arch, options.mode) |
| 204 |
| 187 # Special processing of other options, sorted alphabetically. | 205 # Special processing of other options, sorted alphabetically. |
| 188 | 206 |
| 189 if options.buildbot: | 207 if options.buildbot: |
| 190 # Buildbots run presubmit tests as a separate step. | 208 # Buildbots run presubmit tests as a separate step. |
| 191 options.no_presubmit = True | 209 options.no_presubmit = True |
| 192 options.no_network = True | 210 options.no_network = True |
| 193 if options.command_prefix: | 211 if options.command_prefix: |
| 194 print("Specifying --command-prefix disables network distribution, " | 212 print("Specifying --command-prefix disables network distribution, " |
| 195 "running tests locally.") | 213 "running tests locally.") |
| 196 options.no_network = True | 214 options.no_network = True |
| 197 options.command_prefix = shlex.split(options.command_prefix) | 215 options.command_prefix = shlex.split(options.command_prefix) |
| 198 options.extra_flags = shlex.split(options.extra_flags) | 216 options.extra_flags = shlex.split(options.extra_flags) |
| 199 if options.j == 0: | 217 if options.j == 0: |
| 200 options.j = multiprocessing.cpu_count() | 218 options.j = multiprocessing.cpu_count() |
| 201 | 219 |
| 202 def excl(*args): | 220 def excl(*args): |
| 203 """Returns true if zero or one of multiple arguments are true.""" | 221 """Returns true if zero or one of multiple arguments are true.""" |
| 204 return reduce(lambda x, y: x + y, args) <= 1 | 222 return reduce(lambda x, y: x + y, args) <= 1 |
| 205 | 223 |
| 206 if not excl(options.no_stress, options.stress_only, options.no_variants): | 224 if not excl(options.no_stress, options.stress_only, options.no_variants, |
| 207 print "Use only one of --no-stress, --stress-only or --no-variants." | 225 bool(options.variants), options.quickcheck): |
| 226 print("Use only one of --no-stress, --stress-only, --no-variants, " |
| 227 "--variants, or --quickcheck.") |
| 208 return False | 228 return False |
| 209 if options.no_stress: | 229 if options.no_stress: |
| 210 VARIANT_FLAGS = [[], ["--nocrankshaft"]] | 230 VARIANTS = ["default", "nocrankshaft"] |
| 211 if options.no_variants: | 231 if options.no_variants: |
| 212 VARIANT_FLAGS = [[]] | 232 VARIANTS = ["default"] |
| 233 if options.stress_only: |
| 234 VARIANTS = ["stress"] |
| 235 if options.variants: |
| 236 VARIANTS = options.variants.split(",") |
| 237 if not set(VARIANTS).issubset(VARIANT_FLAGS.keys()): |
| 238 print "All variants must be in %s" % str(VARIANT_FLAGS.keys()) |
| 239 return False |
| 240 if options.quickcheck: |
| 241 VARIANTS = ["default", "stress"] |
| 242 options.flaky_tests = "skip" |
| 243 options.slow_tests = "skip" |
| 244 options.pass_fail_tests = "skip" |
| 245 |
| 213 if not options.shell_dir: | 246 if not options.shell_dir: |
| 214 if options.shell: | 247 if options.shell: |
| 215 print "Warning: --shell is deprecated, use --shell-dir instead." | 248 print "Warning: --shell is deprecated, use --shell-dir instead." |
| 216 options.shell_dir = os.path.dirname(options.shell) | 249 options.shell_dir = os.path.dirname(options.shell) |
| 217 if options.stress_only: | |
| 218 VARIANT_FLAGS = [["--stress-opt", "--always-opt"]] | |
| 219 if options.valgrind: | 250 if options.valgrind: |
| 220 run_valgrind = os.path.join("tools", "run-valgrind.py") | 251 run_valgrind = os.path.join("tools", "run-valgrind.py") |
| 221 # This is OK for distributed running, so we don't need to set no_network. | 252 # This is OK for distributed running, so we don't need to set no_network. |
| 222 options.command_prefix = (["python", "-u", run_valgrind] + | 253 options.command_prefix = (["python", "-u", run_valgrind] + |
| 223 options.command_prefix) | 254 options.command_prefix) |
| 224 if not options.flaky_tests in ["run", "skip", "dontcare"]: | 255 def CheckTestMode(name, option): |
| 225 print "Unknown flaky test mode %s" % options.flaky_tests | 256 if not option in ["run", "skip", "dontcare"]: |
| 257 print "Unknown %s mode %s" % (name, option) |
| 258 return False |
| 259 return True |
| 260 if not CheckTestMode("flaky test", options.flaky_tests): |
| 261 return False |
| 262 if not CheckTestMode("slow test", options.slow_tests): |
| 263 return False |
| 264 if not CheckTestMode("pass|fail test", options.pass_fail_tests): |
| 226 return False | 265 return False |
| 227 return True | 266 return True |
| 228 | 267 |
| 229 | 268 |
| 230 def ShardTests(tests, shard_count, shard_run): | 269 def ShardTests(tests, shard_count, shard_run): |
| 231 if shard_count < 2: | 270 if shard_count < 2: |
| 232 return tests | 271 return tests |
| 233 if shard_run < 1 or shard_run > shard_count: | 272 if shard_run < 1 or shard_run > shard_count: |
| 234 print "shard-run not a valid number, should be in [1:shard-count]" | 273 print "shard-run not a valid number, should be in [1:shard-count]" |
| 235 print "defaulting back to running all tests" | 274 print "defaulting back to running all tests" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 254 workspace = os.path.abspath(join(os.path.dirname(sys.argv[0]), "..")) | 293 workspace = os.path.abspath(join(os.path.dirname(sys.argv[0]), "..")) |
| 255 if not options.no_presubmit: | 294 if not options.no_presubmit: |
| 256 print ">>> running presubmit tests" | 295 print ">>> running presubmit tests" |
| 257 code = subprocess.call( | 296 code = subprocess.call( |
| 258 [sys.executable, join(workspace, "tools", "presubmit.py")]) | 297 [sys.executable, join(workspace, "tools", "presubmit.py")]) |
| 259 exit_code = code | 298 exit_code = code |
| 260 | 299 |
| 261 suite_paths = utils.GetSuitePaths(join(workspace, "test")) | 300 suite_paths = utils.GetSuitePaths(join(workspace, "test")) |
| 262 | 301 |
| 263 if len(args) == 0: | 302 if len(args) == 0: |
| 264 suite_paths = [ s for s in suite_paths if s in DEFAULT_TESTS ] | 303 suite_paths = [ s for s in DEFAULT_TESTS if s in suite_paths ] |
| 265 else: | 304 else: |
| 266 args_suites = set() | 305 args_suites = set() |
| 267 for arg in args: | 306 for arg in args: |
| 268 suite = arg.split(os.path.sep)[0] | 307 suite = arg.split(os.path.sep)[0] |
| 269 if not suite in args_suites: | 308 if not suite in args_suites: |
| 270 args_suites.add(suite) | 309 args_suites.add(suite) |
| 271 suite_paths = [ s for s in suite_paths if s in args_suites ] | 310 suite_paths = [ s for s in args_suites if s in suite_paths ] |
| 272 | 311 |
| 273 suites = [] | 312 suites = [] |
| 274 for root in suite_paths: | 313 for root in suite_paths: |
| 275 suite = testsuite.TestSuite.LoadTestSuite( | 314 suite = testsuite.TestSuite.LoadTestSuite( |
| 276 os.path.join(workspace, "test", root)) | 315 os.path.join(workspace, "test", root)) |
| 277 if suite: | 316 if suite: |
| 278 suites.append(suite) | 317 suites.append(suite) |
| 279 | 318 |
| 280 if options.download_data: | 319 if options.download_data: |
| 281 for s in suites: | 320 for s in suites: |
| 282 s.DownloadData() | 321 s.DownloadData() |
| 283 | 322 |
| 284 for mode in options.mode: | 323 for (arch, mode) in options.arch_and_mode: |
| 285 for arch in options.arch: | 324 try: |
| 286 code = Execute(arch, mode, args, options, suites, workspace) | 325 code = Execute(arch, mode, args, options, suites, workspace) |
| 287 exit_code = exit_code or code | 326 except KeyboardInterrupt: |
| 327 return 2 |
| 328 exit_code = exit_code or code |
| 288 return exit_code | 329 return exit_code |
| 289 | 330 |
| 290 | 331 |
| 291 def Execute(arch, mode, args, options, suites, workspace): | 332 def Execute(arch, mode, args, options, suites, workspace): |
| 292 print(">>> Running tests for %s.%s" % (arch, mode)) | 333 print(">>> Running tests for %s.%s" % (arch, mode)) |
| 293 | 334 |
| 294 shell_dir = options.shell_dir | 335 shell_dir = options.shell_dir |
| 295 if not shell_dir: | 336 if not shell_dir: |
| 296 if options.buildbot: | 337 if options.buildbot: |
| 297 shell_dir = os.path.join(workspace, options.outdir, mode) | 338 shell_dir = os.path.join(workspace, options.outdir, mode) |
| 298 mode = mode.lower() | 339 mode = mode.lower() |
| 299 else: | 340 else: |
| 300 shell_dir = os.path.join(workspace, options.outdir, | 341 shell_dir = os.path.join(workspace, options.outdir, |
| 301 "%s.%s" % (arch, mode)) | 342 "%s.%s" % (arch, mode)) |
| 302 shell_dir = os.path.relpath(shell_dir) | 343 shell_dir = os.path.relpath(shell_dir) |
| 303 | 344 |
| 345 if mode == "optdebug": |
| 346 mode = "debug" # "optdebug" is just an alias. |
| 347 |
| 304 # Populate context object. | 348 # Populate context object. |
| 305 mode_flags = MODE_FLAGS[mode] | 349 mode_flags = MODE_FLAGS[mode] |
| 306 timeout = options.timeout | 350 timeout = options.timeout |
| 307 if timeout == -1: | 351 if timeout == -1: |
| 308 # Simulators are slow, therefore allow a longer default timeout. | 352 # Simulators are slow, therefore allow a longer default timeout. |
| 309 if arch in SLOW_ARCHS: | 353 if arch in SLOW_ARCHS: |
| 310 timeout = 2 * TIMEOUT_DEFAULT; | 354 timeout = 2 * TIMEOUT_DEFAULT; |
| 311 else: | 355 else: |
| 312 timeout = TIMEOUT_DEFAULT; | 356 timeout = TIMEOUT_DEFAULT; |
| 313 | 357 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 330 } | 374 } |
| 331 all_tests = [] | 375 all_tests = [] |
| 332 num_tests = 0 | 376 num_tests = 0 |
| 333 test_id = 0 | 377 test_id = 0 |
| 334 for s in suites: | 378 for s in suites: |
| 335 s.ReadStatusFile(variables) | 379 s.ReadStatusFile(variables) |
| 336 s.ReadTestCases(ctx) | 380 s.ReadTestCases(ctx) |
| 337 if len(args) > 0: | 381 if len(args) > 0: |
| 338 s.FilterTestCasesByArgs(args) | 382 s.FilterTestCasesByArgs(args) |
| 339 all_tests += s.tests | 383 all_tests += s.tests |
| 340 s.FilterTestCasesByStatus(options.warn_unused, options.flaky_tests) | 384 s.FilterTestCasesByStatus(options.warn_unused, options.flaky_tests, |
| 385 options.slow_tests, options.pass_fail_tests) |
| 341 if options.cat: | 386 if options.cat: |
| 342 verbose.PrintTestSource(s.tests) | 387 verbose.PrintTestSource(s.tests) |
| 343 continue | 388 continue |
| 389 variant_flags = [VARIANT_FLAGS[var] for var in VARIANTS] |
| 344 s.tests = [ t.CopyAddingFlags(v) | 390 s.tests = [ t.CopyAddingFlags(v) |
| 345 for t in s.tests | 391 for t in s.tests |
| 346 for v in s.VariantFlags(t, VARIANT_FLAGS) ] | 392 for v in s.VariantFlags(t, variant_flags) ] |
| 347 s.tests = ShardTests(s.tests, options.shard_count, options.shard_run) | 393 s.tests = ShardTests(s.tests, options.shard_count, options.shard_run) |
| 348 num_tests += len(s.tests) | 394 num_tests += len(s.tests) |
| 349 for t in s.tests: | 395 for t in s.tests: |
| 350 t.id = test_id | 396 t.id = test_id |
| 351 test_id += 1 | 397 test_id += 1 |
| 352 | 398 |
| 353 if options.cat: | 399 if options.cat: |
| 354 return 0 # We're done here. | 400 return 0 # We're done here. |
| 355 | 401 |
| 356 if options.report: | 402 if options.report: |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 runner = network_execution.NetworkedRunner(suites, progress_indicator, | 437 runner = network_execution.NetworkedRunner(suites, progress_indicator, |
| 392 ctx, peers, workspace) | 438 ctx, peers, workspace) |
| 393 else: | 439 else: |
| 394 runner = execution.Runner(suites, progress_indicator, ctx) | 440 runner = execution.Runner(suites, progress_indicator, ctx) |
| 395 | 441 |
| 396 exit_code = runner.Run(options.j) | 442 exit_code = runner.Run(options.j) |
| 397 if runner.terminate: | 443 if runner.terminate: |
| 398 return exit_code | 444 return exit_code |
| 399 overall_duration = time.time() - start_time | 445 overall_duration = time.time() - start_time |
| 400 except KeyboardInterrupt: | 446 except KeyboardInterrupt: |
| 401 return 1 | 447 raise |
| 402 | 448 |
| 403 if options.time: | 449 if options.time: |
| 404 verbose.PrintTestDurations(suites, overall_duration) | 450 verbose.PrintTestDurations(suites, overall_duration) |
| 405 return exit_code | 451 return exit_code |
| 406 | 452 |
| 407 | 453 |
| 408 if __name__ == "__main__": | 454 if __name__ == "__main__": |
| 409 sys.exit(Main()) | 455 sys.exit(Main()) |
| OLD | NEW |