Add test priorities to force test start order

pull/5850/head
Peter Hutterer 5 years ago committed by Jussi Pakkanen
parent e3b21de563
commit 4ebce2c3f2
  1. 6
      docs/markdown/Reference-manual.md
  2. 13
      docs/markdown/Unit-tests.md
  3. 8
      mesonbuild/backend/backends.py
  4. 12
      mesonbuild/interpreter.py
  5. 1
      mesonbuild/mintro.py
  6. 22
      test cases/common/224 test priorities/meson.build
  7. 3
      test cases/common/224 test priorities/test.sh

@ -1520,6 +1520,12 @@ Keyword arguments are the following:
Protocol](https://www.testanything.org/)). For more on the Meson test Protocol](https://www.testanything.org/)). For more on the Meson test
harness protocol read [Unit Tests](Unit-tests.md). Since 0.50.0 harness protocol read [Unit Tests](Unit-tests.md). Since 0.50.0
- `priority` specifies the priority of a test. Tests with a
higher priority are *started* before tests with a lower priority.
The starting order of tests with identical priorities is
implementation-defined. The default priority is 0, negative numbers are
permitted. Since 0.52.0
Defined tests can be run in a backend-agnostic way by calling Defined tests can be run in a backend-agnostic way by calling
`meson test` inside the build dir, or by using backend-specific `meson test` inside the build dir, or by using backend-specific
commands, such as `ninja test` or `msbuild RUN_TESTS.vcxproj`. commands, such as `ninja test` or `msbuild RUN_TESTS.vcxproj`.

@ -51,6 +51,19 @@ By default Meson uses as many concurrent processes as there are cores on the tes
$ MESON_TESTTHREADS=5 ninja test $ MESON_TESTTHREADS=5 ninja test
``` ```
Priorities
--
Tests can be assigned a priority that determines when a test is *started*. Tests with higher priority are started first, tests with lower priority started later. The default priority is 0, meson makes no guarantee on the ordering of tests with identical priority.
```meson
test('started second', t, priority : 0)
test('started third', t, priority : -50)
test('started first', t, priority : 1000)
```
Note that the test priority only affects the starting order of tests and subsequent tests are affected by how long it takes previous tests to complete. It is thus possible that a higher-priority test is still running when lower-priority tests with a shorter runtime have completed.
## Skipped tests and hard errors ## Skipped tests and hard errors
Sometimes a test can only determine at runtime that it can not be run. Sometimes a test can only determine at runtime that it can not be run.

@ -86,7 +86,7 @@ class TestSerialisation:
is_parallel: bool, cmd_args: typing.List[str], is_parallel: bool, cmd_args: typing.List[str],
env: build.EnvironmentVariables, should_fail: bool, env: build.EnvironmentVariables, should_fail: bool,
timeout: typing.Optional[int], workdir: typing.Optional[str], timeout: typing.Optional[int], workdir: typing.Optional[str],
extra_paths: typing.List[str], protocol: str): extra_paths: typing.List[str], protocol: str, priority: int):
self.name = name self.name = name
self.project_name = project self.project_name = project
self.suite = suite self.suite = suite
@ -103,6 +103,7 @@ class TestSerialisation:
self.workdir = workdir self.workdir = workdir
self.extra_paths = extra_paths self.extra_paths = extra_paths
self.protocol = protocol self.protocol = protocol
self.priority = priority
class OptionProxy: class OptionProxy:
def __init__(self, value): def __init__(self, value):
@ -728,7 +729,7 @@ class Backend:
def create_test_serialisation(self, tests): def create_test_serialisation(self, tests):
arr = [] arr = []
for t in tests: for t in sorted(tests, key=lambda tst: -1 * tst.priority):
exe = t.get_exe() exe = t.get_exe()
if isinstance(exe, dependencies.ExternalProgram): if isinstance(exe, dependencies.ExternalProgram):
cmd = exe.get_command() cmd = exe.get_command()
@ -770,7 +771,8 @@ class Backend:
raise MesonException('Bad object in test command.') raise MesonException('Bad object in test command.')
ts = TestSerialisation(t.get_name(), t.project_name, t.suite, cmd, is_cross, ts = TestSerialisation(t.get_name(), t.project_name, t.suite, cmd, is_cross,
exe_wrapper, t.is_parallel, cmd_args, t.env, exe_wrapper, t.is_parallel, cmd_args, t.env,
t.should_fail, t.timeout, t.workdir, extra_paths, t.protocol) t.should_fail, t.timeout, t.workdir,
extra_paths, t.protocol, t.priority)
arr.append(ts) arr.append(ts)
return arr return arr

@ -900,7 +900,8 @@ class Test(InterpreterObject):
def __init__(self, name: str, project: str, suite: List[str], exe: build.Executable, def __init__(self, name: str, project: str, suite: List[str], exe: build.Executable,
depends: List[Union[build.CustomTarget, build.BuildTarget]], depends: List[Union[build.CustomTarget, build.BuildTarget]],
is_parallel: bool, cmd_args: List[str], env: build.EnvironmentVariables, is_parallel: bool, cmd_args: List[str], env: build.EnvironmentVariables,
should_fail: bool, timeout: int, workdir: Optional[str], protocol: str): should_fail: bool, timeout: int, workdir: Optional[str], protocol: str,
priority: int):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.name = name self.name = name
self.suite = suite self.suite = suite
@ -914,6 +915,7 @@ class Test(InterpreterObject):
self.timeout = timeout self.timeout = timeout
self.workdir = workdir self.workdir = workdir
self.protocol = protocol self.protocol = protocol
self.priority = priority
def get_exe(self): def get_exe(self):
return self.exe return self.exe
@ -2044,7 +2046,7 @@ permitted_kwargs = {'add_global_arguments': {'language', 'native'},
'subdir': {'if_found'}, 'subdir': {'if_found'},
'subproject': {'version', 'default_options', 'required'}, 'subproject': {'version', 'default_options', 'required'},
'test': {'args', 'depends', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir', 'test': {'args', 'depends', 'env', 'is_parallel', 'should_fail', 'timeout', 'workdir',
'suite', 'protocol'}, 'suite', 'protocol', 'priority'},
'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'}, 'vcs_tag': {'input', 'output', 'fallback', 'command', 'replace_string'},
} }
@ -3383,6 +3385,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
self.add_test(node, args, kwargs, False) self.add_test(node, args, kwargs, False)
@FeatureNewKwargs('test', '0.46.0', ['depends']) @FeatureNewKwargs('test', '0.46.0', ['depends'])
@FeatureNewKwargs('test', '0.52.0', ['priority'])
@permittedKwargs(permitted_kwargs['test']) @permittedKwargs(permitted_kwargs['test'])
def func_test(self, node, args, kwargs): def func_test(self, node, args, kwargs):
self.add_test(node, args, kwargs, True) self.add_test(node, args, kwargs, True)
@ -3453,8 +3456,11 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
for dep in depends: for dep in depends:
if not isinstance(dep, (build.CustomTarget, build.BuildTarget)): if not isinstance(dep, (build.CustomTarget, build.BuildTarget)):
raise InterpreterException('Depends items must be build targets.') raise InterpreterException('Depends items must be build targets.')
priority = kwargs.get('priority', 0)
if not isinstance(priority, int):
raise InterpreterException('Keyword argument priority must be an integer.')
t = Test(args[0], prj, suite, exe.held_object, depends, par, cmd_args, t = Test(args[0], prj, suite, exe.held_object, depends, par, cmd_args,
env, should_fail, timeout, workdir, protocol) env, should_fail, timeout, workdir, protocol, priority)
if is_base_test: if is_base_test:
self.build.tests.append(t) self.build.tests.append(t)
mlog.debug('Adding test', mlog.bold(args[0], True)) mlog.debug('Adding test', mlog.bold(args[0], True))

@ -321,6 +321,7 @@ def get_test_list(testdata):
to['timeout'] = t.timeout to['timeout'] = t.timeout
to['suite'] = t.suite to['suite'] = t.suite
to['is_parallel'] = t.is_parallel to['is_parallel'] = t.is_parallel
to['priority'] = t.priority
result.append(to) result.append(to)
return result return result

@ -0,0 +1,22 @@
project('test priorities', 'c')
test_prog = find_program('test.sh')
test('priority 0', test_prog,
args : ['0'],
)
test('priority neg 10', test_prog,
args : ['-10'],
priority : -10
)
test('priority 1000', test_prog,
args : ['1000'],
priority : 1000
)
test('priority 50', test_prog,
args : ['50'],
priority : 50
)
Loading…
Cancel
Save