From: Anthony PERARD <anthony@xenproject.org>
To: xen-devel@lists.xenproject.org
Cc: "Andrew Cooper" <andrew.cooper3@citrix.com>,
"Marek Marczykowski-Górecki" <marmarek@invisiblethingslab.com>,
"Anthony PERARD" <anthony.perard@vates.tech>,
"Doug Goldstein" <cardoe@cardoe.com>,
"Stefano Stabellini" <sstabellini@kernel.org>
Subject: [RFC XEN PATCH 10/13] pytest: Add guest test
Date: Tue, 22 Sep 2026 12:08:57 +0200 [thread overview]
Message-ID: <20260922100900.29129-11-anthony@xenproject.org> (raw)
In-Reply-To: <20260922100900.29129-1-anthony@xenproject.org>
From: Anthony PERARD <anthony.perard@vates.tech>
Adding a second test, to help show how to improve the fixtures, and
needed code in libraries
That test copies part of the run tools-test tests, but we could shared
that better.
Then, we ssh to the host, to both follow the guest log files and to
prepare and start the guest, over several SSH channel.
tail_log() could go into a lib.
And I don't know yet what to do with the collected threads object.
I also want to get rid of the guest_boot_script marker, and ssh to the
guest instead.
Signed-off-by: Anthony PERARD <anthony.perard@vates.tech>
---
automation/pytest/test_boot.py | 97 ++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/automation/pytest/test_boot.py b/automation/pytest/test_boot.py
index 5a7ec43fa52b..089aa1e6c063 100644
--- a/automation/pytest/test_boot.py
+++ b/automation/pytest/test_boot.py
@@ -3,8 +3,11 @@ import os
import paramiko
from pathlib import Path
import pytest
+from queue import Queue
import random
import string
+from textwrap import dedent
+from threading import Thread
from typing import Generator
from lib.boot_binary import BootBinary
@@ -138,3 +141,97 @@ def test_xen_tools_tests(machine_on_ipmi: IPMI,
errormsg = stderr.read()
if errormsg:
logging.info(f"cmd errro: {errormsg!r}")
+
+
+@pytest.mark.timeout(600)
+@pytest.mark.guest_boot_script(dedent(f"""
+ ifconfig eth0 10.1.105.101
+ until ping -c 10 {os.environ["HOST_IP4"].partition('/')[0]}; do
+ sleep 1
+ done
+ echo \"guest ping test passed\"
+ """))
+def test_guest(
+ machine_on_ipmi: IPMI,
+ sshkey_for_test: paramiko.pkey.PKey,
+ boot_string: str,
+ ) -> None:
+ expect_string = boot_string
+ for line in machine_on_ipmi.console_output_generator():
+ #
+ # Wait for `expect_string` for the test to succeed
+ #
+ if expect_string in line:
+ logging.info(f"got expect_string '{line}'.")
+ break
+ #
+ # Some common expected or not console outputs.
+ #
+ if "Latest ChangeSet:" in line:
+ logging.info(f"Test xen build from '{line}'.")
+ if "Manual reset required ('noreboot' specified)" in line:
+ # Test failed, could wait a bit before failing the test.
+ logging.error("Xen panic")
+
+ with paramiko.client.SSHClient() as ssh:
+ threads = []
+ ssh_logs: Queue[str] = Queue()
+ ssh.set_missing_host_key_policy(paramiko.client.WarningPolicy)
+ logging.debug(f"connecting to {os.environ['HOST_IP4'].split('/')[0]}")
+ ssh.connect(os.environ['HOST_IP4'].split('/')[0],
+ username='root',
+ pkey=sshkey_for_test,
+ timeout=10,
+ )
+
+ def ssh_channel_read(stdout, prefix):
+ for output in stdout:
+ ssh_logs.put(f"{prefix}{output.strip()}")
+
+ def tail_log(file: Path, prefix: str):
+ stdin, stdout, stderr = ssh.exec_command(f"tail -n0 -F {file}")
+ stdin.close()
+ # Dirty, should keep `stderr` to clean it up
+ t = Thread(target=ssh_channel_read, args=(stdout, prefix))
+ t.start()
+ return t
+
+ threads += [
+ tail_log(Path("/var/log/xen/console/guest-domU.log"), "(domU) "),
+ tail_log(Path("/var/log/xen/qemu-dm-domU.log"), "(qemu-dm) "),
+ ]
+
+ cmd = dedent(f"""
+ set -x
+ pxe_host="{os.environ["PXE_HOST"]}"
+ http_pxe_path="{os.environ["PXE_HTTP_PATH"]}"
+ wget http://${{pxe_host}}/${{http_pxe_path}}/bzImage -O /boot/vmlinuz-domU
+ wget http://${{pxe_host}}/${{http_pxe_path}}/guest-rootfs.cpio.gz -O /boot/initrd-domU
+ xl -Tvvv create /etc/xen/domU.cfg 2>&1
+ """)
+ logging.info(f"Exec command: {cmd}")
+ stdin, stdout, stderr = ssh.exec_command(cmd)
+
+ # everything is on stderr, both wget and xl output
+ t = Thread(target=ssh_channel_read, args=(stderr, ""))
+ t.start()
+ threads.append(t)
+ t = Thread(target=ssh_channel_read, args=(stdout, ""))
+ t.start()
+ threads.append(t)
+
+ # Log while `xl` is preparing the guest to start
+ while t.is_alive():
+ line = ssh_logs.get()
+ logging.debug(line)
+
+ xl_exit_status = stderr.channel.recv_exit_status()
+ assert xl_exit_status == 0
+
+ # `xl` have exited, continue logging the guest output
+ while True:
+ line = ssh_logs.get()
+ logging.debug(line)
+ if "guest ping test passed" in line:
+ logging.info("found expected guest line in logs")
+ break
--
Anthony PERARD
next prev parent reply other threads:[~2026-09-22 10:29 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 10:08 [RFC XEN PATCH 00/13] Running bare-metal tests with "pytest" Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 01/13] pytest: Add fixture to prepare rootfs Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 02/13] Creating new python project Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 03/13] pytest: Add fixture to prepare the tftp server Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 04/13] pytest: Add fixture that boot a machine Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 05/13] pytest: Introduce reading the console, and add a test Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 06/13] We need an older version of paramiko Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 07/13] pytest: Add random string to look for in the logs Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 08/13] pytest: Run run-tools-tests over ssh on the test machine Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 09/13] pytest: Generate a rootfs for a guest Anthony PERARD
2026-09-22 10:08 ` Anthony PERARD [this message]
2026-09-22 10:08 ` [RFC XEN PATCH 11/13] pytest: Add config to enable live log, and disable ssh/paramiko logging Anthony PERARD
2026-09-22 10:08 ` [RFC XEN PATCH 12/13] pytest: Add example .env for options for the tests Anthony PERARD
2026-09-22 10:09 ` [RFC XEN PATCH 13/13] gitlab-ci: Add job for moonshot with pytest Anthony PERARD
2026-09-22 11:01 ` [RFC XEN PATCH 00/13] Running bare-metal tests with "pytest" Marek Marczykowski-Górecki
2026-09-22 14:31 ` Baptiste Le Duc
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=20260922100900.29129-11-anthony@xenproject.org \
--to=anthony@xenproject.org \
--cc=andrew.cooper3@citrix.com \
--cc=anthony.perard@vates.tech \
--cc=cardoe@cardoe.com \
--cc=marmarek@invisiblethingslab.com \
--cc=sstabellini@kernel.org \
--cc=xen-devel@lists.xenproject.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.