aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2020-11-19 10:08:07 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2020-12-27 13:55:02 +0100
commit3f8c9012459d4923cc3167bf4859e2f8a6794f96 (patch)
treeac03755b4309faca006ef6fa3fd116912558f6fb
parent30741a0f202cf6cdf3c84645978bc7b38ed24b28 (diff)
downloadmeson-3f8c9012459d4923cc3167bf4859e2f8a6794f96.zip
meson-3f8c9012459d4923cc3167bf4859e2f8a6794f96.tar.gz
meson-3f8c9012459d4923cc3167bf4859e2f8a6794f96.tar.bz2
mtest: add name and number to TestRun
Place in TestRun everything that is needed in order to format the result. This avoids passing around the number and visible test name as arguments. Test numbers are assigned the first time they are used. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--mesonbuild/mtest.py56
1 files changed, 33 insertions, 23 deletions
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py
index 34e4943..c754309 100644
--- a/mesonbuild/mtest.py
+++ b/mesonbuild/mtest.py
@@ -353,12 +353,12 @@ class JunitBuilder:
'testsuites', tests='0', errors='0', failures='0')
self.suites = {} # type: T.Dict[str, et.Element]
- def log(self, name: str, test: 'TestRun') -> None:
+ def log(self, test: 'TestRun') -> None:
"""Log a single test case."""
if test.junit is not None:
for suite in test.junit.findall('.//testsuite'):
# Assume that we don't need to merge anything here...
- suite.attrib['name'] = '{}.{}.{}'.format(test.project, name, suite.attrib['name'])
+ suite.attrib['name'] = '{}.{}.{}'.format(test.project, test.name, suite.attrib['name'])
# GTest can inject invalid attributes
for case in suite.findall('.//testcase[@result]'):
@@ -372,7 +372,7 @@ class JunitBuilder:
# We want to record this so that each result is recorded
# separately
if test.results:
- suitename = '{}.{}'.format(test.project, name)
+ suitename = '{}.{}'.format(test.project, test.name)
assert suitename not in self.suites, 'duplicate suite'
suite = self.suites[suitename] = et.Element(
@@ -420,7 +420,7 @@ class JunitBuilder:
suite = self.suites[test.project]
suite.attrib['tests'] = str(int(suite.attrib['tests']) + 1)
- testcase = et.SubElement(suite, 'testcase', name=name, classname=name)
+ testcase = et.SubElement(suite, 'testcase', name=test.name, classname=test.name)
if test.res is TestResult.SKIP:
et.SubElement(testcase, 'skipped')
suite.attrib['skipped'] = str(int(suite.attrib['skipped']) + 1)
@@ -451,10 +451,14 @@ class JunitBuilder:
class TestRun:
+ TEST_NUM = 0
- def __init__(self, test: TestSerialisation, test_env: T.Dict[str, str]):
+ def __init__(self, test: TestSerialisation, test_env: T.Dict[str, str],
+ name: str):
self.res = TestResult.PENDING
self.test = test
+ self._num = None # type: T.Optional[int]
+ self.name = name
self.results = list() # type: T.List[TestResult]
self.returncode = 0
self.starttime = None # type: T.Optional[float]
@@ -529,6 +533,13 @@ class TestRun:
self.complete(res, results, returncode, stdo, stde, cmd)
+ @property
+ def num(self) -> int:
+ if self._num is None:
+ TestRun.TEST_NUM += 1
+ self._num = TestRun.TEST_NUM
+ return self._num
+
def complete(self, res: TestResult, results: T.List[TestResult],
returncode: int,
stdo: T.Optional[str], stde: T.Optional[str],
@@ -574,8 +585,8 @@ def decode(stream: T.Union[None, bytes]) -> str:
except UnicodeDecodeError:
return stream.decode('iso-8859-1', errors='ignore')
-def write_json_log(jsonlogfile: T.TextIO, test_name: str, result: TestRun) -> None:
- jresult = {'name': test_name,
+def write_json_log(jsonlogfile: T.TextIO, result: TestRun) -> None:
+ jresult = {'name': result.name,
'stdout': result.stdo,
'result': result.res.value,
'starttime': result.starttime,
@@ -647,12 +658,13 @@ async def complete_all(futures: T.Iterable[asyncio.Future]) -> None:
class SingleTestRunner:
def __init__(self, test: TestSerialisation, test_env: T.Dict[str, str],
- env: T.Dict[str, str], options: argparse.Namespace):
+ env: T.Dict[str, str], name: str,
+ options: argparse.Namespace):
self.test = test
self.test_env = test_env
self.env = env
self.options = options
- self.runobj = TestRun(test, test_env)
+ self.runobj = TestRun(test, test_env, name)
def _get_cmd(self) -> T.Optional[T.List[str]]:
if self.test.fname[0].endswith('.jar'):
@@ -915,7 +927,7 @@ class TestHarness:
options.wrapper = current.exe_wrapper
return current.env.get_env(os.environ.copy())
- def get_test_runner(self, test: TestSerialisation) -> SingleTestRunner:
+ def get_test_runner(self, test: TestSerialisation, name: str) -> SingleTestRunner:
options = deepcopy(self.options)
if not options.setup:
options.setup = self.build_data.test_setup_default_name
@@ -928,7 +940,7 @@ class TestHarness:
if (test.is_cross_built and test.needs_exe_wrapper and
test.exe_runner and test.exe_runner.found()):
env['MESON_EXE_WRAPPER'] = join_args(test.exe_runner.get_command())
- return SingleTestRunner(test, test_env, env, options)
+ return SingleTestRunner(test, test_env, env, name, options)
def process_test_result(self, result: TestRun) -> None:
if result.res is TestResult.TIMEOUT:
@@ -947,17 +959,16 @@ class TestHarness:
sys.exit('Unknown test result encountered: {}'.format(result.res))
def print_stats(self, test_count: int, name_max_len: int,
- tests: T.List[TestSerialisation],
- name: str, result: TestRun, i: int) -> None:
+ result: TestRun) -> None:
ok_statuses = (TestResult.OK, TestResult.EXPECTEDFAIL)
bad_statuses = (TestResult.FAIL, TestResult.TIMEOUT, TestResult.INTERRUPT,
TestResult.UNEXPECTEDPASS, TestResult.ERROR)
result_str = '{num:{numlen}}/{testcount} {name:{name_max_len}} {res:{reslen}} {dur:.2f}s'.format(
numlen=len(str(test_count)),
- num=i,
+ num=result.num,
testcount=test_count,
name_max_len=name_max_len,
- name=name,
+ name=result.name,
reslen=TestResult.maxlen(),
res=result.res.value,
dur=result.duration)
@@ -979,9 +990,9 @@ class TestHarness:
if self.logfile:
self.logfile.write(result_str)
if self.jsonlogfile:
- write_json_log(self.jsonlogfile, name, result)
+ write_json_log(self.jsonlogfile, result)
if self.junit:
- self.junit.log(name, result)
+ self.junit.log(result)
def print_summary(self) -> None:
# Prepend a list of failures
@@ -1201,14 +1212,13 @@ class TestHarness:
self.build_data = build.load(os.getcwd())
interrupted = False
- async def run_test(test: SingleTestRunner,
- name: str, index: int) -> None:
+ async def run_test(test: SingleTestRunner) -> None:
async with semaphore:
if interrupted or (self.options.repeat > 1 and self.fail_count):
return
res = await test.run()
self.process_test_result(res)
- self.print_stats(test_count, name_max_len, tests, name, res, index)
+ self.print_stats(test_count, name_max_len, res)
def test_done(f: asyncio.Future) -> None:
if not f.cancelled():
@@ -1253,13 +1263,13 @@ class TestHarness:
asyncio.get_event_loop().add_signal_handler(signal.SIGTERM, sigterm_handler)
try:
for _ in range(self.options.repeat):
- for i, test in enumerate(tests, 1):
+ for test in tests:
visible_name = self.get_pretty_suite(test)
- single_test = self.get_test_runner(test)
+ single_test = self.get_test_runner(test, visible_name)
if not test.is_parallel or single_test.options.gdb:
await complete_all(futures)
- future = asyncio.ensure_future(run_test(single_test, visible_name, i))
+ future = asyncio.ensure_future(run_test(single_test))
futures.append(future)
running_tests[future] = visible_name
future.add_done_callback(test_done)