All of lore.kernel.org
 help / color / mirror / Atom feed
* [KVM-autotest] virtio_console test v3.0
@ 2010-09-15 15:41 Lukas Doktor
  2010-09-15 15:41 ` Lukas Doktor
  0 siblings, 1 reply; 3+ messages in thread
From: Lukas Doktor @ 2010-09-15 15:41 UTC (permalink / raw)
  To: ldoktor, jzupka, autotest, kvm, lmr, amit.shah

Cheers,

we are back with new version of virtio_console. This version is more similar to upstream C virtio_console test so it will be easier to maintain. Also we moved the scripts/console_switch.py to more sensible scripts/virtio_guest.py

the patch with explanation follows.

Best regards,
Lukas and Jiri

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [KVM-autotest] virtio_console test v3.0
  2010-09-15 15:41 [KVM-autotest] virtio_console test v3.0 Lukas Doktor
@ 2010-09-15 15:41 ` Lukas Doktor
  2010-09-17  8:52   ` Amit Shah
  0 siblings, 1 reply; 3+ messages in thread
From: Lukas Doktor @ 2010-09-15 15:41 UTC (permalink / raw)
  To: ldoktor, jzupka, autotest, kvm, lmr, amit.shah

New version of virtio_console test is more similar to upstream C virtio_console test so it will be easier to maintain. Also we moved the scripts/console_switch.py to more sensible scripts/virtio_guest.py

There are still some virtio_console bugs which restricts some usage (mostly with console). We have created workarounds which enables us to run the tests. They are marked as FIXME comments.

It tests more virtio_console features:
[preparation]:
* Prepare for testing
* test parameters '$console_type:$data;...'
1) creates GUEST machine with virtio_ports (serialport/consoles)
2) Initiate connection; defines and verifies the virtio_ports on GUEST side.

[test_smoke]:
* Tests the basic capabilities of virtio_consoles.
* test parameters, multiple recievers allowe. '$source_console_type@$buffer_length:$destination_console_type1@buffer_length:...:$loopback_buffer_length;...'

1) POLL test (IN,OUT,HUP)
2) Read/write without connected host
3) Read in nonblocking and blocking mode
4) Basic loopback test (different from test_loopback test)

[test_loopback]:
*Creates a loopback between sender port and receiving port, send data through this connection, verify data correctness.
* test parameters '$console_type@$buffer_length:$test_duration;...'
* link checking mode is configurable by virtio_check_mode = {none, poll, select}
1) GUEST: creates loopback between specified ports
2) HOST: creates thread for sending data and storing them into verification buffer
3) HOST: creates threads for receiving data and comparing them with verification buffer
4) let it work for 60 seconds
5) Exit threads and loopback

[test_perf]:
* Measure performance for the virtio console tunnel
---< Host->Guest >---
1) GUEST: creates loopback between the port and nothing (read and forget)
2) HOST: prepare for data send (sending thread, stats, cpu loads)
3) HOST: starts sending the data in loop for specified period of time
4) HOST: stop the sending and process stats/cpu loads
5) Exit threads and loopback

---< Guest->Host >---
1) GUEST: inits sender thread
2) HOST: prepare for receiving data (recv thread, stats, cpu loads)
3) GUEST: starts sending the data
4) HOST: stop logging stats
5) GUEST: exit sending thread
6) HOST: finish receiving

Signed-off-by: Lukas Doktor <ldoktor@redhat.com>
Signed-off-by: Jiri Zupka <jzupka@redhat.com>
---
 client/tests/kvm/scripts/console_switch.py |  219 ---------
 client/tests/kvm/scripts/virtio_guest.py   |  571 ++++++++++++++++++++++
 client/tests/kvm/tests/virtio_console.py   |  730 +++++++++++++++++-----------
 client/tests/kvm/tests_base.cfg.sample     |    8 +-
 4 files changed, 1022 insertions(+), 506 deletions(-)
 delete mode 100644 client/tests/kvm/scripts/console_switch.py
 create mode 100644 client/tests/kvm/scripts/virtio_guest.py

diff --git a/client/tests/kvm/scripts/console_switch.py b/client/tests/kvm/scripts/console_switch.py
deleted file mode 100644
index 3df4094..0000000
--- a/client/tests/kvm/scripts/console_switch.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-"""
-Auxiliary script used to send data between ports on guests.
-
-@copyright: 2008-2009 Red Hat Inc.
-@author: Jiri Zupka (jzupka@redhat.com)
-@author: Lukas Doktor (ldoktor@redhat.com)
-"""
-import threading
-from threading import Thread
-import os,time,select,re,random,sys,array
-
-files = {}
-ev = threading.Event()
-threads = []
-
-DEBUGPATH="/sys/kernel/debug"
-
-
-class Switch(Thread):
-    """
-    Create a thread which sends data between ports.
-    """
-    def __init__(self, exitevent, in_files, out_files, cachesize=1):
-        """
-        @param exitevent: Event to end switch.
-        @param in_files: Array of input files.
-        @param out_files: Array of output files.
-        @param cachesize: Block to receive and send.
-        """
-        Thread.__init__(self)
-
-        self.in_files = in_files
-        self.out_files = out_files
-
-        self.cachesize = cachesize
-        self.exitevent = exitevent
-
-
-    def run(self):
-        while not self.exitevent.isSet():
-            #TODO: Why select causes trouble? :-(
-            #ret = select.select(self.in_files,[],[],1.0)
-            data = ""
-            #if not ret[0] == []:
-            for desc in self.in_files:
-                data += os.read(desc, self.cachesize)
-            for desc in self.out_files:
-                os.write(desc, data)
-
-
-class Sender(Thread):
-    """
-    Creates thread which sends random blocks of data to the destination port.
-    """
-    def __init__(self, port, length):
-        """
-        @param port: Destination port.
-        @param length: Length of the random data block.
-        """
-        Thread.__init__(self)
-        self.port = port
-        self.data = array.array('L')
-        for i in range(max(length/self.data.itemsize, 1)):
-            self.data.append(random.randrange(sys.maxint))
-
-
-    def run(self):
-        while True:
-            os.write(self.port, self.data)
-        del threads[:]
-
-
-def get_port_status():
-    """
-    Get info about ports from kernel debugfs.
-
-    @return: ports dictionary of port properties
-    """
-    ports = {}
-
-    not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
-    if not os.path.ismount(DEBUGPATH):
-        os.system('mount -t debugfs none %s' % DEBUGPATH)
-    try:
-        if not os.path.isdir('%s/virtio-ports' % DEBUGPATH):
-            print not_present_msg
-    except:
-        print not_present_msg
-    else:
-        viop_names = os.listdir('%s/virtio-ports' % DEBUGPATH)
-        for name in viop_names:
-            f = open("%s/virtio-ports/%s" % (DEBUGPATH, name), 'r')
-            port = {}
-            for line in iter(f):
-                m = re.match("(\S+): (\S+)",line)
-                port[m.group(1)] = m.group(2)
-
-            if (port['is_console'] == "yes"):
-                port["path"] = "/dev/hvc%s" % port["console_vtermno"]
-                # Console works like a serialport
-            else:
-                port["path"] = "/dev/%s" % name
-            ports[port['name']] = port
-            f.close()
-
-    return ports
-
-
-def open_device(in_files, ports):
-    """
-    Open devices and return an array of descriptors.
-
-    @param in_files: files array
-    @return: array of descriptors
-    """
-    f = []
-
-    for item in in_files:
-        name = ports[item[0]]["path"]
-        if (not item[1] == ports[item[0]]["is_console"]):
-            print ports
-            print "FAIL: Host console is not like console on guest side\n"
-
-        if (name in files):
-            f.append(files[name])
-        else:
-            try:
-                files[name] = os.open(name, os.O_RDWR)
-                if (ports[item[0]]["is_console"] == "yes"):
-                    print os.system("stty -F %s raw -echo" %
-                                    (ports[item[0]]["path"]))
-                    print os.system("stty -F %s -a" % ports[item[0]]["path"])
-                f.append(files[name])
-            except Exception as inst:
-                print "FAIL: Failed to open file %s" % name
-                raise inst
-    return f
-
-
-def start_switch(in_files,out_files,cachesize=1):
-    """
-    Start a switch thread
-    (because there is a problem with opening one file multiple times).
-
-    @param in_files: array of input files
-    @param out_files: array of output files
-    @param cachesize: cachesize
-    """
-    ports = get_port_status()
-
-    in_f = open_device(in_files, ports)
-    out_f = open_device(out_files, ports)
-
-    s = Switch(ev, in_f, out_f, cachesize)
-    s.start()
-    threads.append(s)
-
-    print "PASS: Start switch"
-
-
-def end_switches():
-    """
-    End all running data switches.
-    """
-    ev.set()
-    for th in threads:
-        print "join"
-        th.join(3.0)
-    ev.clear()
-
-    del threads[:]
-    print "PASS: End switch"
-
-
-def die():
-    """
-    Quit consoleswitch.
-    """
-    for desc in files.itervalues():
-        os.close(desc)
-    current_pid = os.getpid()
-    os.kill(current_pid, 15)
-
-
-def sender_prepare(port, length):
-    """
-    Prepares the sender thread. Requires a clean thread structure.
-    """
-    del threads[:]
-    ports = get_port_status()
-    in_f = open_device([port], ports)
-
-    threads.append(Sender(in_f[0], length))
-    print "PASS: Sender prepare"
-
-
-def sender_start():
-    """
-    Start sender data transfer. Requires sender_prepare to run first.
-    """
-    threads[0].start()
-    print "PASS: Sender start"
-
-
-def main():
-    """
-    Main (infinite) loop of console_switch.
-    """
-    print "PASS: Start"
-    end = False
-    while not end:
-        str = raw_input()
-        exec str
-
-
-if __name__ == "__main__":
-    main()
diff --git a/client/tests/kvm/scripts/virtio_guest.py b/client/tests/kvm/scripts/virtio_guest.py
new file mode 100644
index 0000000..a0f9df8
--- /dev/null
+++ b/client/tests/kvm/scripts/virtio_guest.py
@@ -0,0 +1,571 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+Auxiliary script used to send data between ports on guests.
+
+@copyright: 2008-2009 Red Hat Inc.
+@author: Jiri Zupka (jzupka@redhat.com)
+@author: Lukas Doktor (ldoktor@redhat.com)
+"""
+#from _pydev_SimpleXMLRPCServer import fcntl
+
+"""
+TODO:
+virt.init([consoles])   # sysfs, udev, OK
+virt.open(name)
+virt.close(name)
+virt.poll(name, eventmask, timeout) # poll.register(), poll.poll(),
+return event
+virt.send(name, length) # host disconnected
+virt.recv(name, length) # host disconnected
+virt.blocking(name, true)   # true = blocking, false = nonblocking
+virt.loopback(in_names, out_names, type="None")  # use select/poll
+"""
+
+import threading
+from threading import Thread
+import os, time, select, re, random, sys, array, fcntl, array, subprocess
+
+DEBUGPATH = "/sys/kernel/debug"
+SYSFSPATH = "/sys/class/virtio-ports/"
+
+
+class virtio_guest():
+
+    LOOP_NONE = 0
+    LOOP_POLL = 1
+    LOOP_SELECT = 2
+
+    def __init__(self):
+        self.files = {}
+        self.exit_thread = threading.Event()
+        self.threads = []
+        self.ports = {}
+
+    def _readfile(self, name):
+        """
+        Read file and return content as string
+
+        @param name: Name of file
+        @return: Content of file as string
+        """
+        out = ""
+        try:
+            f = open(name, "r")
+            out = f.read()
+            f.close()
+        except:
+            print "FAIL: Cannot open file %s" % (name)
+
+        return out
+
+    def _get_port_status(self):
+        """
+        Get info about ports from kernel debugfs.
+
+        @return: Ports dictionary of port properties
+        """
+        ports = {}
+        not_present_msg = "FAIL: There's no virtio-ports dir in debugfs"
+        if (not os.path.ismount(DEBUGPATH)):
+            os.system('mount -t debugfs none %s' % (DEBUGPATH))
+        try:
+            if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)):
+                print not_present_msg
+        except:
+            print not_present_msg
+        else:
+            viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH))
+            for name in viop_names:
+                f = open("%s/virtio-ports/%s" % (DEBUGPATH, name), 'r')
+                port = {}
+                for line in iter(f):
+                    m = re.match("(\S+): (\S+)", line)
+                    port[m.group(1)] = m.group(2)
+
+                if (port['is_console'] == "yes"):
+                    port["path"] = "/dev/hvc%s" % (port["console_vtermno"])
+                    # Console works like a serialport
+                else:
+                    port["path"] = "/dev/%s" % name
+
+                if (not os.path.exists(port['path'])):
+                    print "FAIL: %s not exist" % port['path']
+
+                sysfspath = SYSFSPATH + name
+                if (not os.path.isdir(sysfspath)):
+                    print "FAIL: %s not exist" % (sysfspath)
+
+                info_name = sysfspath + "/name"
+                port_name = self._readfile(info_name).strip()
+                if (port_name != port["name"]):
+                    print "FAIL: Port info not match \n%s - %s\n%s - %s" \
+                    % (info_name , port_name, \
+                       "%s/virtio-ports/%s" % (DEBUGPATH, name), port["name"])
+
+                ports[port['name']] = port
+                f.close()
+
+        return ports
+
+    def init(self, in_files):
+        """
+        Init and check port properties
+        """
+        self.ports = self._get_port_status()
+
+        for item in in_files:
+            if (item[1] != self.ports[item[0]]["is_console"]):
+                print self.ports
+                print "FAIL: Host console is not like console on guest side\n"
+        print "PASS: Init and check virtioconsole files in system."
+
+    class switch(Thread):
+        """
+        Create a thread which sends data between ports.
+        """
+        def __init__ (self, in_files, out_files, event, \
+                      cachesize=1024, method=0):
+            """
+            @param in_files: Array of input files
+            @param out_files: Array of output files
+            @param method: Method of read/write access
+            @param cachesize: Block to receive and send
+            """
+            Thread.__init__(self)
+
+            self.in_files = in_files
+            self.out_files = out_files
+            self.exit_thread = event
+            self.method = method
+
+            self.cachesize = cachesize
+
+        def _none_mode(self):
+            """
+            Read and write to device in blocking mode
+            """
+            data = ""
+            while not self.exit_thread.isSet():
+                data = ""
+                for desc in self.in_files:
+                    data += os.read(desc, self.cachesize)
+                if data != "":
+                    for desc in self.out_files:
+                        os.write(desc, data)
+
+        def _poll_mode(self):
+            """
+            Read and write to device in polling mode
+            """
+
+            pi = select.poll()
+            po = select.poll()
+
+            for fd in self.in_files:
+                pi.register(fd, select.POLLIN)
+
+            for fd in self.out_files:
+                po.register(fd, select.POLLOUT)
+            readyf = []
+            data = ""#array.array('B')
+            while not self.exit_thread.isSet():
+                data = ""
+                t_out = self.out_files
+
+                readyf = pi.poll(1.0)
+                for i in readyf:
+                    try:
+                        data += os.read(desc, self.cachesize)
+                    except EOFError:
+                        pass
+
+                if data.count(x):
+                    readyf = []
+                    while (len(t_out) != len(readyf)) and \
+                            not self.exit_thread.isSet():
+                        readyf = po.poll(1.0)
+                    for desc in t_out:
+                        os.write(desc, data)
+
+
+
+        def _select_mode(self):
+            """
+            Read and write to device in selecting mode
+            """
+            data = ""
+            ret = []
+            while not self.exit_thread.isSet():
+                #TODO: Why select causes trouble? :-(
+                ret = select.select(self.in_files, [], [], 1.0)
+                data = ""
+                if ret[0] != []:
+                    for desc in ret[0]:
+                        data += os.read(desc, self.cachesize)
+                if data != "":
+                    ret = select.select([], self.out_files, [], 1.0)
+                    while (len(self.out_files) != len(ret[1])) and \
+                            not self.exit_thread.isSet():
+                        ret = select.select([], self.out_files, [], 1.0)
+                    for desc in ret[1]:
+                        os.write(desc, data)
+
+        def run(self):
+            if (self.method == virtio_guest.LOOP_POLL):
+                self._poll_mode()
+            elif (self.method == virtio_guest.LOOP_SELECT):
+                self._select_mode()
+            else:
+                self._none_mode()
+
+        def _poll_mode(self):
+            """
+            Read and write to device in polling mode
+            """
+
+            pi = select.poll()
+            po = select.poll()
+
+            for fd in self.in_files:
+                pi.register(fd, select.POLLIN)
+
+            for fd in self.out_files:
+                po.register(fd, select.POLLOUT)
+
+            while not self.exit_thread.isSet():
+                data = ""
+                t_out = self.out_files
+
+                readyf = pi.poll(1.0)
+                for i in readyf:
+                    data += os.read(i[0], self.cachesize)
+
+                if data != "":
+                    while (len(t_out) != len(readyf)) and \
+                            not self.exit_thread.isSet():
+                        readyf = po.poll(1.0)
+                    for desc in t_out:
+                        os.write(desc, data)
+
+
+
+        def _select_mode(self):
+            """
+            Read and write to device in selecting mode
+            """
+            while not self.exit_thread.isSet():
+                #TODO: Why select causes trouble? :-(
+                ret = select.select(self.in_files, [], [], 1.0)
+                data = ""
+                if ret[0] != []:
+                    for desc in ret[0]:
+                        data += os.read(desc, self.cachesize)
+                if data != "":
+                    ret = select.select([], self.out_files, [], 1.0)
+                    while (len(self.out_files) != len(ret[1])) and \
+                            not self.exit_thread.isSet():
+                        ret = select.select([], self.out_files, [], 1.0)
+                    for desc in ret[1]:
+                        os.write(desc, data)
+
+        def run(self):
+            if (self.method == virtio_guest.LOOP_POLL):
+                self._poll_mode()
+            elif (self.method == virtio_guest.LOOP_SELECT):
+                self._select_mode()
+            else:
+                self._none_mode()
+
+    class sender(Thread):
+        """
+        Creates thread which sends random blocks of data to the destination
+        port.
+        """
+        def __init__(self, port, event, length):
+            """
+            @param port: Destination port
+            @param length: Length of the random data block
+            """
+            Thread.__init__(self)
+            self.port = port
+            self.exit_thread = event
+            self.data = array.array('L')
+            for i in range(max(length / self.data.itemsize, 1)):
+                self.data.append(random.randrange(sys.maxint))
+
+        def run(self):
+            while not self.exit_thread.isSet():
+                os.write(self.port, self.data)
+
+
+    def _open(self, in_files):
+        """
+        Open devices and return array of descriptors
+
+        @param in_files: Files array
+        @return: Array of descriptor
+        """
+
+        f = []
+
+        for item in in_files:
+            name = self.ports[item]["path"]
+            if (name in self.files):
+                f.append(self.files[name])
+            else:
+                try:
+                    self.files[name] = os.open(name, os.O_RDWR)
+                    if (self.ports[item]["is_console"] == "yes"):
+                        print os.system("stty -F %s raw -echo" % (name))
+                        print os.system("stty -F %s -a" % (name))
+                    f.append(self.files[name])
+                except Exception as inst:
+                    print "FAIL: Failed to open file %s" % (name)
+                    raise inst
+        return f
+
+
+    def poll(self, port, expected, timeout=500):
+        """
+        Pool event from device and print event like text
+
+        @param file: Device
+        """
+
+        in_f = self._open([port])
+
+        p = select.poll()
+        p.register(in_f[0])
+
+        mask = p.poll(timeout)
+
+        str = ""
+        if (mask[0][1] & select.POLLIN):
+            str += "IN "
+        if (mask[0][1] & select.POLLPRI):
+            str += "PRI IN "
+        if (mask[0][1] & select.POLLOUT):
+            str += "OUT "
+        if (mask[0][1] & select.POLLERR):
+            str += "ERR "
+        if (mask[0][1] & select.POLLHUP):
+            str += "HUP "
+        if (mask[0][1] & select.POLLMSG):
+            str += "MSG "
+
+        if (mask[0][1] & expected) == expected:
+            print "PASS: Events: " + str
+        else:
+            print "FAIL: Events: " + str
+
+
+    def blocking(self, port, mode=False):
+        """
+        Set port function mode blocking/nonblocking
+
+        @param port: port to set mode
+        @param mode: False to set nonblock mode, True for block mode
+        """
+        path = self.ports[port]["path"]
+        fd = self.files[path]
+
+        try:
+            fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+            if not mode:
+                fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+            else:
+                fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
+
+        except Exception as inst:
+            print "FAIL: Setting (non)blocking mode: " + str(inst)
+            return
+
+        print "PASS: set blocking mode to %s mode" % \
+                ("blocking" if mode else "nonblocking")
+
+
+    def close(self, file):
+        """
+        Close open port
+
+        @param file: file to close
+        """
+        descriptor = None
+        path = self.ports[file]["path"]
+        if path != None:
+            if path in self.files.keys():
+                descriptor = self.files[path]
+                del self.files[path]
+        try:
+            os.close(descriptor)
+        except Exception as inst:
+            print "FAIL: Closing the file: " + str(inst)
+            return
+        print "PASS: Close"
+
+    def open(self, in_files):
+        """
+        Direct open devices.
+
+        @param in_files: Files array
+        @return: Array of descriptor
+        """
+
+        name = self.ports[in_files]["path"]
+        try:
+            self.files[name] = os.open(name, os.O_RDWR)
+            print "PASS: Open all filles correctly."
+        except Exception as inst:
+            print "%s\nFAIL: Failed open file %s" % (str(inst), name)
+
+
+    def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE):
+        """
+        Function starts switch thread (because there is problem with multiple
+        open of one files).
+
+        @param in_files: Array of input files
+        @param out_files: Array of output files
+        @param cachesize: Cachesize
+        """
+
+
+        self.ports = self._get_port_status()
+
+        in_f = self._open(in_files)
+        out_f = self._open(out_files)
+
+        s = self.switch(in_f, out_f, self.exit_thread, cachesize, mode)
+        s.start()
+        self.threads.append(s)
+        print "PASS: Start switch"
+
+    def exit_threads(self):
+        """
+        Function end all running data switch.
+        """
+        self.exit_thread.set()
+        for th in self.threads:
+            print "join"
+            th.join()
+        self.exit_thread.clear()
+
+        del self.threads[:]
+        for desc in self.files.itervalues():
+            os.close(desc)
+        self.files.clear()
+        print "PASS: All threads finished."
+
+    def die(self):
+        """
+        Quit consoleswitch.
+        """
+        self.exit_threads()
+        exit()
+
+
+    def send_loop_init(self, port, length):
+        """
+        Prepares the sender thread. Requires clean thread structure.
+        """
+        self.ports = self._get_port_status()
+        in_f = self._open([port])
+
+        self.threads.append(self.sender(in_f[0], self.exit_thread, length))
+        print "PASS: Sender prepare"
+
+
+    def send_loop(self):
+        """
+        Start sender data transfer. Requires senderprepare run firs.
+        """
+        self.threads[0].start()
+        print "PASS: Sender start"
+
+
+    def send(self, port, length=1, mode=True):
+        """
+        Send a data of some length
+
+        @param port: Port to write data
+        @param length: Length of data
+        @param mode: True = loop mode, False = one shoot mode
+        """
+        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 as inst:
+            print inst
+        if not writes:
+            writes = 0
+        if mode:
+            while (writes < length):
+                try:
+                    writes += os.write(in_f[0], data)
+                except Exception as inst:
+                    print inst
+        if writes >= length:
+            print "PASS: Send data length %d" % writes
+        else:
+            print "FAIL: Partial send: desired %d, transfered %d" \
+                    % (length, writes)
+
+
+    def recv(self, port, length=1, buffer=1024, mode=True):
+        """
+        Recv a data of some length
+
+        @param port: Port to write data
+        @param length: Length of data
+        @param mode: True = loop mode, False = one shoot mode
+        """
+        in_f = self._open([port])
+
+        recvs = ""
+        try:
+            recvs = os.read(in_f[0], buffer)
+        except Exception as inst:
+            print inst
+        if mode:
+            while (len(recvs) < length):
+                try:
+                    recvs += os.read(in_f[0], buffer)
+                except Exception as inst:
+                    print inst
+        if len(recvs) >= length:
+            print "PASS: Recv data length %d" % len(recvs)
+        else:
+            print "FAIL: Partial recv: desired %d, transfered %d" \
+                    % (length, len(recvs))
+
+def compile():
+    """
+    Compile virtio_guest.py to speed up.
+    """
+    import py_compile
+    py_compile.compile(sys.path[0] + "/virtio_guest.py")
+    print "PASS: compile"
+    exit(0)
+
+def main():
+    """
+    Main (infinite) loop of virtio_guest.
+    """
+    if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
+        compile()
+
+    virt = virtio_guest()
+    print "PASS: Start"
+
+    while True:
+        str = raw_input()
+        exec str
+
+
+if __name__ == "__main__":
+    main()
diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py
index 2e22f2f..058bb94 100644
--- a/client/tests/kvm/tests/virtio_console.py
+++ b/client/tests/kvm/tests/virtio_console.py
@@ -1,10 +1,10 @@
-import socket, random, array, sys, os, tempfile, shutil, threading, select, re
-import logging, time
-from threading import Thread
+import array, logging, os, random, re, select, shutil, socket, sys, tempfile
+import threading, time
 from collections import deque
-from autotest_lib.client.common_lib import error
-import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_preprocessing
+from threading import Thread
 
+import kvm_subprocess, kvm_test_utils, kvm_utils, kvm_preprocessing
+from autotest_lib.client.common_lib import error
 
 def run_virtio_console(test, params, env):
     """
@@ -28,139 +28,162 @@ def run_virtio_console(test, params, env):
         """
         Random data sender thread.
         """
-        def __init__(self, port, length, buffers, blocklen=32):
-            """
-            @param port: Destination port.
-            @param length: Amount of data we want to send.
-            @param buffers: Buffers for the control data (FIFOs).
-            @param blocklen: Block length.
-            """
-            Thread.__init__(self)
-            self.ExitState = True
-            self.port = port[0]
-            self.length = length
-            self.buffers = buffers
-            self.blocklen = blocklen
-
-
-        def run(self):
-            logging.debug("th_send %s: run", self.getName())
-            idx = 0
-            while idx < self.length:
-                ret = select.select([], [self.port], [], 1.0)
-                if ret:
-                    # Generate blocklen of random data add them to the FIFO
-                    # and send tham over virtio_console
-                    buf = ""
-                    for i in range(min(self.blocklen, self.length-idx)):
-                        ch = "%c" % random.randrange(255)
-                        buf += ch
-                        for buffer in self.buffers:
-                            buffer.append(ch)
-                    idx += len(buf)
-                    self.port.sendall(buf)
-            logging.debug("th_send %s: exit(%d)", self.getName(), idx)
-            if idx >= self.length:
-                self.ExitState = False
-
-
-    class th_send_loop(Thread):
-        """
-        Send data in the loop until the exit event is set
-        """
         def __init__(self, port, data, event):
             """
-            @param port: destination port
-            @param data: the data intend to be send in a loop
-            @param event: exit event
+            @param port: Destination port.
+            @param data: The data intend to be send in a loop.
+            @param event: Exit event.
             """
             Thread.__init__(self)
             self.port = port
+            # FIXME: socket.send(data>>127998) without read blocks thread
+            if len(data) > 102400:
+                data = data[0:102400]
+                logging.error("Data are too long, using only first %d bytes",
+                              len(data))
             self.data = data
             self.exitevent = event
             self.idx = 0
-
-
         def run(self):
-            logging.debug("th_send_loop %s: run", self.getName())
+            logging.debug("th_send %s: run", self.getName())
             while not self.exitevent.isSet():
                 self.idx += self.port.send(self.data)
-            logging.debug("th_send_loop %s: exit(%d)", self.getName(),
+            logging.debug("th_send %s: exit(%d)", self.getName(),
                           self.idx)
 
-
-    class th_recv(Thread):
+    class th_send_check(Thread):
         """
-        Random data reciever/checker thread
+        Random data sender thread
         """
-        def __init__(self, port, buffer, length, blocklen=32):
+        def __init__(self, port, event, queues, blocklen=1024):
             """
-            @param port: source port
-            @param buffer: control data buffer (FIFO)
-            @param length: amount of data we want to receive
-            @param blocklen: block length
+            @param port: Destination port
+            @param event: Exit event
+            @param queues: Queues for the control data (FIFOs)
+            @param blocklen: Block length
             """
             Thread.__init__(self)
-            self.ExitState = True
-            self.port = port[0]
-            self.buffer = buffer
-            self.length = length
+            self.port = port
+            self.queues = queues
+            # FIXME: socket.send(data>>127998) without read blocks thread
+            if blocklen > 102400:
+                blocklen = 102400
+                logging.error("Data are too long, using blocklen = %d",
+                              blocklen)
             self.blocklen = blocklen
-
+            self.exitevent = event
+            self.idx = 0
 
         def run(self):
-            logging.debug("th_recv %s: run", self.getName())
-            idx = 0
-            while idx < self.length:
-                ret = select.select([self.port], [], [], 1.0)
-                if ret:
-                    buf = self.port.recv(self.blocklen)
-                    if buf:
-                        # Compare the recvd data with the control data
-                        for ch in buf:
-                            if not ch == self.buffer.popleft():
-                                error.TestFail("th_recv: incorrect data")
-                    idx += len(buf)
-            logging.debug("th_recv %s: exit(%d)", self.getName(), idx)
-            if (idx >= self.length) and (len(self.buffer) == 0):
-                self.ExitState = False
+            logging.debug("th_send_check %s: run", self.getName())
+            too_much_data = False
+            while not self.exitevent.isSet():
+                # FIXME: workaround the problem with qemu-kvm stall when too
+                # much data send without receiving
+                for queue in self.queues:
+                    while not self.exitevent.isSet() and len(queue) > 1048576:
+                        too_much_data = True
+                        time.sleep(0.1)
+                ret = select.select([], [self.port], [], 1.0)
+                if ret[1]:
+                    # Generate blocklen of random data add them to the FIFO
+                    # and send them over virtio_console
+                    buf = ""
+                    for i in range(self.blocklen):
+                        ch = "%c" % random.randrange(255)
+                        buf += ch
+                        for queue in self.queues:
+                            queue.append(ch)
+                    target = self.idx + self.blocklen
+                    while not self.exitevent.isSet() and self.idx < target:
+                        idx = self.port.send(buf)
+                        buf = buf[idx:]
+                        self.idx += idx
+            logging.debug("th_send_check %s: exit(%d)", self.getName(),
+                          self.idx)
+            if too_much_data:
+                logging.error("th_send_check: workaround the 'too_much_data'"
+                              "bug")
 
 
-    class th_recv_null(Thread):
+    class th_recv(Thread):
         """
-        Receives data and throws it away.
+        Recieves data and throw them away
         """
-        def __init__(self, port, event, blocklen=32):
+        def __init__(self, port, event, blocklen=1024):
             """
             @param port: Data source port.
             @param event: Exit event.
             @param blocklen: Block length.
             """
             Thread.__init__(self)
-            self.port = port[0]
+            self.port = port
             self._port_timeout = self.port.gettimeout()
             self.port.settimeout(0.1)
             self.exitevent = event
             self.blocklen = blocklen
             self.idx = 0
-
-
         def run(self):
-            logging.debug("th_recv_null %s: run", self.getName())
+            logging.debug("th_recv %s: run", self.getName())
             while not self.exitevent.isSet():
-                # Workaround, it didn't work with select :-/
+                # 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("th_recv_null %s: exit(%d)", self.getName(),
+            logging.debug("th_recv %s: exit(%d)", self.getName(), self.idx)
+
+
+    class th_recv_check(Thread):
+        """
+        Random data reciever/checker thread
+        """
+        def __init__(self, port, buffer, event, blocklen=1024):
+            """
+            @param port: Source port.
+            @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 = buffer
+            self.exitevent = event
+            self.blocklen = blocklen
+            self.idx = 0
+        def run(self):
+            logging.debug("th_recv_check %s: run", self.getName())
+            while not self.exitevent.isSet():
+                ret = select.select([self.port], [], [], 1.0)
+                if ret and (not self.exitevent.isSet()):
+                    buf = self.port.recv(self.blocklen)
+                    if buf:
+                        # Compare the recvd data with the control data
+                        for ch in buf:
+                            ch_ = self.buffer.popleft()
+                            if not ch == ch_:
+                                self.exitevent.set()
+                                logging.error("Failed to recv %dth character",
+                                              self.idx)
+                                logging.error("%s != %s", repr(ch), repr(ch_))
+                                logging.error("Recv = %s", repr(buf))
+                                # sender might change the buffer :-(
+                                time.sleep(1)
+                                ch_ = ""
+                                for buf in self.buffer:
+                                    ch_ += buf
+                                logging.error("Queue = %s", repr(ch_))
+                                raise error.TestFail("th_recv_check: incorrect "
+                                                     "data")
+                        self.idx += len(buf)
+            logging.debug("th_recv_check %s: exit(%d)", self.getName(),
                           self.idx)
 
     seqTest = threading.Lock();
 
 
-    class average_cpu_load():
+    class cpu_load():
         """
         Get average cpu load between start and get_load
         """
@@ -198,10 +221,11 @@ def run_virtio_console(test, params, env):
                     return load
 
 
-        def start ( self ):
+        def start (self):
             """
             Start CPU usage measurement
             """
+            self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
             self.startTime = time.time();
             self._get_cpu_load()
 
@@ -209,10 +233,11 @@ def run_virtio_console(test, params, env):
         def get_load(self):
             """
             Get and reset CPU usage
+
             @return: return group cpu (user[%], system[%], sum[%], testTime[s])
             """
             self.endTime = time.time()
-            testTime =  self.endTime-self.startTime
+            testTime = self.endTime - self.startTime
             load = self._get_cpu_load()
 
             user = load[0] / testTime
@@ -222,7 +247,7 @@ def run_virtio_console(test, params, env):
             return (user, system, sum, testTime)
 
 
-    class average_process_cpu_load():
+    class pid_load():
         """
         Get average process cpu load between start and get_load
         """
@@ -234,7 +259,7 @@ def run_virtio_console(test, params, env):
             self.name = name
 
 
-        def _get_cpu_load(self,pid):
+        def _get_cpu_load(self, pid):
             # Let's see if we can calc system load.
             try:
                 f = open("/proc/%d/stat" % (pid), "r")
@@ -249,19 +274,19 @@ def run_virtio_console(test, params, env):
                 load_values = reg.findall(line)
                 del load_values[0:11]
                 # extract values from /proc/stat
-                load = [0,0]
+                load = [0, 0]
                 for i in range(2):
-                    load[i] = int(load_values[i])-self.old_load[i]
+                    load[i] = int(load_values[i]) - self.old_load[i]
 
                 for i in range(2):
                     self.old_load[i] = int(load_values[i])
                 return load
 
-
-        def start ( self ):
+        def start (self):
             """
             Start CPU usage measurement
             """
+            self.old_load = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
             self.startTime = time.time();
             self._get_cpu_load(self.pid)
 
@@ -274,7 +299,7 @@ def run_virtio_console(test, params, env):
                     (pid, user[%], system[%], sum[%], testTime[s])
             """
             self.endTime = time.time()
-            testTime =  self.endTime - self.startTime
+            testTime = self.endTime - self.startTime
             load = self._get_cpu_load(self.pid)
 
             user = load[0] / testTime
@@ -288,12 +313,12 @@ def run_virtio_console(test, params, env):
         """
         Print load in tabular mode.
 
-        @param process: list of process statistic tuples
-        @param system: tuple of system cpu usage
+        @param process: List of process statistic tuples.
+        @param system: Tuple of system cpu usage.
         """
 
         logging.info("%-10s %6s %5s %5s %5s %11s",
-                     "NAME", "PID","USER","SYS","SUM","TIME")
+                     "NAME", "PID", "USER", "SYS", "SUM", "TIME")
         for pr in process:
             logging.info("%-10s %6d %4.0f%% %4.0f%% %4.0f%% %10.3fs" % pr)
         logging.info("TOTAL:     ------ %4.0f%% %4.0f%% %4.0f%% %10.3fs" %
@@ -302,64 +327,96 @@ def run_virtio_console(test, params, env):
 
     def process_stats(stats, scale=1.0):
         """
-        Process and print the stats.
+        Process and print the statistic.
 
         @param stats: List of measured data.
         """
         if not stats:
             return None
-        for i in range((len(stats)-1),0,-1):
-            stats[i] = stats[i] - stats[i-1]
+        for i in range((len(stats) - 1), 0, -1):
+            stats[i] = stats[i] - stats[i - 1]
             stats[i] /= scale
         stats[0] /= scale
         stats = sorted(stats)
         return stats
 
 
-    def _start_console_switch(vm, timeout=2):
+    def init_guest(vm, timeout=2):
         """
-        Execute console_switch.py on guest, wait until it is initialized.
+        Execute virtio_guest.py on guest, wait until it is initialized.
 
         @param vm: Informations about the guest.
         @param timeout: Timeout that will be used to verify if the script
                 started properly.
         """
-        logging.debug("Starting console_switch.py on guest %s", vm[0].name)
-        vm[1].sendline("python /tmp/console_switch.py")
+        logging.debug("compile virtio_guest.py on guest %s", vm[0].name)
+        vm[1].sendline("python -OO /tmp/virtio_guest.py -c &&"
+                       "echo -n 'PASS: Compile virtio_guest finished' ||"
+                       "echo -n 'FAIL: Compile virtio_guest failed'")
         (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
                                                            timeout)
         if match == 1 or match is None:
             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_guest.py on guest %s", vm[0].name)
+        vm[1].sendline("python /tmp/virtio_guest.pyo &&"
+                       "echo -n 'PASS: virtio_guest finished' ||"
+                       "echo -n 'FAIL: virtio_guest failed'")
+        (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:"],
+                                                           timeout)
+        if match == 1 or match is None:
+            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)
 
 
-    def _execute_console_switch(command, vm, timeout=2):
+    def _on_guest(command, vm, timeout=2):
         """
         Execute given command inside the script's main loop, indicating the vm
         the command was executed on.
 
         @param command: Command that will be executed.
-        @param vm: Informations about the guest
+        @param vm: Informations about the guest.
         @param timeout: Timeout used to verify expected output.
 
         @return: Tuple (match index, data)
         """
-        logging.debug("Executing '%s' on console_switch.py loop, vm: %s,"
+        logging.debug("Executing '%s' on virtio_guest.py loop, vm: %s," +
                       "timeout: %s", command, vm[0].name, timeout)
         vm[1].sendline(command)
-        (match, data) = vm[1].read_until_last_line_matches(["PASS:","FAIL:"],
-                                                             timeout)
+        (match, data) = vm[1].read_until_last_line_matches(["PASS:", "FAIL:" \
+                                                         "[Failed to execute]"], \
+                                                          timeout)
+        return (match, data)
+
+
+    def on_guest(command, vm, timeout=2):
+        """
+        Wrapper around the _on_guest command which executes the command on
+        guest. Unlike _on_guest command when the command fails it raises the
+        test error.
+
+        @param command: Command that will be executed.
+        @param vm: Informations about the guest.
+        @param timeout: Timeout used to verify expected output.
+
+        @return: Tuple (match index, data)
+        """
+        match, data = _on_guest(command, vm, timeout)
         if match == 1 or match is None:
-            raise error.TestFail("Failed to execute '%s' on console_switch.py, "
+            raise error.TestFail("Failed to execute '%s' on virtio_guest.py, "
                                  "vm: %s, output:\n%s" %
                                  (command, vm[0].name, data))
+
         return (match, data)
 
 
     def socket_readall(sock, read_timeout, mesagesize):
         """
-       Read everything from the socket.
+        Read everything from the socket
 
         @param sock: socket
         @param read_timeout: read timeout
@@ -380,14 +437,44 @@ def run_virtio_console(test, params, env):
         return message
 
 
+    def _guest_exit_threads(vm, send_pts, recv_pts):
+        """
+        Safely executes on_guest("virt.exit_threads()") using workaround of
+        the stucked thread in loopback in mode=virt.LOOP_NONE .
+
+        @param vm: Informations about the guest.
+        @param send_pts: list of possible send sockets we need to work around
+        @param recv_pts: list of possible recv sockets we need to read-out
+        """
+        # in LOOP_NONE mode it might stuck in read/write
+        match, tmp = _on_guest("virt.exit_threads()", vm, 10)
+        if match == None:
+            logging.debug("Workaround the stucked thread on Guest")
+            # Thread is stucked in read/write
+            for send_pt in send_pts:
+                send_pt[0].sendall(".")
+        elif match != 0:
+            # Something else
+            raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n"
+                                 % (match, tmp))
+
+        # Read-out all remaining data
+        for recv_pt in recv_pts:
+            while select.select([recv_pt[0]], [], [], 0.1)[0]:
+                recv_pt[0].recv(1024)
+
+        # This will cause fail in case anything went wrong.
+        on_guest("print 'PASS: nothing'", vm, 10)
+
+
     def _vm_create(no_console=3, no_serialport=3):
         """
         Creates the VM and connects the specified number of consoles and serial
         ports.
 
-        @param no_console: number of desired virtconsoles
-        @param no_serialport: number of desired virtserialports
-        @return tuple with (guest information, consoles information)
+        @param no_console: Number of desired virtconsoles.
+        @param no_serialport: Number of desired virtserialports.
+        @return tupple with (guest information, consoles information)
             guest informations = [vm, session, tmp_dir]
             consoles informations = [consoles[], serialports[]]
         """
@@ -398,24 +485,24 @@ def run_virtio_console(test, params, env):
             params['extra_params'] = ''
         params['extra_params'] += " -device virtio-serial"
 
-        for i in range(0, no_console):
-            params['extra_params'] += (" -chardev socket,path=%s/%d,id=c%d,"
+        for i in  range(0, no_console):
+            params['extra_params'] += (" -chardev socket,path=%s/%d,id=%d,"
                                        "server,nowait" % (tmp_dir, i, i))
-            params['extra_params'] += (" -device virtconsole,chardev=c%d,"
-                                       "name=org.fedoraproject.console.%d,"
-                                       "id=c%d" % (i, i, i))
+            params['extra_params'] += (" -device virtconsole,chardev=%d,"
+                                      "name=console-%d,id=c%d" % (i, i, i))
 
         for i in  range(no_console, no_console + no_serialport):
-            params['extra_params'] += (" -chardev socket,path=%s/%d,id=p%d,"
+            params['extra_params'] += (" -chardev socket,path=%s/%d,id=%d,"
                                        "server,nowait" % (tmp_dir, i, i))
-            params['extra_params'] += (" -device virtserialport,chardev=p%d,"
-                                       "name=org.fedoraproject.data.%d,id=p%d" %
-                                       (i, i, i))
+            params['extra_params'] += (" -device virtserialport,chardev=%d,"
+                                       "name=serialport-%d,id=p%d" % (i, i, i))
+
 
         logging.debug("Booting first guest %s", params.get("main_vm"))
         kvm_preprocessing.preprocess_vm(test, params, env,
                                         params.get("main_vm"))
 
+
         vm = kvm_utils.env_get_vm(env, params.get("main_vm"))
 
         session = kvm_test_utils.wait_for_login(vm, 0,
@@ -426,12 +513,11 @@ def run_virtio_console(test, params, env):
         for i in range(0, no_console):
             sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
             sock.connect("%s/%d" % (tmp_dir, i))
-            consoles.append([sock, "org.fedoraproject.console.%d" % i, "yes"])
-
+            consoles.append([sock, "console-%d" % i, "yes"])
         for i in range(no_console, no_console + no_serialport):
             sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
             sock.connect("%s/%d" % (tmp_dir, i))
-            serialports.append([sock, "org.fedoraproject.data.%d" % i, "no"])
+            serialports.append([sock, "serialport-%d" % i, "no"])
 
         return [vm, session, tmp_dir], [consoles, serialports]
 
@@ -440,15 +526,15 @@ def run_virtio_console(test, params, env):
         """
         Virtio console smoke test.
 
-        Creates loopback on the vm machine between the ports[>=2] provided and
-        sends the data
+        Tests the basic functionalities (poll, read/write with and without
+        connected host, etc.
 
         @param vm: target virtual machine [vm, session, tmp_dir]
         @param consoles: a field of virtio ports with the minimum of 2 items
         @param params: test parameters '$console_type:$data;...'
         """
-        logging.info("Smoke test: Send data on the sender port, "
-                     "verify data integrity on the receiving port")
+        logging.info("Smoke test: Tests the basic capabilities of "
+                     "virtio_consoles.")
         # PREPARE
         for param in params.split(';'):
             if not param:
@@ -462,23 +548,118 @@ def run_virtio_console(test, params, env):
             param = (param[0] == 'serialport')
             send_pt = consoles[param][0]
             recv_pt = consoles[param][1]
-            _start_console_switch(vm, 10.0)
 
             # TEST
-            _execute_console_switch('start_switch([%s], [%s])' %
-                                   (str(send_pt[1:3]), str(recv_pt[1:3])),
-                                   vm, 2.0)
-
+            # Poll (OUT)
+            on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLOUT), vm,
+                     2)
+
+            # Poll (IN, OUT)
+            send_pt[0].sendall("test")
+            for test in [select.POLLIN, select.POLLOUT]:
+                on_guest("virt.poll('%s', %s)" % (send_pt[1], test), vm, 2)
+
+            # Poll (IN HUP)
+            # I store the socket informations and close the socket
+            sock = send_pt[0]
+            send_pt[0] = sock.getpeername()
+            sock.shutdown(2)
+            sock.close()
+            del sock
+            for test in [select.POLLIN, select.POLLHUP]:
+                on_guest("virt.poll('%s', %s)" % (send_pt[1], test), vm, 2)
+
+            # Poll (HUP)
+            on_guest("virt.recv('%s', 4, 1024, False)" % (send_pt[1]), vm, 2)
+            on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLHUP), vm,
+                     2)
+
+            # Reconnect the socket
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect(send_pt[0])
+            send_pt[0] = sock
+            # Redefine socket in consoles
+            consoles[param][0] = send_pt
+            on_guest("virt.poll('%s', %s)" % (send_pt[1], select.POLLOUT), vm,
+                     2)
+
+            # Read/write without host connected
+            # I store the socket informations and close the socket
+            sock = send_pt[0]
+            send_pt[0] = sock.getpeername()
+            sock.shutdown(2)
+            sock.close()
+            del sock
+            # Read should pass
+            on_guest("virt.recv('%s', 0, 1024, False)" % send_pt[1], vm, 2)
+            # Write should timed-out
+            match, tmp = _on_guest("virt.send('%s', 10, False)"
+                                    % send_pt[1], vm, 2)
+            if match != None:
+                raise error.TestFail("Read on guest while host disconnected "
+                                     "didn't timed out.\nOutput:\n%s"
+                                     % tmp)
+            sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+            sock.connect(send_pt[0])
+            send_pt[0] = sock
+            # Redefine socket in consoles
+            consoles[param][0] = send_pt
+            if (send_pt[0].recv(1024) < 10):
+                raise error.TestFail("Didn't received data from guest")
+            # Now the _on_guest("virt.send('%s'... command should be finished
+            on_guest("print 'PASS: nothing'", vm, 2)
+
+            # Non-blocking mode
+            on_guest("virt.blocking('%s', False)" % send_pt[1], vm, 2)
+            # Recv should return FAIL with 0 received data
+            match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)"
+                                    % send_pt[1], vm, 2)
+            if match == 0:
+                raise error.TestFail("Received data even when non were sent\n"
+                                     "Data:\n%s" % tmp)
+            elif match == None:
+                raise error.TestFail("Timed out, probably in blocking mode\n"
+                                     "Data:\n%s" % tmp)
+            elif match != 1:
+                raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n"
+                                     % (match, tmp))
+            send_pt[0].sendall("1234567890")
+            on_guest("virt.recv('%s', 10, 1024, False)" % send_pt[1], vm, 2)
+
+            # Blocking mode
+            on_guest("virt.blocking('%s', True)" % send_pt[1], vm, 2)
+            # Recv should timed out
+            match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)"
+                                    % send_pt[1], vm, 2)
+            if match == 0:
+                raise error.TestFail("Received data even when non were sent\n"
+                                     "Data:\n%s" % tmp)
+            elif match != None:
+                raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n"
+                                     % (match, tmp))
+            send_pt[0].sendall("1234567890")
+            # Now guest received the data end escaped from the recv()
+            on_guest("print 'PASS: nothing'", vm, 2)
+
+            # Basic loopback test
+            on_guest("virt.loopback(['%s'], ['%s'], 1024, virt.LOOP_NONE)"
+                     % (send_pt[1], recv_pt[1]), vm, 2)
             send_pt[0].sendall(data)
-            d = socket_readall(recv_pt[0], 1.0, len(data))
-            if data != d:
-                raise error.TestFail("test_smoke: received data on port %s "
-                                     "does not match data sent through "
-                                     "port %s" % (recv_pt, send_pt))
-
-            vm[1].sendline('die()')
+            tmp = ""
+            i = 0
+            while i <= 10:
+                i += 1
+                ret = select.select([recv_pt[0]], [], [], 1.0)
+                if ret:
+                    tmp += recv_pt[0].recv(1024)
+                if len(tmp) >= len(data):
+                    break
+            if tmp != data:
+                raise error.TestFail("Incorrect data: '%s' != '%s'",
+                                     data, tmp)
+            _guest_exit_threads(vm, [send_pt], [recv_pt])
 
-        logging.info("test_smoke: PASS")
+        return consoles
 
 
     def test_loopback(vm, consoles, params):
@@ -492,9 +673,9 @@ def run_virtio_console(test, params, env):
         @param vm: target virtual machine [vm, session, tmp_dir]
         @param consoles: a field of virtio ports with the minimum of 2 items
         @param params: test parameters, multiple recievers allowed.
-                '$source_console_type@buffer_length:
-                 $destination_console_type1@buffer_length:...:
-                 $loopback_buffer_length;...'
+            '$source_console_type@buffer_length:
+             $destination_console_type1@$buffer_length:...:
+             $loopback_buffer_length;...'
         """
         logging.info("Loopback test: Creates a loopback between sender port "
                      "and receiving port, send data through this connection, "
@@ -517,7 +698,7 @@ def run_virtio_console(test, params, env):
             if (len(param[0].split('@')) == 2):
                 buf_len.append(int(param[0].split('@')[1]))
             else:
-                buf_len.append(32)
+                buf_len.append(1024)
             recv_pts = []
             for parm in param[1:]:
                 if (parm.isdigit()):
@@ -532,201 +713,170 @@ def run_virtio_console(test, params, env):
                 if (len(parm[0].split('@')) == 2):
                     buf_len.append(int(parm[0].split('@')[1]))
                 else:
-                    buf_len.append(32)
+                    buf_len.append(1024)
             # There must be sum(idx_*) consoles + last item as loopback buf_len
             if len(buf_len) == (idx_console + idx_serialport):
-                buf_len.append(32)
+                buf_len.append(1024)
 
             if len(recv_pts) == 0:
                 raise error.TestFail("test_loopback: incorrect recv consoles"
                                      "definition")
+
             threads = []
-            buffers = []
+            queues = []
             for i in range(0, len(recv_pts)):
-                buffers.append(deque())
+                queues.append(deque())
 
-            _start_console_switch(vm, 10.0)
-            tmp = str(recv_pts[0][1:3])
+            tmp = "'%s'" % recv_pts[0][1]
             for recv_pt in recv_pts[1:]:
-                tmp += ", " + str(recv_pt[1:3])
-            _execute_console_switch('start_switch([%s], [%s], %d)' %
-                                    (str(send_pt[1:3]), tmp, buf_len[-1]),
-                                    vm, 2.0)
+                tmp += ", '%s'" % (recv_pt[1])
+            on_guest("virt.loopback(['%s'], [%s], %d, virt.LOOP_POLL)"
+                     % (send_pt[1], tmp, buf_len[-1]), vm, 2)
+
+            exit_event = threading.Event()
 
             # TEST
-            thread = th_send(send_pt, 1048576, buffers, buf_len[0])
+            thread = th_send_check(send_pt[0], exit_event, queues, buf_len[0])
             thread.start()
             threads.append(thread)
 
             for i in range(len(recv_pts)):
-                thread = th_recv(recv_pts[i], buffers[i], 1048576,
-                                 buf_len[i+1])
+                thread = th_recv_check(recv_pts[i][0], queues[i], exit_event,
+                                       buf_len[i + 1])
                 thread.start()
                 threads.append(thread)
 
-            dead_threads = False
-            # Send + recv threads, DL 60s
-            for i in range(60):
-                for t in threads:
-                    if not t.is_alive():
-                        if t.ExitState:
-                            error.TestFail("test_loopback: send/recv thread "
-                                           "failed")
-                        dead_threads = True
-                if dead_threads:
-                    break
-                tmp = ""
-                for buf in buffers:
-                    tmp += str(len(buf)) + ", "
-                logging.debug("test_loopback: buffer length (%s)", tmp[:-2])
-                time.sleep(1)
-
-            if not dead_threads:
-                raise error.TestFail("test_loopback: send/recv timeout")
-            # at this point at least one thread died. It should be the send one.
-
-            # Wait for recv threads to finish their's work
-            for i in range(60):
-                dead_threads = True
-                for t in threads:
-                    if t.is_alive():
-                        dead_threads = False
-                # There are no living threads
-                if dead_threads:
-                    break
-                tmp = ""
-                for buf in buffers:
-                    tmp += str(len(buf)) + ", "
-                logging.debug("test_loopback: buffer length (%s)", tmp[:-2])
-                time.sleep(1)
+            time.sleep(60)
+            exit_event.set()
+            threads[0].join()
+            tmp = "%d data sent; " % threads[0].idx
+            for thread in threads[1:]:
+                thread.join()
+                tmp += "%d, " % thread.idx
+            logging.info("test_loopback: %s data received and verified",
+                         tmp[:-2])
 
-            for t in threads:
-                if t.ExitState:
-                    raise error.TestFail("test_loopback: recv thread failed")
+            # Read-out all remaining data
+            for recv_pt in recv_pts:
+                while select.select([recv_pt[0]], [], [], 0.1)[0]:
+                    recv_pt[0].recv(1024)
 
-            # At least one thread is still alive
-            if not dead_threads:
-                raise error.TestFail("test_loopback: recv timeout")
+            _guest_exit_threads(vm, [send_pt], recv_pts)
 
-            vm[1].sendline("die()")
-
-        logging.info("test_loopback: PASS")
+            del exit_event
+            del threads[:]
 
 
     def test_perf(vm, consoles, params):
         """
-        Virtio console performance test.
-
         Tests performance of the virtio_console tunel. First it sends the data
-        from host to guest and then back. It provides informations about
-        computer utilization and statistic information about the throughput.
+        from host to guest and than back. It provides informations about
+        computer utilisation and statistic informations about the troughput.
 
         @param vm: target virtual machine [vm, session, tmp_dir]
         @param consoles: a field of virtio ports with the minimum of 2 items
         @param params: test parameters:
-                '$console_type@buffer_length:$test_duration;...'
+                '$console_type@$buffer_length:$test_duration;...'
         """
         logging.info("Performance test: Measure performance for the "
-                     "virtio console tunnel")
-        # PREPARE
+                             "virtio console tunnel")
         for param in params.split(';'):
             if not param:
                 continue
-            logging.info("test_perf: params: %s", param)
+            print "test_perf: params: %s" % param
             param = param.split(':')
-            if len(param) > 1 and param[1].isdigit():
-                duration = float(param[1])
-            else:
-                duration = 30.0
+            duration = 60.0
+            if len(param) > 1:
+                try:
+                    duration = float(param[1])
+                except:
+                    pass
             param = param[0].split('@')
             if len(param) > 1 and param[1].isdigit():
                 buf_len = int(param[1])
             else:
-                buf_len = 32
-            if param[0] == "serialport":
-                port = consoles[1][0]
-            else:
-                port = consoles[0][0]
-            data = array.array("L")
-            for i in range(max((buf_len / data.itemsize), 1)):
-                data.append(random.randrange(sys.maxint))
-
-            ev = threading.Event()
-            thread = th_send_loop(port[0], data.tostring(), ev)
+                buf_len = 1024
+            param = (param[0] == 'serialport')
+            port = consoles[param][0]
 
-            _start_console_switch(vm, 10.0)
+            data = ""
+            for i in range(buf_len):
+                data += "%c" % random.randrange(255)
 
-            _execute_console_switch('start_switch([%s], [], %d)' %
-                                    (str(port[1:3]), buf_len), vm, 2.0)
+            exit_event = threading.Event()
+            slice = float(duration)/100
 
-            # TEST
-            # Host -> Guest
-            load = []
+            # HOST->GUEST
+            on_guest('virt.loopback(["%s"], [], %d, virt.LOOP_NONE)' % (
+                        port[1], buf_len), vm, 2)
+            thread = th_send(port[0], data, exit_event)
             stats = array.array('f', [])
-            slice = float(duration)/100
-            load.append(average_cpu_load())
-            load.append(average_process_cpu_load(os.getpid(), 'autotest'))
-            load.append(average_process_cpu_load(vm[0].get_pid(), 'VM'))
-            for ld in load:
-                ld.start()
+            loads = []
+            loads.append(cpu_load())
+            loads.append(pid_load(os.getpid(), 'autotest'))
+            loads.append(pid_load(vm[0].get_pid(), 'VM'))
+
+            for load in loads:
+                load.start()
             _time = time.time()
             thread.start()
             for i in range(100):
                 stats.append(thread.idx)
                 time.sleep(slice)
             _time = time.time() - _time - duration
-            print_load([load[1].get_load(), load[2].get_load()],
-                       load[0].get_load())
-            ev.set()
+            print_load([loads[1].get_load(), loads[2].get_load()],
+                       loads[0].get_load())
+            exit_event.set()
             thread.join()
+
+            _guest_exit_threads(vm, [port], [])
+
             if (_time > slice):
-                logging.error("test_perf: test ran %fs longer "
-                              "(more than 1 slice)", _time)
+                logging.error(
+                "Test ran %fs longer which is more than one slice", _time)
             else:
-                logging.debug("test_perf: test ran %fs longer "
-                              "(less than 1 slice)", _time)
-            stats = process_stats(stats[1:], slice*1024*1024)
-            logging.info("Host -> Guest [MB/s] min/med/max = %.3f/%.3f/%.3f",
+                logging.debug("Test ran %fs longer", _time)
+            stats = process_stats(stats[1:], slice*1048576)
+            logging.debug("Stats = %s", stats)
+            logging.info("Host->Guest [mb/s] min/med/max = %.3f/%.3f/%.3f",
                          stats[0], stats[len(stats)/2], stats[-1])
-            time.sleep(5)
-            vm[1].sendline("die()")
 
-            # Guest -> Host
-            _start_console_switch(vm, 10.0)
-            _execute_console_switch('sender_prepare(%s, %d)' %
-                                    (str(port[1:3]), buf_len), vm, 10)
+            del thread
+
+            # GUEST->HOST
+            exit_event.clear()
             stats = array.array('f', [])
-            ev.clear()
-            thread = th_recv_null(port, ev, buf_len)
+            on_guest("virt.send_loop_init('%s', %d)" % (port[1], buf_len),
+                     vm, 30)
+            thread = th_recv(port[0], exit_event, buf_len)
             thread.start()
-            # reset load measures
-            for ld in load:
-                ld.get_load()
-            _execute_console_switch('sender_start()', vm, 2)
+            for load in loads:
+                load.start()
+            on_guest("virt.send_loop()", vm, 2)
             _time = time.time()
             for i in range(100):
                 stats.append(thread.idx)
                 time.sleep(slice)
             _time = time.time() - _time - duration
-            print_load([load[1].get_load(), load[2].get_load()],
-                       load[0].get_load())
-            vm[1].sendline("die()")
-            time.sleep(5)
-            ev.set()
+            print_load([loads[1].get_load(), loads[2].get_load()],
+                       loads[0].get_load())
+            on_guest("virt.exit_threads()", vm, 2)
+            exit_event.set()
             thread.join()
             if (_time > slice): # Deviation is higher than 1 slice
-                logging.error("test_perf: test ran %fs longer "
-                              "(more than 1 slice)", _time)
+                logging.error(
+                "Test ran %fs longer which is more than one slice", _time)
             else:
-                logging.debug("test_perf: test ran %fs longer "
-                              "(less than 1 slice)", _time)
-            stats = process_stats(stats[1:], slice*1024*1024)
-            logging.info("Guest -> Host [MB/s] min/med/max = %.3f/%.3f/%.3f",
+                logging.debug("Test ran %fs longer" % _time)
+            stats = process_stats(stats[1:], slice*1048576)
+            logging.debug("Stats = %s", stats)
+            logging.info("Guest->Host [mb/s] min/med/max = %.3f/%.3f/%.3f",
                          stats[0], stats[len(stats)/2], stats[-1])
-            for ld in load:
-                del(ld)
 
-        logging.info("test_perf: PASS")
+            del thread
+
+            del exit_event
+            del loads[:]
 
 
     # INITIALIZE
@@ -736,35 +886,44 @@ def run_virtio_console(test, params, env):
 
     no_serialports = 0
     no_consoles = 0
-
     # consoles required for Smoke test
     if (test_smoke_params.count('serialport')):
         no_serialports = max(2, no_serialports)
     if (test_smoke_params.count('console')):
         no_consoles = max(2, no_consoles)
-
     # consoles required for Loopback test
     for param in test_loopback_params.split(';'):
         no_serialports = max(no_serialports, param.count('serialport'))
         no_consoles = max(no_consoles, param.count('console'))
-
     # consoles required for Performance test
     if (test_perf_params.count('serialport')):
         no_serialports = max(1, no_serialports)
     if (test_perf_params.count('console')):
         no_consoles = max(1, no_consoles)
 
+    if (no_serialports + no_consoles) == 0:
+        raise error.TestFail("No tests defined, probably incorrect "
+                             "configuration in tests_base.cfg")
+
     vm, consoles = _vm_create(no_consoles, no_serialports)
 
-    # Copy console_switch.py into guests
+    # Copy allocator.py into guests
     pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm')
-    vksmd_src = os.path.join(pwd, "scripts/console_switch.py")
+    vksmd_src = os.path.join(pwd, "scripts/virtio_guest.py")
     dst_dir = "/tmp"
     if not vm[0].copy_files_to(vksmd_src, dst_dir):
         raise error.TestFail("copy_files_to failed %s" % vm[0].name)
 
     # ACTUAL TESTING
-    test_smoke(vm, consoles, test_smoke_params)
+    # Defines all available consoles; tests udev and sysfs
+    conss = []
+    for mode in consoles:
+        for cons in mode:
+            conss.append(cons[1:3])
+    init_guest(vm, 10)
+    on_guest("virt.init(%s)" % (conss), vm, 10)
+
+    consoles = test_smoke(vm, consoles, test_smoke_params)
     test_loopback(vm, consoles, test_loopback_params)
     test_perf(vm, consoles, test_perf_params)
 
@@ -772,3 +931,4 @@ def run_virtio_console(test, params, env):
     vm[1].close()
     vm[0].destroy(gracefully=False)
     shutil.rmtree(vm[2])
+
diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kvm/tests_base.cfg.sample
index bef0f1c..ff0a760 100644
--- a/client/tests/kvm/tests_base.cfg.sample
+++ b/client/tests/kvm/tests_base.cfg.sample
@@ -502,11 +502,15 @@ variants:
         vms = ''
         type = virtio_console
         # smoke params - $console_type:data_string
-        virtio_console_smoke = "serialport;console:Custom data"
+        # FIXME: test_smoke doesn't work with console yet (virtio_console bug)
+        # "serialport;console:Custom data"
+        virtio_console_smoke = "serialport"
         # loopback params - '$source_console_type@buffer_length:$destination_console_type1@buffer_length:...:$loopback_buffer_length;...'
         virtio_console_loopback = "serialport:serialport;serialport@1024:serialport@32:console@1024:console@8:16"
         # perf params - $console_type@buffer_length:$test_duration
-        virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
+        # FIXME: test_perf doesn't work with console yet (virtio_console bug)
+        # virtio_console_perf = "serialport;serialport@1000000:120;console@1024:60"
+        virtio_console_perf = "serialport;serialport@1000000:120"
 
     # 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.2.2

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [KVM-autotest] virtio_console test v3.0
  2010-09-15 15:41 ` Lukas Doktor
@ 2010-09-17  8:52   ` Amit Shah
  0 siblings, 0 replies; 3+ messages in thread
From: Amit Shah @ 2010-09-17  8:52 UTC (permalink / raw)
  To: Lukas Doktor; +Cc: jzupka, autotest, kvm, lmr

On (Wed) Sep 15 2010 [17:41:28], Lukas Doktor wrote:
> New version of virtio_console test is more similar to upstream C virtio_console test so it will be easier to maintain. Also we moved the scripts/console_switch.py to more sensible scripts/virtio_guest.py
> 
> There are still some virtio_console bugs which restricts some usage (mostly with console). We have created workarounds which enables us to run the tests. They are marked as FIXME comments.

I'm guessing you're seeing those bugs because you try open/close/etc.
calls on the hvc devices.  That's not how they're supposed to be used.
As I mentioned previously, you should spawn a terminal on hvc and use it
for console IO.

I'll take a look at the rest in a bit.

		Amit

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-09-17  8:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-15 15:41 [KVM-autotest] virtio_console test v3.0 Lukas Doktor
2010-09-15 15:41 ` Lukas Doktor
2010-09-17  8:52   ` Amit Shah

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.