diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2020-11-25 14:47:44 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2021-01-07 19:20:40 +0100 |
commit | 755412b5261c448025d40214e3f2c0197e2e27bc (patch) | |
tree | ba5039e2e5f2f9cf6b51c5375a774aac56b681b9 /mesonbuild/mtest.py | |
parent | 0ccc70ae1bb85095c5d7313d68bbda5ddb0d1530 (diff) | |
download | meson-755412b5261c448025d40214e3f2c0197e2e27bc.zip meson-755412b5261c448025d40214e3f2c0197e2e27bc.tar.gz meson-755412b5261c448025d40214e3f2c0197e2e27bc.tar.bz2 |
mtest: read test stdout/stderr via asyncio pipes
Instead of creating temporary files, get the StreamReaders from
_run_subprocess's returned object. Through asyncio magic, their
contents will be read as it becomes ready and then returned when
the StreamReader.read future is awaited.
Because of this change, the stdout and stderr can be easily
preserved when TestSubprocess returns an additional_error.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'mesonbuild/mtest.py')
-rw-r--r-- | mesonbuild/mtest.py | 50 |
1 files changed, 29 insertions, 21 deletions
diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index e2c2c56..e1782b3 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -32,7 +32,6 @@ import re import signal import subprocess import sys -import tempfile import textwrap import time import typing as T @@ -929,6 +928,14 @@ class TestSubprocess: self._process = p self.postwait_fn = postwait_fn # type: T.Callable[[], None] + @property + def stdout(self) -> T.Optional[asyncio.StreamReader]: + return self._process.stdout + + @property + def stderr(self) -> T.Optional[asyncio.StreamReader]: + return self._process.stderr + async def _kill(self) -> T.Optional[str]: # Python does not provide multiplatform support for # killing a process and all its children so we need @@ -1033,7 +1040,7 @@ class SingleTestRunner: return self.runobj async def _run_subprocess(self, args: T.List[str], *, - stdout: T.IO, stderr: T.IO, + stdout: int, stderr: int, env: T.Dict[str, str], cwd: T.Optional[str]) -> TestSubprocess: # Let gdb handle ^C instead of us if self.options.gdb: @@ -1088,11 +1095,12 @@ class SingleTestRunner: stdout = None stderr = None - if not self.options.verbose: - stdout = tempfile.TemporaryFile("wb+") - stderr = tempfile.TemporaryFile("wb+") if self.options.split else stdout - if self.test.protocol is TestProtocol.TAP and stderr is stdout: - stdout = tempfile.TemporaryFile("wb+") + if self.test.protocol is TestProtocol.TAP: + stdout = asyncio.subprocess.PIPE + stderr = None if self.options.verbose else asyncio.subprocess.PIPE + elif not self.options.verbose: + stdout = asyncio.subprocess.PIPE + stderr = asyncio.subprocess.PIPE if self.options.split else asyncio.subprocess.STDOUT extra_cmd = [] # type: T.List[str] if self.test.protocol is TestProtocol.GTEST: @@ -1114,24 +1122,24 @@ class SingleTestRunner: env=self.env, cwd=self.test.workdir) + stdo = stde = '' + stdo_task = stde_task = None + if stdout is not None: + stdo_task = p.stdout.read(-1) + if stderr is not None and stderr != asyncio.subprocess.STDOUT: + stde_task = p.stderr.read(-1) + returncode, result, additional_error = await p.wait(timeout) if result is TestResult.TIMEOUT and self.options.verbose: print('{} time out (After {} seconds)'.format(self.test.name, timeout)) - if additional_error is None: - if stdout is None: - stdo = '' - else: - stdout.seek(0) - stdo = decode(stdout.read()) - if stderr is None or stderr is stdout: - stde = '' - else: - stderr.seek(0) - stde = decode(stderr.read()) - else: - stdo = "" - stde = additional_error + if stdo_task is not None: + stdo = decode(await stdo_task) + if stde_task is not None: + stde = decode(await stde_task) + + if additional_error is not None: + stde += '\n' + additional_error # Print lines along the way if requested def lines() -> T.Iterator[str]: |