[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC XEN PATCH 10/13] pytest: Add guest test



From: Anthony PERARD <anthony.perard@xxxxxxxxxx>

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@xxxxxxxxxx>
---
 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




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.