diff options
author | Thomas Haller <thaller@redhat.com> | 2019-11-06 15:30:55 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-11-06 18:50:50 +0100 |
commit | ca466ea9aa929621e8a35d4105ef33017b1ebf25 (patch) | |
tree | f331e67a95c4b3b9d454597997737e424a33d504 | |
parent | a1022138204a8eb18e78a009380309701609b044 (diff) | |
download | NetworkManager-th/libnm-no-dbus-codegen-3.tar.gz |
clients/tests: read stdout/stderr buffers during test-clients.pyth/libnm-no-dbus-codegen-3
We need to actually read the stdout/stderr of the nmcli programs.
Otherwise, the pipe might fill uup and block to process (eventually
leading to timeout).
-rwxr-xr-x | clients/tests/test-client.py | 65 |
1 files changed, 53 insertions, 12 deletions
diff --git a/clients/tests/test-client.py b/clients/tests/test-client.py index 5ca150eb5b..10739239b8 100755 --- a/clients/tests/test-client.py +++ b/clients/tests/test-client.py @@ -91,11 +91,13 @@ import itertools import subprocess import shlex import re +import fcntl import dbus import time import random import dbus.service import dbus.mainloop.glib +import io ############################################################################### @@ -173,26 +175,52 @@ class Util: @staticmethod def popen_wait(p, timeout = 0): - if Util.python_has_version(3, 3): - if timeout == 0: - return p.poll() - try: - return p.wait(timeout) - except subprocess.TimeoutExpired: - return None + (res, b_stdout, b_stderr) = Util.popen_wait_read(p, timeout = timeout, read_std_pipes = False) + return res + + @staticmethod + def popen_wait_read(p, timeout = 0, read_std_pipes = True): start = NM.utils_get_timestamp_msec() delay = 0.0005 + b_stdout = b'' + b_stderr = b'' + res = None while True: + if read_std_pipes: + b_stdout += Util.buffer_read(p.stdout) + b_stderr += Util.buffer_read(p.stderr) if p.poll() is not None: - return p.returncode + res = p.returncode + break if timeout == 0: - return None + break assert(timeout > 0) remaining = timeout - ((NM.utils_get_timestamp_msec() - start) / 1000.0) if remaining <= 0: - return None + break delay = min(delay * 2, remaining, 0.05) time.sleep(delay) + return (res, b_stdout, b_stderr) + + @staticmethod + def buffer_read(buf): + b = b'' + while True: + try: + b1 = buf.read() + except io.BlockingIOError: + b1 = b'' + except IOError: + b1 = b'' + if not b1: + return b + b += b1 + + @staticmethod + def buffer_set_nonblock(buf): + fd = buf.fileno() + fl = fcntl.fcntl(fd, fcntl.F_GETFL) + fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) @staticmethod def random_job(jobs): @@ -459,10 +487,14 @@ class AsyncProcess(): def start(self): if not hasattr(self, '_p'): self._p_start_timestamp = NM.utils_get_timestamp_msec() + self._p_stdout_buf = b'' + self._p_stderr_buf = b'' self._p = subprocess.Popen(self._args, stdout = subprocess.PIPE, stderr = subprocess.PIPE, env = self._env) + Util.buffer_set_nonblock(self._p.stdout) + Util.buffer_set_nonblock(self._p.stderr) def _timeout_remaining_time(self): # note that we call this during poll() and wait_and_complete(). @@ -476,7 +508,11 @@ class AsyncProcess(): def poll(self, timeout = 0): self.start() - return_code = Util.popen_wait(self._p, timeout) + (return_code, b_stdout, b_stderr) = Util.popen_wait_read(self._p, timeout) + + self._p_stdout_buf += b_stdout + self._p_stderr_buf += b_stderr + if return_code is None \ and self._timeout_remaining_time() <= 0: raise Exception("process is still running after timeout: %s" % (' '.join(self._args))) @@ -488,11 +524,16 @@ class AsyncProcess(): p = self._p self._p = None - return_code = Util.popen_wait(p, max(0, self._timeout_remaining_time()) / 1000) + (return_code, b_stdout, b_stderr) = Util.popen_wait_read(p, max(0, self._timeout_remaining_time()) / 1000) (stdout, stderr) = (p.stdout.read(), p.stderr.read()) p.stdout.close() p.stderr.close() + stdout = self._p_stdout_buf + b_stdout + stdout + stderr = self._p_stderr_buf + b_stderr + stderr + del self._p_stdout_buf + del self._p_stderr_buf + if return_code is None: print(stdout) print(stderr) |