Adds support for new tests. Adds new clean function for destructive tests. Corrects kernel crash log monitor. Signed-off-by: JiÅÃ Åupka <jzupka@xxxxxxxxxx> Signed-off-by: LukÃÅ Doktor <ldoktor@xxxxxxxxxx> --- client/tests/kvm/scripts/virtio_console_guest.py | 63 +++++-- client/tests/kvm/tests/virtio_console.py | 208 ++++++++++++++++------ 2 files changed, 197 insertions(+), 74 deletions(-) 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.") -- 1.7.3.5 -- 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