From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: fam@euphon.net, berrange@redhat.com, f4bug@amsat.org,
aurelien@aurel32.net, pbonzini@redhat.com, stefanha@redhat.com,
crosa@redhat.com, "Alex Bennée" <alex.bennee@linaro.org>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Wainer dos Santos Moschetta" <wainersm@redhat.com>,
"Beraldo Leal" <bleal@redhat.com>
Subject: [PATCH v2 02/12] tests/avocado: improve behaviour waiting for login prompts
Date: Fri, 11 Nov 2022 14:55:19 +0000 [thread overview]
Message-ID: <20221111145529.4020801-3-alex.bennee@linaro.org> (raw)
In-Reply-To: <20221111145529.4020801-1-alex.bennee@linaro.org>
This attempts to deal with the problem of login prompts not being
guaranteed to be terminated with a newline. The solution to this is to
peek at the incoming data looking to see if we see an up-coming match
before we fall back to the old readline() logic. The reason to mostly
rely on readline is because I am occasionally seeing the peek stalling
despite data being there.
This seems kinda hacky and gross so I'm open to alternative approaches
and cleaner python code.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
v2
- remove superfluous /r/n
---
tests/avocado/avocado_qemu/__init__.py | 89 +++++++++++++++++++++++++-
1 file changed, 88 insertions(+), 1 deletion(-)
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
index 910f3ba1ea..20cba57161 100644
--- a/tests/avocado/avocado_qemu/__init__.py
+++ b/tests/avocado/avocado_qemu/__init__.py
@@ -131,6 +131,58 @@ def pick_default_qemu_bin(bin_prefix='qemu-system-', arch=None):
return path
return None
+def _peek_ahead(console, min_match, success_message):
+ """
+ peek ahead in the console stream keeping an eye out for the
+ success message.
+
+ Returns some message to process or None, indicating the normal
+ readline should occur.
+ """
+ console_logger = logging.getLogger('console')
+ peek_len = 0
+ retries = 0
+
+ while True:
+ try:
+ old_peek_len = peek_len
+ peek_ahead = console.peek(min_match).decode()
+ peek_len = len(peek_ahead)
+
+ # if we get stuck too long lets just fallback to readline
+ if peek_len <= old_peek_len:
+ retries += 1
+ if retries > 10:
+ return None
+
+ # if we see a newline in the peek we can let safely bail
+ # and let the normal readline() deal with it
+ if peek_ahead.endswith(('\n', '\r')):
+ return None
+
+ # if we haven't seen enough for the whole message but the
+ # first part matches lets just loop again
+ if len(peek_ahead) < min_match and \
+ success_message[:peek_len] in peek_ahead:
+ continue
+
+ # if we see the whole success_message we are done, consume
+ # it and pass back so we can exit to the user
+ if success_message in peek_ahead:
+ return console.read(peek_len).decode()
+
+ # of course if we've seen enough then this line probably
+ # doesn't contain what we are looking for, fallback
+ if peek_len > min_match:
+ return None
+
+ except UnicodeDecodeError:
+ console_logger.log("error in decode of peek")
+ return None
+
+ # we should never get here
+ return None
+
def _console_interaction(test, success_message, failure_message,
send_string, keep_sending=False, vm=None):
@@ -139,17 +191,52 @@ def _console_interaction(test, success_message, failure_message,
vm = test.vm
console = vm.console_socket.makefile(mode='rb', encoding='utf-8')
console_logger = logging.getLogger('console')
+
+ # Establish the minimum number of bytes we would need to
+ # potentially match against success_message
+ if success_message is not None:
+ min_match = len(success_message)
+ else:
+ min_match = 0
+
+ console_logger.debug("looking for %d:(%s), sending %s (always=%s)",
+ min_match, success_message, send_string, keep_sending)
+
while True:
+ msg = None
+
+ # First send our string, optionally repeating the send next
+ # cycle.
if send_string:
vm.console_socket.sendall(send_string.encode())
if not keep_sending:
send_string = None # send only once
+
+ # If the console has no data to read we briefly
+ # sleep before continuing.
+ if not console.readable():
+ time.sleep(0.1)
+ continue
+
try:
- msg = console.readline().decode().strip()
+
+ # First we shall peek ahead for a potential match to cover waiting
+ # for lines without any newlines.
+ if min_match > 0:
+ msg = _peek_ahead(console, min_match, success_message)
+
+ # otherwise we block here for a full line
+ if not msg:
+ msg = console.readline().decode().strip()
+
except UnicodeDecodeError:
+ console_logger.debug("skipped unicode error")
msg = None
+
+ # if nothing came out we continue and try again
if not msg:
continue
+
console_logger.debug(msg)
if success_message is None or success_message in msg:
break
--
2.34.1
next prev parent reply other threads:[~2022-11-11 14:58 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-11 14:55 [PATCH for 7.2-rc1 v2 00/12] testing, docs, plugins, arm pre-PR Alex Bennée
2022-11-11 14:55 ` [PATCH v2 01/12] Run docker probe only if docker or podman are available Alex Bennée
2022-11-11 16:50 ` Thomas Huth
2022-11-11 14:55 ` Alex Bennée [this message]
2022-11-14 16:28 ` [PATCH v2 02/12] tests/avocado: improve behaviour waiting for login prompts Peter Maydell
2022-11-14 22:15 ` Philippe Mathieu-Daudé
2022-11-17 13:38 ` Cédric Le Goater
2022-11-17 13:50 ` Peter Maydell
2022-11-17 14:04 ` Alex Bennée
2022-11-17 17:14 ` Cédric Le Goater
2022-11-11 14:55 ` [PATCH v2 03/12] tests/avocado/machine_aspeed.py: Reduce noise on the console for SDK tests Alex Bennée
2022-11-11 14:55 ` [PATCH v2 04/12] tests/docker: allow user to override check target Alex Bennée
2022-11-11 17:12 ` Philippe Mathieu-Daudé
2022-11-11 14:55 ` [PATCH v2 05/12] docs/devel: add a maintainers section to development process Alex Bennée
2022-11-11 14:55 ` [PATCH v2 06/12] docs/devel: make language a little less code centric Alex Bennée
2022-11-11 14:55 ` [PATCH v2 07/12] docs/devel: simplify the minimal checklist Alex Bennée
2022-11-11 14:55 ` [PATCH v2 08/12] docs/devel: try and improve the language around patch review Alex Bennée
2022-11-11 14:55 ` [PATCH v2 09/12] tests/plugins: add a new vcpu state tracking plugin Alex Bennée
2022-11-11 14:55 ` [PATCH v2 10/12] tests/avocado: Raise timeout for boot_linux.py:BootLinuxPPC64.test_pseries_tcg Alex Bennée
2022-11-11 14:55 ` [PATCH v2 11/12] gitlab: integrate coverage report Alex Bennée
2022-11-11 19:35 ` Philippe Mathieu-Daudé
2022-11-11 14:55 ` [PATCH v2 12/12] hw/intc: add implementation of GICD_IIDR to Arm GIC Alex Bennée
2022-11-14 13:18 ` Peter Maydell
2022-11-14 12:47 ` [PATCH for 7.2-rc1 v2 00/12] testing, docs, plugins, arm pre-PR Alex Bennée
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221111145529.4020801-3-alex.bennee@linaro.org \
--to=alex.bennee@linaro.org \
--cc=aurelien@aurel32.net \
--cc=berrange@redhat.com \
--cc=bleal@redhat.com \
--cc=crosa@redhat.com \
--cc=f4bug@amsat.org \
--cc=fam@euphon.net \
--cc=pbonzini@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
--cc=wainersm@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).