diff mbox

[KVM-Autotest,1/2,virtio-console] Corrects virtio-console test.

Message ID 1296660787-21365-1-git-send-email-jzupka@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jiri Zupka Feb. 2, 2011, 3:33 p.m. UTC
None
diff mbox

Patch

diff --git a/client/tests/kvm/scripts/virtio_console_guest.py b/client/tests/kvm/scripts/virtio_console_guest.py
index c407231..f11436c 100755
--- a/client/tests/kvm/scripts/virtio_console_guest.py
+++ b/client/tests/kvm/scripts/virtio_console_guest.py
@@ -9,11 +9,12 @@  Auxiliary script used to send data between ports on guests.
 """
 import threading
 from threading import Thread
-import os, select, re, random, sys, array
-import fcntl, traceback, signal
+import os, time, select, re, random, sys, array
+import fcntl, subprocess, traceback, signal
 
 DEBUGPATH = "/sys/kernel/debug"
 SYSFSPATH = "/sys/class/virtio-ports/"
+DEVPATH = "/dev/virtio-ports/"
 
 exiting = False
 
@@ -53,10 +54,11 @@  class VirtioGuest:
         return out
 
 
-    def _get_port_status(self):
+    def _get_port_status(self, in_files=None):
         """
         Get info about ports from kernel debugfs.
 
+        @param in_files: Array of input files.
         @return: Ports dictionary of port properties
         """
         ports = {}
@@ -70,6 +72,23 @@  class VirtioGuest:
             print not_present_msg
         else:
             viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
+            if (in_files != None):
+                dev_names = os.listdir('/dev')
+                rep = re.compile(r"vport[0-9]p[0-9]+")
+                dev_names = filter(lambda x: rep.match(x) != None, dev_names)
+                if len(dev_names) != len(in_files):
+                    print ("FAIL: Not all ports are sucesfully inicailized"+
+                           " in /dev "+
+                           "only %d from %d." % (len(dev_names),
+                                                 len(in_files)))
+                    return
+
+                if len(viop_names) != len(in_files):
+                    print ("FAIL: No all ports  are sucesfully inicailized "
+                           "in debugfs only %d from %d." % (len(viop_names),
+                                                            len(in_files)))
+                    return
+
             for name in viop_names:
                 open_db_file = "%s/virtio-ports/%s" % (DEBUGPATH, name)
                 f = open(open_db_file, 'r')
@@ -102,9 +121,14 @@  class VirtioGuest:
                                (info_name , port_name,
                                 "%s/virtio-ports/%s" % (DEBUGPATH, name),
                                 port["name"]))
+                    dev_ppath = DEVPATH + port_name
+                    if not (os.path.exists(dev_ppath)):
+                        print ("FAIL: Symlink " + dev_ppath + " not exist.")
+                    if not (os.path.realpath(dev_ppath) != "/dev/name"):
+                        print ("FAIL: Sumlink " + dev_ppath + " not correct.")
                 except AttributeError:
                     print ("In file " + open_db_file +
-                           " are bad data\n"+ "".join(file).strip())
+                           " are incorrect data\n" + "".join(file).strip())
                     print ("FAIL: Fail file data.")
                     return
 
@@ -118,7 +142,7 @@  class VirtioGuest:
         """
         Init and check port properties.
         """
-        self.ports = self._get_port_status()
+        self.ports = self._get_port_status(in_files)
 
         if self.ports == None:
             return
@@ -126,6 +150,8 @@  class VirtioGuest:
             if (item[1] != self.ports[item[0]]["is_console"]):
                 print self.ports
                 print "FAIL: Host console is not like console on guest side\n"
+                return
+
         print "PASS: Init and check virtioconsole files in system."
 
 
@@ -426,7 +452,7 @@  class VirtioGuest:
         return ret
 
 
-    def async(self, port, mode=True, exp_val = 0):
+    def async(self, port, mode=True, exp_val=0):
         """
         Set port function mode async/sync.
 
@@ -566,7 +592,7 @@  class VirtioGuest:
         print "PASS: Sender start"
 
 
-    def send(self, port, length=1, mode=True):
+    def send(self, port, length=1, mode=True, is_static=False):
         """
         Send a data of some length
 
@@ -577,14 +603,18 @@  class VirtioGuest:
         in_f = self._open([port])
 
         data = ""
-        while len(data) < length:
-            data += "%c" % random.randrange(255)
-        try:
-            writes = os.write(in_f[0], data)
-        except Exception, inst:
-            print inst
-        if not writes:
-            writes = 0
+        writes = 0
+
+        if not is_static:
+            while len(data) < length:
+                data += "%c" % random.randrange(255)
+            try:
+                writes = os.write(in_f[0], data)
+            except Exception, inst:
+                print inst
+        else:
+            while len(data) < 4096:
+                data += "%c" % random.randrange(255)
         if mode:
             while (writes < length):
                 try:
@@ -632,7 +662,7 @@  class VirtioGuest:
         buf = ""
         if ret[0]:
             buf = os.read(in_f[0], buffer)
-        print ("PASS: Rest in socket: ") + str(buf[10])
+        print ("PASS: Rest in socket: ") + str(buf[:10])
 
 
 def is_alive():
@@ -681,6 +711,7 @@  def worker(virt):
                             traceback.format_exception(exc_type,
                                                        exc_value,
                                                        exc_traceback))
+            print "FAIL: Guest command exception."
 
 
 def sigusr_handler(sig, frame):
diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py
index af32bf2..8ab6427 100644
--- a/client/tests/kvm/tests/virtio_console.py
+++ b/client/tests/kvm/tests/virtio_console.py
@@ -10,7 +10,8 @@  from threading import Thread
 
 from autotest_lib.client.common_lib import error
 from autotest_lib.client.bin import utils
-import kvm_subprocess, kvm_test_utils, kvm_preprocessing
+import kvm_subprocess, kvm_test_utils, kvm_utils
+import kvm_preprocessing, kvm_monitor
 
 
 def run_virtio_console(test, params, env):
@@ -57,6 +58,15 @@  def run_virtio_console(test, params, env):
             self.cleanup_args = args
 
 
+        def get_cleanup_func(self):
+            """
+            Returns the tupple of cleanup_func and clenaup_args
+
+            @return: Tupple of self.cleanup_func and self.cleanup_args
+            """
+            return (self.cleanup_func, self.cleanup_args)
+
+
         def do_test(self, function, args=None, fatal=False, cleanup=True):
             """
             Execute subtest function.
@@ -73,7 +83,7 @@  def run_virtio_console(test, params, env):
                 args = []
             res = [None, function.func_name, args]
             try:
-                logging.debug("Start test %s.", function.func_name)
+                logging.info("Start test %s." % function.func_name)
                 ret = function(*args)
                 res[0] = True
                 logging.info(self.result_to_string(res))
@@ -371,16 +381,16 @@  def run_virtio_console(test, params, env):
         """
         Random data receiver/checker thread.
         """
-        def __init__(self, port, buf, event, blocklen=1024):
+        def __init__(self, port, buffer, event, blocklen=1024):
             """
             @param port: Source port.
-            @param buf: Control data buffer (FIFO).
+            @param buffer: Control data buffer (FIFO).
             @param length: Amount of data we want to receive.
             @param blocklen: Block length.
             """
             Thread.__init__(self)
             self.port = port
-            self.buffer = buf
+            self.buffer = buffer
             self.exitevent = event
             self.blocklen = blocklen
             self.idx = 0
@@ -439,26 +449,28 @@  def run_virtio_console(test, params, env):
         @param timeout: Timeout that will be used to verify if the script
                 started properly.
         """
-        logging.debug("compile virtio_console_guest.py on guest %s", vm[0].name)
+        logging.debug("compile virtio_console_guest.py on guest %s",
+                      vm[0].name)
 
-        (match, data) = _on_guest("python -OO /tmp/virtio_console_guest.py -c &&"
-                       "echo -n 'PASS: Compile virtio_guest finished' ||"
+        (match, data) = _on_guest("python -OO /tmp/virtio_console_guest.py -c"
+                       "&& echo -n 'PASS: Compile virtio_guest finished' ||"
                        "echo -n 'FAIL: Compile virtio_guest failed'",
                         vm, timeout)
 
         if match != 0:
-            raise error.TestFail("Command console_switch.py on guest %s failed."
-                                 "\nreturn code: %s\n output:\n%s" %
+            raise error.TestFail("Command console_switch.py on guest %s "
+                                 "failed.\nreturn code: %s\n output:\n%s" %
                                  (vm[0].name, match, data))
-        logging.debug("Starting virtio_console_guest.py on guest %s", vm[0].name)
+        logging.debug("Starting virtio_console_guest.py on guest %s",
+                      vm[0].name)
         vm[1].sendline()
         (match, data) = _on_guest("python /tmp/virtio_console_guest.pyo &&"
                        "echo -n 'PASS: virtio_guest finished' ||"
                        "echo -n 'FAIL: virtio_guest failed'",
                        vm, timeout)
         if match != 0:
-            raise error.TestFail("Command console_switch.py on guest %s failed."
-                                 "\nreturn code: %s\n output:\n%s" %
+            raise error.TestFail("Command console_switch.py on guest %s "
+                                 "failed.\nreturn code: %s\n output:\n%s" %
                                  (vm[0].name, match, data))
         # Let the system rest
         time.sleep(2)
@@ -479,27 +491,27 @@  def run_virtio_console(test, params, env):
         on_guest("virt.init(%s)" % (conss), vm, 10)
 
 
-    def _search_kernel_crashlog(vm, timeout = 2):
+    def _search_kernel_crashlog(vm_port, timeout=2):
         """
         Find kernel crash message.
 
-        @param vm: Informations about the guest.
+        @param vm_port : Guest output port.
         @param timeout: Timeout used to verify expected output.
 
         @return: Kernel crash log or None.
         """
-        data = vm[3].read_nonblocking()
-        match = re.search("^BUG:", data, re.MULTILINE)
+        data = vm_port.read_nonblocking()
+        match = re.search("BUG:", data, re.MULTILINE)
         if match == None:
             return None
 
-        match = re.search(r"^BUG:.*^---\[ end trace .* \]---",
+        match = re.search(r"BUG:.*---\[ end trace .* \]---",
                   data, re.DOTALL |re.MULTILINE)
         if match == None:
-            data += vm[3].read_until_last_line_matches(
-                                            ["---\[ end trace .* \]---"],timeout)
+            data += vm_port.read_until_last_line_matches(
+                                ["---\[ end trace .* \]---"],timeout)
 
-        match = re.search(r"(^BUG:.*^---\[ end trace .* \]---)",
+        match = re.search(r"(BUG:.*---\[ end trace .* \]---)",
                   data, re.DOTALL |re.MULTILINE)
         return match.group(0)
 
@@ -514,10 +526,10 @@  def run_virtio_console(test, params, env):
         @param vm: Informations about the guest.
         @param timeout: Timeout used to verify expected output.
 
-        @return: Tuple (match index, data)
+        @return: Tuple (match index, data, kernel_crash)
         """
-        logging.debug("Executing '%s' on virtio_console_guest.py loop, vm: %s," +
-                      "timeout: %s", command, vm[0].name, timeout)
+        logging.debug("Executing '%s' on virtio_console_guest.py loop," +
+                      " vm: %s, timeout: %s", command, vm[0].name, timeout)
         vm[1].sendline(command)
         try:
             (match, data) = vm[1].read_until_last_line_matches(["PASS:",
@@ -528,7 +540,7 @@  def run_virtio_console(test, params, env):
             match = None
             data = "Timeout."
 
-        kcrash_data = _search_kernel_crashlog(vm)
+        kcrash_data = _search_kernel_crashlog(vm[3])
         if (kcrash_data != None):
             logging.error(kcrash_data)
             vm[4] = True
@@ -550,7 +562,8 @@  def run_virtio_console(test, params, env):
         """
         match, data = _on_guest(command, vm, timeout)
         if match == 1 or match is None:
-            raise error.TestFail("Failed to execute '%s' on virtio_console_guest.py, "
+            raise error.TestFail("Failed to execute '%s' on"
+                                 " virtio_console_guest.py, "
                                  "vm: %s, output:\n%s" %
                                  (command, vm[0].name, data))
 
@@ -587,7 +600,7 @@  def run_virtio_console(test, params, env):
         on_guest("print 'PASS: nothing'", vm, 10)
 
 
-    def _vm_create(no_console=3, no_serialport=3):
+    def _vm_create(no_console=3, no_serialport=3, spread=True):
         """
         Creates the VM and connects the specified number of consoles and serial
         ports.
@@ -608,12 +621,17 @@  def run_virtio_console(test, params, env):
         consoles = []
         serialports = []
         tmp_dir = tempfile.mkdtemp(prefix="virtio-console-", dir="/tmp/")
-        if not params.get('extra_params'):
-            params['extra_params'] = ''
+        #if not params.get('extra_params'):
+        params['extra_params'] = ''
 
+        if not spread:
+            pci = "virtio-serial-pci0"
+            params['extra_params'] += (" -device virtio-serial-pci,id="
+                                           + pci)
+            pci += ".0"
         for i in range(0, no_console):
             # Spread consoles between multiple PCI devices (2 per a dev)
-            if not i % 2:
+            if not i % 2 and spread:
                 pci = "virtio-serial-pci%d" % (i / 2)
                 params['extra_params'] += (" -device virtio-serial-pci,id="
                                            + pci)
@@ -626,7 +644,7 @@  def run_virtio_console(test, params, env):
 
         for i in  range(no_console, no_console + no_serialport):
             # Spread seroal ports between multiple PCI devices (2 per a dev)
-            if not i % 2:
+            if not i % 2  and spread:
                 pci = "virtio-serial-pci%d" % (i / 2)
                 params['extra_params'] += (" -device virtio-serial-pci,id="
                                            + pci)
@@ -637,17 +655,7 @@  def run_virtio_console(test, params, env):
                                        "name=serialport-%d,id=p%d,bus=%s"
                                        % (i, i, i, pci))
 
-        logging.debug("Booting first guest %s", params.get("main_vm"))
-        kvm_preprocessing.preprocess_vm(test, params, env,
-                                        params.get("main_vm"))
-
-        vm = env.get_vm(params.get("main_vm"))
-
-        session = vm.wait_for_login(timeout=float(params.get("boot_timeout", 240)))
-
-        sserial = kvm_test_utils.wait_for_login(vm, 0,
-                                         float(params.get("boot_timeout", 240)),
-                                         0, 2, serial=True)
+        (vm, session, sserial) = _restore_vm()
 
         # connect the sockets
         for i in range(0, no_console):
@@ -662,6 +670,37 @@  def run_virtio_console(test, params, env):
         return [vm, session, tmp_dir, sserial, kcrash], [consoles, serialports]
 
 
+    def _restore_vm():
+        """
+        Restore old virtual machine when VM is destroied.
+        """
+        logging.debug("Booting guest %s", params.get("main_vm"))
+        kvm_preprocessing.preprocess_vm(test, params, env,
+                                        params.get("main_vm"))
+
+        vm = env.get_vm(params.get("main_vm"))
+
+        kernel_bug = None
+        try:
+            session = kvm_test_utils.wait_for_login(vm, 0,
+                                    float(params.get("boot_timeout", 100)),
+                                    0, 2)
+        except (error.TestFail):
+            kernel_bug = _search_kernel_crashlog(vm.serial_console, 10)
+            if kernel_bug != None:
+                logging.error(kernel_bug)
+            raise
+
+        kernel_bug = _search_kernel_crashlog(vm.serial_console, 10)
+        if kernel_bug != None:
+            logging.error(kernel_bug)
+
+        sserial = kvm_test_utils.wait_for_login(vm, 0,
+                                         float(params.get("boot_timeout", 20)),
+                                         0, 2, serial=True)
+        return [vm, session, sserial]
+
+
     def topen(vm, port):
         """
         Open virtioconsole port.
@@ -819,8 +858,8 @@  def run_virtio_console(test, params, env):
             port.close()
 
         on_guest("virt.recv('%s', 0, 1024, False)" % port.name, vm, 10)
-        match, tmp = _on_guest("virt.send('%s', 10, False)"
-                                % port.name, vm, 10)
+        match, tmp = _on_guest("virt.send('%s', 10, True)" % port.name,
+                                                             vm, 10)
         if match != None:
             raise error.TestFail("Write on guest while host disconnected "
                                  "didn't timed out.\nOutput:\n%s"
@@ -1168,7 +1207,7 @@  def run_virtio_console(test, params, env):
         print "CLEANING"
         match, tmp = _on_guest("is_alive()", vm, 10)
         if (match == None) or (match != 0):
-            logging.error("Python died/is stuck/has remaining threads")
+            logging.error("Python died/is stucked/have remaining threads")
             logging.debug(tmp)
             try:
                 if vm[4] == True:
@@ -1176,10 +1215,12 @@  def run_virtio_console(test, params, env):
                 match, tmp = _on_guest("guest_exit()", vm, 10)
                 if (match == None) or (match == 0):
                     vm[1].close()
-                vm[1] = vm[0].wait_for_login(timeout=float(params.get("boot_timeout", 240)))
+                    vm[1] = kvm_test_utils.wait_for_login(vm[0], 0,
+                                        float(params.get("boot_timeout", 5)),
+                                        0, 10)
                 on_guest("killall -9 python "
                          "&& echo -n PASS: python killed"
-                         "|| echo -n PASS: python died",
+                         "|| echo -n PASS: python was death",
                          vm, 10)
 
                 init_guest(vm, consoles)
@@ -1191,10 +1232,22 @@  def run_virtio_console(test, params, env):
                 logging.error("Virtio-console driver is irreparably"
                               " blocked. Every comd end with sig KILL."
                               "Try reboot vm for continue in testing.")
-                vm[1] = vm[0].reboot(vm[1], "system_reset")
+                try:
+                    vm[1] = kvm_test_utils.reboot(vm[0], vm[1], "system_reset")
+                except (kvm_monitor.MonitorProtocolError):
+                    logging.error("Qemu is blocked. Monitor"
+                                  " no longer communicate.")
+                    vm[0].destroy(gracefully = False)
+                    os.system("kill -9 %d" % (vm[0].get_pid()))
+                    (vm[0], vm[1], vm[3]) = _restore_vm()
                 init_guest(vm, consoles)
+                cname = ""
+                try:
+                    cname = consoles[0][0].name
+                except (IndexError):
+                    cname = consoles[1][0].name
                 match = _on_guest("virt.clean_port('%s'),1024" %
-                                      consoles[0][0].name, vm, 10)[0]
+                                  cname, vm, 10)[0]
 
                 if (match == None) or (match != 0):
                     raise error.TestFail("Virtio-console driver is irrepar"
@@ -1204,6 +1257,25 @@  def run_virtio_console(test, params, env):
                 _clean_ports(vm, consoles)
 
 
+    def clean_reload_vm(vm, consoles, expected=False):
+        """
+        Reloads and boots the damaged vm
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param consoles: Consoles which should be clean.
+        """
+        if not expected:
+            print "Scheduled vm reboot"
+        else:
+            print "SCHWARZENEGGER is CLEANING"
+        vm[0].destroy(gracefully=False)
+        shutil.rmtree(vm[2])    # Remove virtio sockets tmp directory
+        (_vm, _consoles) = _vm_create(len(consoles[0]), len(consoles[1]))
+        consoles[:] = _consoles[:]
+        vm[:] = _vm[:]
+        init_guest(vm, consoles)
+
+
     def test_smoke(test, vm, consoles, params):
         """
         Virtio console smoke test.
@@ -1253,12 +1325,23 @@  def run_virtio_console(test, params, env):
         @param consoles: Field of virtio ports with the minimum of 2 items.
         @param params: Test parameters '$console_type:$data;...'
         """
-        test.headline("test_multiport:")
+        subtest.headline("test_multiport:")
         #Test Loopback
-        test.do_test(tloopback, [vm, consoles, params[0]])
+        subtest.do_test(tloopback, [vm, consoles, params[0]])
 
         #Test Performance
-        test.do_test(tperf, [vm, consoles, params[1]])
+        subtest.do_test(tperf, [vm, consoles, params[1]])
+
+
+    def test_destructive(test, vm, consoles):
+        """
+        This is group of test is destructive.
+
+        @param test: Main test object.
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param consoles: Field of virtio ports with the minimum of 2 items.
+        """
+        subtest.headline("test_destructive:")
 
 
     # INITIALIZE
@@ -1294,26 +1377,35 @@  def run_virtio_console(test, params, env):
     pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm')
     vksmd_src = os.path.join(pwd, "scripts/virtio_console_guest.py")
     dst_dir = "/tmp"
+
     vm[0].copy_files_to(vksmd_src, dst_dir)
 
     # ACTUAL TESTING
     # Defines all available consoles; tests udev and sysfs
 
-    test = SubTest()
+    subtest = SubTest()
     try:
         init_guest(vm, consoles)
 
-        test.set_cleanup_func(clean_ports, [vm, consoles])
+        subtest.set_cleanup_func(clean_ports, [vm, consoles])
         #Test Smoke
-        test_smoke(test, vm, consoles, tsmoke_params)
+        test_smoke(subtest, vm, consoles, tsmoke_params)
 
         #Test multiport functionality and performance.
-        test_multiport(test, vm, consoles, [tloopback_params, tperf_params])
+        test_multiport(subtest, vm, consoles, [tloopback_params, tperf_params])
+
+        #Test destructive test.
+        # Uses stronger clean up function
+        (_cleanup_func, _cleanup_args) = subtest.get_cleanup_func()
+        subtest.set_cleanup_func(clean_reload_vm, [vm, consoles])
+        test_destructive(subtest, vm, consoles)
+        subtest.set_cleanup_func(_cleanup_func, _cleanup_args)
     finally:
         logging.info(("Summary: %d tests passed  %d test failed :\n" %
-                      (test.passed, test.failed)) + test.get_text_result())
+                      (subtest.passed, subtest.failed)) +
+                      subtest.get_text_result())
 
-    if test.is_failed():
+    if subtest.is_failed():
         raise error.TestFail("Virtio_console test FAILED.")