diff mbox

[KVM-Autotest,virtio-console] KVM-test: Add hotplug test.

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

Commit Message

Jiri Zupka Feb. 23, 2011, 2:13 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 6626593..beee062 100755
--- a/client/tests/kvm/scripts/virtio_console_guest.py
+++ b/client/tests/kvm/scripts/virtio_console_guest.py
@@ -547,6 +547,7 @@  class VirtioGuest:
         @param in_files: Array of input files.
         @param out_files: Array of output files.
         @param cachesize: Cachesize.
+        @param mode: Mode of switch.
         """
         self.ports = self._get_port_status()
 
@@ -556,7 +557,7 @@  class VirtioGuest:
         s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode)
         s.start()
         self.threads.append(s)
-        print "PASS: Start switch"
+        print "PASS: Start switch."
 
 
     def exit_threads(self):
diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py
index bc40837..438f297 100644
--- a/client/tests/kvm/tests/virtio_console.py
+++ b/client/tests/kvm/tests/virtio_console.py
@@ -266,11 +266,12 @@  def run_virtio_console(test, params, env):
         """
         Random data sender thread.
         """
-        def __init__(self, port, data, event):
+        def __init__(self, port, data, event, quiet=False):
             """
             @param port: Destination port.
             @param data: The data intend to be send in a loop.
             @param event: Exit event.
+            @param quiet: If true don't raise event when crash.
             """
             Thread.__init__(self)
             self.port = port
@@ -282,14 +283,20 @@  def run_virtio_console(test, params, env):
             self.data = data
             self.exitevent = event
             self.idx = 0
+            self.quiet = quiet
 
 
         def run(self):
             logging.debug("ThSend %s: run", self.getName())
-            while not self.exitevent.isSet():
-                self.idx += self.port.send(self.data)
-            logging.debug("ThSend %s: exit(%d)", self.getName(),
-                          self.idx)
+            try:
+                while not self.exitevent.isSet():
+                    self.idx += self.port.send(self.data)
+                logging.debug("ThSend %s: exit(%d)", self.getName(),
+                              self.idx)
+            except Exception as ints:
+                if not self.quiet:
+                    raise ints
+                logging.debug(ints)
 
 
     class ThSendCheck(Thread):
@@ -352,11 +359,12 @@  def run_virtio_console(test, params, env):
         """
         Recieves data and throws it away.
         """
-        def __init__(self, port, event, blocklen=1024):
+        def __init__(self, port, event, blocklen=1024, quiet=False):
             """
             @param port: Data source port.
             @param event: Exit event.
             @param blocklen: Block length.
+            @param quiet: If true don't raise event when crash.
             """
             Thread.__init__(self)
             self.port = port
@@ -365,16 +373,24 @@  def run_virtio_console(test, params, env):
             self.exitevent = event
             self.blocklen = blocklen
             self.idx = 0
+            self.quiet = quiet
+
+
         def run(self):
             logging.debug("ThRecv %s: run", self.getName())
-            while not self.exitevent.isSet():
-                # TODO: Workaround, it didn't work with select :-/
-                try:
-                    self.idx += len(self.port.recv(self.blocklen))
-                except socket.timeout:
-                    pass
-            self.port.settimeout(self._port_timeout)
-            logging.debug("ThRecv %s: exit(%d)", self.getName(), self.idx)
+            try:
+                while not self.exitevent.isSet():
+                    # TODO: Workaround, it didn't work with select :-/
+                    try:
+                        self.idx += len(self.port.recv(self.blocklen))
+                    except socket.timeout:
+                        pass
+                self.port.settimeout(self._port_timeout)
+                logging.debug("ThRecv %s: exit(%d)", self.getName(), self.idx)
+            except Exception as ints:
+                if not self.quiet:
+                    raise ints
+                logging.debug(ints)
 
 
     class ThRecvCheck(Thread):
@@ -621,7 +637,7 @@  def run_virtio_console(test, params, env):
         consoles = []
         serialports = []
         tmp_dir = tempfile.mkdtemp(prefix="virtio-console-", dir="/tmp/")
-        params['extra_params'] = ''
+        params['extra_params'] = standard_extra_params
 
         if not spread:
             pci = "virtio-serial-pci0"
@@ -638,7 +654,7 @@  def run_virtio_console(test, params, env):
             params['extra_params'] += (" -chardev socket,path=%s/%d,id=vc%d,"
                                        "server,nowait" % (tmp_dir, i, i))
             params['extra_params'] += (" -device virtconsole,chardev=vc%d,"
-                                      "name=console-%d,id=c%d,bus=%s"
+                                      "name=console-%d,id=console-%d,bus=%s"
                                       % (i, i, i, pci))
 
         for i in  range(no_console, no_console + no_serialport):
@@ -651,8 +667,8 @@  def run_virtio_console(test, params, env):
             params['extra_params'] += (" -chardev socket,path=%s/%d,id=vs%d,"
                                        "server,nowait" % (tmp_dir, i, i))
             params['extra_params'] += (" -device virtserialport,chardev=vs%d,"
-                                       "name=serialport-%d,id=p%d,bus=%s"
-                                       % (i, i, i, pci))
+                                       "name=serialport-%d,id=serialport-%d,"
+                                       "bus=%s" % (i, i, i, pci))
 
         (vm, session, sserial) = _restore_vm()
 
@@ -1190,6 +1206,181 @@  def run_virtio_console(test, params, env):
         logging.info("Logged in after migration")
 
 
+    def _virtio_dev_create(vm, ports_name, pciid, id, console="no"):
+        """
+        Add virtio serialport device.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param ports_name: Structure of ports.
+        @param pciid: Id of virtio-serial-pci device.
+        @param id: Id of port.
+        @param console: if "yes" inicialize console.
+        """
+        port = "serialport-"
+        port_type = "virtserialport"
+        if console == "yes":
+            port = "console-"
+            port_type = "virtconsole"
+        port += "%d%d" % (pciid, id)
+        ret = vm[0].monitors[0].cmd("device_add %s,"
+                                    "bus=virtio-serial-pci%d.0,"
+                                    "id=%s,"
+                                    "name=%s"
+                                    % (port_type, pciid, port, port))
+        ports_name.append([ port, console])
+        if ret != "":
+            logging.error(ret)
+
+
+    def _virtio_dev_del(vm, ports_name, pciid, id):
+        """
+        Del virtio serialport device.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param ports_name: Structure of ports.
+        @param pciid: Id of virtio-serial-pci device.
+        @param id: Id of port.
+        """
+        port = filter(lambda x: x[0].endswith("-%d%d" % (pciid, id)),
+                      ports_name)
+        ret = vm[0].monitors[0].cmd("device_del %s"
+                                        % (port[0][0]))
+        ports_name.remove(port[0])
+        if ret != "":
+            logging.error(ret)
+
+
+    def thotplug(vm, consoles, console="no", timeout=1):
+        """
+        Try hotplug function of virtio-consoles ports.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param consoles: Consoles.
+        @param console: If "yes" inicialize console.
+        @param timeout: Timeout between hotplug operations.
+        """
+        logging.info("Timeout between hotplug operations t=%fs" % timeout)
+        _reset_vm(vm, consoles, 1, 1)
+        ports_name = []
+        ports_name.append(['serialport-1','no'])
+        ports_name.append(['console-0','yes'])
+
+        logging.info("Test corect initialization of hotplug ports.")
+        for id in range(1,5): #count of pci device
+            ret = vm[0].monitors[0].cmd("device_add virtio-serial-pci,"
+                                        "id=virtio-serial-pci%d" % (id))
+            if ret != "":
+                logging.error(ret)
+            for i in range(id*5+5): #max port 30
+                _virtio_dev_create(vm, ports_name, id, i, console)
+                time.sleep(timeout)
+
+        # Test corect initialization of hotplug ports.
+        time.sleep(10) #Timeout for port initialization.
+        _init_guest(vm, 10)
+        on_guest('virt.init(%s)' % (ports_name), vm, 10)
+
+        logging.info("Delete ports when ports are used.")
+        # Delete ports when ports are used.
+        if not consoles[0][0].is_open:
+            consoles[0][0].open()
+        if not consoles[1][0].is_open:
+            consoles[1][0].open()
+        on_guest("virt.loopback(['%s'], ['%s'], 1024,"
+                 "virt.LOOP_POLL)" % (consoles[0][0].name,
+                                      consoles[1][0].name), vm, 10)
+        exit_event = threading.Event()
+        send = ThSend(consoles[0][0].sock, "Data", exit_event, quiet = True)
+        recv = ThRecv(consoles[1][0].sock, exit_event, quiet = True)
+        send.start()
+        time.sleep(2)
+        recv.start()
+
+        # Try delete ports under load.
+        ret = vm[0].monitors[0].cmd("device_del serialport-1")
+        ret += vm[0].monitors[0].cmd("device_del console-0")
+        ports_name.remove(['serialport-1','no'])
+        ports_name.remove(['console-0','yes'])
+        if ret != "":
+            logging.error(ret)
+
+        exit_event.set()
+        send.join()
+        recv.join()
+        on_guest("virt.exit_threads()", vm, 10)
+        on_guest('guest_exit()', vm, 10)
+
+        logging.info("Trying add maximum count of ports to one pci device.")
+        # Try add ports.
+        for i in range(30): #max port 30
+            _virtio_dev_create(vm, ports_name, 0, i, console)
+            time.sleep(timeout)
+        _init_guest(vm, 10)
+        time.sleep(10)
+        on_guest('virt.init(%s)' % (ports_name), vm, 20)
+        on_guest('guest_exit()', vm, 10)
+
+        logging.info("Trying delete and add again part of ports.")
+        # Try delete.
+        for i in range(25): #max port 30
+            _virtio_dev_del(vm, ports_name, 0, i)
+            time.sleep(timeout)
+        _init_guest(vm, 10)
+        on_guest('virt.init(%s)' % (ports_name), vm, 10)
+        on_guest('guest_exit()', vm, 10)
+
+        # Try add ports.
+        for i in range(5): #max port 30
+            _virtio_dev_create(vm, ports_name, 0, i, console)
+            time.sleep(timeout)
+        _init_guest(vm, 10)
+        on_guest('virt.init(%s)' % (ports_name), vm, 10)
+        on_guest('guest_exit()', vm, 10)
+
+        logging.info("Trying 100 times add and delete one port.")
+        # Try 100 times add and delete one port.
+        for i in range(100):
+            _virtio_dev_del(vm, ports_name, 0, 0)
+            time.sleep(timeout)
+            _virtio_dev_create(vm, ports_name, 0, 0, console)
+            time.sleep(timeout)
+        _init_guest(vm, 10)
+        on_guest('virt.init(%s)' % (ports_name), vm, 10)
+        on_guest('guest_exit()', vm, 10)
+
+
+    def thotplug_no_timeout(vm, consoles, console="no"):
+        """
+        Start hotplug test without any timeout.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param consoles: Consoles which should be close before rmmod.
+        @param console: If "yes" inicialize console.
+        """
+        thotplug(vm, consoles, console, 0)
+
+
+    def thotplug_virtio_pci(vm, consoles):
+        """
+        Test hotplug of virtio-serial-pci.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param consoles: Consoles which should be close before rmmod.
+        """
+        vm[0].destroy(gracefully = False)
+        (vm, consoles) = _vm_create(1, 1, False)
+        id = 1
+        ret = vm[0].monitors[0].cmd("device_add virtio-serial-pci,"
+                                    "id=virtio-serial-pci%d" % (id))
+        time.sleep(10)
+        ret += vm[0].monitors[0].cmd("device_del virtio-serial-pci%d" % (id))
+        time.sleep(10)
+        ret += vm[0].monitors[0].cmd("device_add virtio-serial-pci,"
+                                    "id=virtio-serial-pci%d" % (id))
+        if ret != "":
+            logging.error(ret)
+
+
     def tloopback(vm, consoles, params):
         """
         Virtio console loopback subtest.
@@ -1446,6 +1637,11 @@  def run_virtio_console(test, params, env):
             logging.error("Python died/is stucked/have remaining threads")
             logging.debug(tmp)
             try:
+                kernel_bug = _search_kernel_crashlog(vm[0].serial_console, 10)
+                if kernel_bug is not None:
+                    logging.error(kernel_bug)
+                    raise error.TestFail("Kernel crash.")
+
                 if vm[4] == True:
                     raise error.TestFail("Kernel crash.")
                 match, tmp = _on_guest("guest_exit()", vm, 10)
@@ -1493,6 +1689,22 @@  def run_virtio_console(test, params, env):
                 _clean_ports(vm, consoles)
 
 
+    def _reset_vm(vm, consoles, no_console=1, no_serialport=1):
+        """
+        Destroy and reload vm.
+
+        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
+        @param consoles: Consoles which should be close and than renew.
+        @param no_console: Number of desired virtconsoles.
+        @param no_serialport: Number of desired virtserialports.
+        """
+        vm[0].destroy(gracefully=False)
+        shutil.rmtree(vm[2])    # Remove virtio sockets tmp directory
+        (_vm, _consoles) = _vm_create(no_console, no_serialport)
+        consoles[:] = _consoles[:]
+        vm[:] = _vm[:]
+
+
     def clean_reload_vm(vm, consoles, expected=False):
         """
         Reloads and boots the damaged vm
@@ -1504,15 +1716,11 @@  def run_virtio_console(test, params, env):
             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[:]
+        _reset_vm(vm, consoles, len(consoles[0]), len(consoles[1]))
         init_guest(vm, consoles)
 
 
-    def test_smoke(test, vm, consoles, params):
+    def test_smoke(test, vm, consoles, params, global_params):
         """
         Virtio console smoke test.
 
@@ -1523,41 +1731,43 @@  def run_virtio_console(test, params, env):
         @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
         @param consoles: Field of virtio ports with the minimum of 2 items.
         @param params: Test parameters '$console_type:$data;...'
+        @param global_params: Params defined by tests_base.conf.
         """
         # PREPARE
-        for param in params.split(';'):
-            if not param:
-                continue
-            headline = "test_smoke: params: %s" % (param)
-            logging.info(headline)
-            param = param.split(':')
-            if len(param) > 1:
-                data = param[1]
-            else:
-                data = "Smoke test data"
-            param = (param[0] == 'serialport')
-            send_pt = consoles[param][0]
-            recv_pt = consoles[param][1]
-            subtest.headline(headline)
-            subtest.do_test(tcheck_zero_sym, [vm], cleanup=False)
-            subtest.do_test(topen, [vm, send_pt], True)
-            subtest.do_test(tclose, [vm, send_pt], True)
-            subtest.do_test(tmulti_open, [vm, send_pt])
-            subtest.do_test(tpooling, [vm, send_pt])
-            subtest.do_test(tsigio, [vm, send_pt])
-            subtest.do_test(tlseek, [vm, send_pt])
-            subtest.do_test(trw_host_offline, [vm, send_pt])
-            subtest.do_test(trw_host_offline_big_data, [vm, send_pt],
-                            cleanup=False)
-            subtest.do_test(trw_notconnect_guest,
-                            [vm, send_pt, consoles])
-            subtest.do_test(trw_nonblocking_mode, [vm, send_pt])
-            subtest.do_test(trw_blocking_mode, [vm, send_pt])
-            subtest.do_test(tbasic_loopback, [vm, send_pt, recv_pt, data],
-                            True)
-
-
-    def test_multiport(test, vm, consoles, params):
+        if (global_params.get('smoke_test') == "yes"):
+            for param in params.split(';'):
+                if not param:
+                    continue
+                headline = "test_smoke: params: %s" % (param)
+                logging.info(headline)
+                param = param.split(':')
+                if len(param) > 1:
+                    data = param[1]
+                else:
+                    data = "Smoke test data"
+                param = (param[0] == 'serialport')
+                send_pt = consoles[param][0]
+                recv_pt = consoles[param][1]
+                subtest.headline(headline)
+                subtest.do_test(tcheck_zero_sym, [vm], cleanup=False)
+                subtest.do_test(topen, [vm, send_pt], True)
+                subtest.do_test(tclose, [vm, send_pt], True)
+                subtest.do_test(tmulti_open, [vm, send_pt])
+                subtest.do_test(tpooling, [vm, send_pt])
+                subtest.do_test(tsigio, [vm, send_pt])
+                subtest.do_test(tlseek, [vm, send_pt])
+                subtest.do_test(trw_host_offline, [vm, send_pt])
+                subtest.do_test(trw_host_offline_big_data, [vm, send_pt],
+                                cleanup=False)
+                subtest.do_test(trw_notconnect_guest,
+                                [vm, send_pt, consoles])
+                subtest.do_test(trw_nonblocking_mode, [vm, send_pt])
+                subtest.do_test(trw_blocking_mode, [vm, send_pt])
+                subtest.do_test(tbasic_loopback, [vm, send_pt, recv_pt, data],
+                                True)
+
+
+    def test_multiport(test, vm, consoles, params, global_params):
         """
         This is group of test which test virtio_console in maximal load and
         with multiple ports.
@@ -1566,34 +1776,59 @@  def run_virtio_console(test, params, env):
         @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
         @param consoles: Field of virtio ports with the minimum of 2 items.
         @param params: Test parameters '$console_type:$data;...'
+        @param global_params: Params defined by tests_base.conf.
         """
         subtest.headline("test_multiport:")
         # Test Loopback
-        subtest.do_test(tloopback, [vm, consoles, params[0]])
+        if (global_params.get('loopback_test') == "yes"):
+            subtest.do_test(tloopback, [vm, consoles, params[0]])
 
         # Test Performance
-        subtest.do_test(tperf, [vm, consoles, params[1]])
+        if (global_params.get('perf_test') == "yes"):
+            subtest.do_test(tperf, [vm, consoles, params[1]])
 
 
-    def test_destructive(test, vm, consoles):
+    def test_destructive(test, vm, consoles, global_params):
         """
         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.
+        @param global_params: Params defined by tests_base.conf.
         """
         subtest.headline("test_destructive:")
-        # Test rmmod
-        subtest.do_test(trmmod, [vm, consoles])
-        subtest.do_test(tmax_serial_ports, [vm, consoles])
-        subtest.do_test(tmax_console_ports, [vm, consoles])
-        subtest.do_test(tmax_mix_serial_conosle_port, [vm, consoles])
-        subtest.do_test(tshutdown, [vm, consoles])
-        subtest.do_test(tmigrate_offline, [vm, consoles])
+        # Uses stronger clean up function
+        (_cleanup_func, _cleanup_args) = subtest.get_cleanup_func()
+        subtest.set_cleanup_func(clean_reload_vm, [vm, consoles])
+
+        if (global_params.get('rmmod_test') == "yes"):
+            subtest.do_test(trmmod,[vm, consoles])
+        if (global_params.get('max_ports_test') == "yes"):
+            subtest.do_test(tmax_serial_ports, [vm, consoles])
+            subtest.do_test(tmax_console_ports, [vm, consoles])
+            subtest.do_test(tmax_mix_serial_conosle_port, [vm, consoles])
+        if (global_params.get('shutdown_test') == "yes"):
+            subtest.do_test(tshutdown, [vm, consoles])
+        if (global_params.get('migrate_test') == "yes"):
+            subtest.do_test(tmigrate_offline, [vm, consoles])
+        if (global_params.get('hotplug_serial_test') == "yes"):
+            subtest.do_test(thotplug, [vm, consoles])
+            subtest.do_test(thotplug_no_timeout, [vm, consoles])
+        if (global_params.get('hotplug_console_test') == "yes"):
+            subtest.do_test(thotplug, [vm, consoles, "yes"])
+            subtest.do_test(thotplug_no_timeout, [vm, consoles, "yes"])
+        if (global_params.get('hotplug_pci_test') == "yes"):
+            subtest.do_test(thotplug_virtio_pci, [vm, consoles])
+
+        subtest.set_cleanup_func(_cleanup_func, _cleanup_args)
 
 
     # INITIALIZE
+    if "extra_params" in params:
+        standard_extra_params = params['extra_params']
+    else:
+        standard_extra_params = ""
 
     tsmoke_params = params.get('virtio_console_smoke', '')
     tloopback_params = params.get('virtio_console_loopback', '')
@@ -1638,17 +1873,14 @@  def run_virtio_console(test, params, env):
 
         subtest.set_cleanup_func(clean_ports, [vm, consoles])
         # Test Smoke
-        test_smoke(subtest, vm, consoles, tsmoke_params)
+        test_smoke(subtest, vm, consoles, tsmoke_params, params)
 
         # Test multiport functionality and performance.
-        test_multiport(subtest, vm, consoles, [tloopback_params, tperf_params])
+        test_multiport(subtest, vm, consoles, [tloopback_params, tperf_params],
+                       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)
+        #Test destructive test.
+        test_destructive(subtest, vm, consoles, params)
     finally:
         logging.info(("Summary: %d tests passed  %d test failed :\n" %
                       (subtest.passed, subtest.failed)) +
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index 661d6fe..49ba53d 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -759,13 +759,25 @@  variants:
         # smoke params - $console_type:data_string
         # FIXME: test_smoke doesn't work with console yet (virtio_console bug)
         # "serialport;console:Custom data"
+        smoke_test = yes
         virtio_console_smoke = "serialport"
         # loopback params - '$source_console_type@buffer_length:$destination_console_type1@buffer_length:...:$loopback_buffer_length;...'
+        loopback_test = yes
         virtio_console_loopback = "serialport:serialport;serialport@1024:serialport@32:console@1024:console@8:16"
         # perf params - $console_type@buffer_length:$test_duration
         # FIXME: test_perf doesn't work with console yet (virtio_console bug)
         # virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
+        perf_test = yes
         virtio_console_perf = "serialport;serialport@1000000:120"
+        #Enable destructive tests: "test_name  = yes"
+        #Disable test: change yes or delete key.
+        rmmod_test = yes
+        max_ports_test = yes
+        shutdown_test = yes
+        migrate_test = yes
+        hotplug_test = yes
+        hotplug_serial_test = yes
+        hotplug_console_test = no
 
     # This unit test module is for older branches of KVM that use the
     # kvmctl test harness (such as the code shipped with RHEL 5.x)