Tests: Hotplug of virtioserial and console. Hotplug of virtio-serial-pci device. Signed-off-by: JiÅÃ Åupka <jzupka@xxxxxxxxxx> --- client/tests/kvm/scripts/virtio_console_guest.py | 3 +- client/tests/kvm/tests/virtio_console.py | 382 +++++++++++++++++----- client/tests/kvm/tests_base.cfg.sample | 12 + 3 files changed, 321 insertions(+), 76 deletions(-) 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) -- 1.7.4 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html