Skip to content

Commit a57ebdc

Browse files
authored
[test] Add --start-at <TEST> argument to test runner (#20406)
When combined with `--failfast` this is a great way to iteratively fix an entire suite without having to re-run it from the beginning each time.
1 parent 431685f commit a57ebdc

File tree

2 files changed

+36
-9
lines changed

2 files changed

+36
-9
lines changed

site/source/docs/getting_started/test-suite.rst

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ individual test, or use wildcards to run some tests in some modes. For example:
3535
.. code-block:: bash
3636
3737
# run one test (in the default mode)
38-
test/runner test_loop
38+
test/runner test_foo
3939
4040
# run a bunch of tests in one mode (here, all i64 tests in -O3)
4141
test/runner core3.test_*i64*
@@ -88,6 +88,23 @@ Wildcards can also be passed in skip, so
8888
8989
will run the whole browser suite except for all the pthread tests in it.
9090

91+
Exiting on first failure
92+
========================
93+
94+
Sometimes it is useful to be able to iteratively fix one test at a time. In
95+
this case the ``--failfast`` option can be used to exit the test runner after
96+
the first failure.
97+
98+
.. note:: This option only works with the serial test runner. For test suites
99+
that are normally run in parallel you can force them to run serially using
100+
``-j1``.
101+
102+
One a test is fixed you continue where you left off using ``--start-at`` option:
103+
104+
.. code-block:: bash
105+
106+
test/runner browser --start-at test_foo --failfast
107+
91108
Running a bunch of random tests
92109
===============================
93110

test/runner.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,11 +264,14 @@ def error_on_legacy_suite_names(args):
264264
utils.exit_with_error('`%s` test suite has been replaced with `%s`', a, new)
265265

266266

267-
def load_test_suites(args, modules):
267+
def load_test_suites(args, modules, start_at):
268+
found_start = not start_at
269+
268270
loader = unittest.TestLoader()
269271
error_on_legacy_suite_names(args)
270272
unmatched_test_names = set(args)
271273
suites = []
274+
272275
total_tests = 0
273276
for m in modules:
274277
names_in_module = []
@@ -282,11 +285,19 @@ def load_test_suites(args, modules):
282285
if len(names_in_module):
283286
loaded_tests = loader.loadTestsFromNames(sorted(names_in_module), m)
284287
tests = flattened_tests(loaded_tests)
285-
total_tests += len(tests)
286288
suite = suite_for_module(m, tests)
287289
for test in tests:
290+
if not found_start:
291+
# Skip over tests until we find the start
292+
if test.id().endswith(start_at):
293+
found_start = True
294+
else:
295+
continue
296+
total_tests += 1
288297
suite.addTest(test)
289298
suites.append((m.__name__, suite))
299+
if not found_start:
300+
utils.exit_with_error(f'unable to find --start-at test: {start_at}')
290301
if total_tests == 1 or parallel_testsuite.num_cores() == 1:
291302
common.EMTEST_SAVE_DIR = True
292303
return suites, unmatched_test_names
@@ -360,18 +371,17 @@ def parse_args(args):
360371
parser.add_argument('--all-engines', action='store_true', default=None)
361372
parser.add_argument('--detect-leaks', action='store_true', default=None)
362373
parser.add_argument('--skip-slow', action='store_true', help='Skip tests marked as slow')
363-
parser.add_argument('--cores',
374+
parser.add_argument('--cores', '-j',
364375
help='Set the number tests to run in parallel. Defaults '
365376
'to the number of CPU cores.', default=None)
366377
parser.add_argument('--rebaseline', action='store_true', default=None,
367378
help='Automatically update test expectations for tests that support it.')
368379
parser.add_argument('--browser',
369380
help='Command to launch web browser in which to run browser tests.')
370381
parser.add_argument('tests', nargs='*')
371-
parser.add_argument('--failfast', dest='failfast', action='store_const',
372-
const=True, default=False)
373-
parser.add_argument('--force64', dest='force64', action='store_const',
374-
const=True, default=None)
382+
parser.add_argument('--failfast', action='store_const', const=True, default=False)
383+
parser.add_argument('--start-at', metavar='NAME', help='Skip all tests up until <NAME>')
384+
parser.add_argument('--force64', action='store_const', const=True, default=None)
375385
parser.add_argument('--crossplatform-only', action='store_true')
376386
return parser.parse_args()
377387

@@ -453,7 +463,7 @@ def prepend_default(arg):
453463
tests = tests_with_expanded_wildcards(tests, all_tests)
454464
tests = skip_requested_tests(tests, modules)
455465
tests = args_for_random_tests(tests, modules)
456-
suites, unmatched_tests = load_test_suites(tests, modules)
466+
suites, unmatched_tests = load_test_suites(tests, modules, options.start_at)
457467
if unmatched_tests:
458468
print('ERROR: could not find the following tests: ' + ' '.join(unmatched_tests))
459469
return 1

0 commit comments

Comments
 (0)