aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/mtest.py
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2020-11-25 14:47:44 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2021-01-07 19:20:40 +0100
commit755412b5261c448025d40214e3f2c0197e2e27bc (patch)
treeba5039e2e5f2f9cf6b51c5375a774aac56b681b9 /mesonbuild/mtest.py
parent0ccc70ae1bb85095c5d7313d68bbda5ddb0d1530 (diff)
downloadmeson-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.py50
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]: