Skip to content

Commit e2158ec

Browse files
committed
mtest: add option to slice tests
Executing tests can take a very long time. As an example, the Git test suite on Windows takes around 4 hours to execute. The Git project has been working around the issue by splitting up CI jobs into multiple slices: one job creates the build artifacts, and then we spawn N test jobs with those artifacts, where each test job executes 1/Nth of the tests. This can be scripted rather easily by using `meson test --list`, selecting every Nth line, but there may be other projects that have a similar need. Wire up a new option "--slice i/n" to `meson test` that does implements this logic. Signed-off-by: Patrick Steinhardt <[email protected]>
1 parent 6299f18 commit e2158ec

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

mesonbuild/mtest.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,29 @@ def uniwidth(s: str) -> int:
9999
result += UNIWIDTH_MAPPING[w]
100100
return result
101101

102+
def test_slice(arg: str) -> T.Tuple[int, int]:
103+
values = arg.split('/')
104+
if len(values) != 2:
105+
raise argparse.ArgumentTypeError("value does not conform to format 'SLICE/NUM_SLICES'")
106+
107+
try:
108+
nrslices = int(values[1])
109+
except ValueError:
110+
raise argparse.ArgumentTypeError("NUM_SLICES is not an integer")
111+
if nrslices <= 0:
112+
raise ValueError("NUM_SLICES is not a positive integer")
113+
114+
try:
115+
subslice = int(values[0])
116+
except ValueError:
117+
raise argparse.ArgumentTypeError("SLICE is not an integer")
118+
if subslice <= 0:
119+
raise ValueError("SLICE not a positive integer")
120+
if subslice > nrslices:
121+
raise ValueError("SLICE exceeds NUM_SLICES")
122+
123+
return subslice, nrslices
124+
102125
# Note: when adding arguments, please also add them to the completion
103126
# scripts in $MESONSRC/data/shell-completions/
104127
def add_arguments(parser: argparse.ArgumentParser) -> None:
@@ -149,12 +172,13 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
149172
help='Arguments to pass to the specified test(s) or all tests')
150173
parser.add_argument('--max-lines', default=100, dest='max_lines', type=int,
151174
help='Maximum number of lines to show from a long test log. Since 1.5.0.')
175+
parser.add_argument('--slice', default=None, type=test_slice, metavar='SLICE/NUM_SLICES',
176+
help='Split tests into NUM_SLICES slices and execute slice SLICE. Since 1.7.0.')
152177
parser.add_argument('args', nargs='*',
153178
help='Optional list of test names to run. "testname" to run all tests with that name, '
154179
'"subprojname:testname" to specifically run "testname" from "subprojname", '
155180
'"subprojname:" to run all tests defined by "subprojname".')
156181

157-
158182
def print_safe(s: str) -> None:
159183
end = '' if s[-1] == '\n' else '\n'
160184
try:
@@ -1976,6 +2000,9 @@ def get_tests(self, errorfile: T.Optional[T.IO] = None) -> T.List[TestSerialisat
19762000
tests = [t for t in self.tests if self.test_suitable(t)]
19772001
if self.options.args:
19782002
tests = list(self.tests_from_args(tests))
2003+
if self.options.slice:
2004+
our_slice, nslices = self.options.slice
2005+
tests = tests[our_slice::nslices]
19792006

19802007
if not tests:
19812008
print('No suitable tests defined.', file=errorfile)

0 commit comments

Comments
 (0)