[lnst] TCPListen and TCPConnect test set added

Jiří Pírko jirka at fedoraproject.org
Tue Aug 14 14:34:58 UTC 2012


commit 5d0cb1e19d15e95a3ed403128c8ad84389840f93
Author: Jan Tluka <jtluka at redhat.com>
Date:   Mon Aug 13 15:37:27 2012 +0200

    TCPListen and TCPConnect test set added
    
    Set of these tests provides possibility to test multiple TCP connections
    within two LNST commands. Data sent are random and every connection
    behaves differently in sense that number of packets is random as well.
    
    Following are two examples of commands in command sequence.
    
        <define>
            <alias name="my_range" value="10000-10100" />
        </define>
        <command machine_id="1" type="test" value="TCPListen" bg_id="1">
            <options>
                <option name="addr" value="{ip(1,1)}"/>
                <option name="port_range" value="{$my_range}"/>
            </options>
        </command>
        <command type="exec" value="sleep 5" />
        <command machine_id="2" type="test" value="TCPConnect" bg_id="2">
            <options>
                <option name="addr" value="{ip(1,1)}"/>
                <option name="port_range" value="{$my_range}"/>
                <option name="sleep" value="0.5" />
            </options>
        </command>
        <command machine_id="2" type="wait" value="2" />
        <command machine_id="1" type="wait" value="1" />
    
    Repeated generation of connections can be achieved using following
    command (see 'cont' option):
    
        <define>
            <alias name="my_range" value="10000-10100" />
        </define>
        <command machine_id="1" type="test" value="TCPListen" bg_id="1">
            <options>
                <option name="addr" value="{ip(1,1)}"/>
                <option name="port_range" value="{$my_range}"/>
                <option name="cont" value="yes" />
            </options>
        </command>
        <command type="exec" value="sleep 5" />
        <command machine_id="2" type="test" value="TCPConnect" bg_id="2">
            <options>
                <option name="addr" value="{ip(1,1)}"/>
                <option name="port_range" value="{$my_range}"/>
                <option name="sleep" value="0.5" />
                <option name="cont" value="yes" />
            </options>
        </command>
        <command type="exec" value="sleep 60" />
        <command machine_id="2" type="intr" value="2" />
        <command machine_id="1" type="kill" value="1" />
    
    Signed-off-by: Jan Tluka <jtluka at redhat.com>
    Signed-off-by: Jiri Pirko <jpirko at redhat.com>

 Tests/TestTCPConnect.py |  167 +++++++++++++++++++++++++++++++++++++++++++++++
 Tests/TestTCPListen.py  |  127 +++++++++++++++++++++++++++++++++++
 2 files changed, 294 insertions(+), 0 deletions(-)
---
diff --git a/Tests/TestTCPConnect.py b/Tests/TestTCPConnect.py
new file mode 100644
index 0000000..0a6c655
--- /dev/null
+++ b/Tests/TestTCPConnect.py
@@ -0,0 +1,167 @@
+"""
+This module defines TCPConnect module
+"""
+
+__author__ = """
+jtluka at redhat.com (Jan Tluka)
+"""
+
+import sys
+import socket
+import errno
+from multiprocessing import Process, Lock
+from signal import signal, SIGINT
+from time import sleep
+from random import randrange, sample
+import logging
+import re
+from Common.TestsCommon import TestGeneric
+
+"""
+Test description:
+    Test spawns client(s) connecting to TCP port(s) defined by port or
+    port_range option. When connected, the client sends random bursts of
+    random data to server. If cont option is set the connections are initiated
+    again and data is sent to server until interrupted by the controller.
+
+Parameters:
+    addr ... mandatory, address to connect to
+    port ... mandatory, port to send data
+    sleep ... optional, sleep time between bursts, if undefined, the bursts
+              are immediate
+    cont ... optional, sets continuous mode of connecting, if set connections
+             are infinitely re-spawned when closed
+"""
+
+class ConnectionWorker():
+    def __init__(self, host, port, sleep_time = None, continuous = None):
+        self._tlock = Lock()
+        self._terminate = 0
+        self._host = host
+        self._port = port
+        self._sleep_time = sleep_time
+        self._cont = continuous
+        self._ascii = [chr(i) for i in range(0,255)]
+
+    def terminate(self):
+        self._tlock.acquire()
+        self._terminate=1
+        self._tlock.release()
+
+    def run(self):
+        loop = True
+
+        while loop:
+            loop = (self._cont is not None)
+            logging.debug("Starting connection to (%s) port %s " % (self._host,
+                          self._port))
+
+            try:
+                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                s.connect((self._host, self._port))
+            except socket.error, msg:
+                s.close()
+                s = None
+                logging.error(msg)
+                return
+
+            for txs in range(10, randrange(20,100)):
+                self._tlock.acquire()
+                if self._terminate:
+                    self._tlock.release()
+                    logging.debug("Terminating connection on port %s" %
+                                  self._port)
+                    loop = False
+                    break
+                else:
+                    self._tlock.release()
+
+                rnd_str = "".join(sample(self._ascii, len(self._ascii)))
+                data = s.sendall(rnd_str)
+                if (self._sleep_time):
+                    sleep(self._sleep_time)
+
+            s.close()
+
+
+class TestTCPConnect(TestGeneric):
+    def _parse_options(self):
+        addr = self.get_mopt("addr")
+        if addr:
+            self._host = addr
+
+        # either port or port_range should be set
+        port = self.get_opt("port")
+        if port:
+            self._port = port
+        else:
+            port_range = self.get_opt("port_range")
+            if port_range:
+                self._port_range = port_range
+            else:
+                e = TestOptionMissing()
+                raise e
+
+        sleep_time = float(self.get_opt("sleep"))
+        if sleep_time:
+            self._sleep_time = sleep_time
+
+        cont = self.get_opt("cont")
+        if cont:
+            self._cont = cont
+
+    def parse_port_range(self):
+        if self._port_range == None:
+            return []
+
+        for c in [',','-']:
+            s = self._port_range.split(c)
+            if len(s) == 2:
+                break
+
+        if len(s) != 2:
+            logging.error("Port range malformed! ", self._port_range)
+
+        low = int(s[0])
+        high = int(s[1]) + 1
+
+        return range(low, high)
+
+    def _close_connections(self, signum, frame):
+        logging.debug("Termination signal delivered ...")
+        for cw in self._cw_instances:
+            cw.terminate()
+
+    def _set_interrupt_handler(self):
+        signal(SIGINT, self._close_connections)
+
+    def run(self):
+        self._terminate = 0
+        self._host = None
+        self._port = None
+        self._cont = None
+        self._cw_instances = []
+
+        self._set_interrupt_handler()
+
+        self._parse_options()
+
+        ports = []
+        if self._port:
+            ports.extend(self._port)
+        else:
+            r = self.parse_port_range()
+            ports.extend(r)
+
+        workers = []
+        for p in ports:
+            cw = ConnectionWorker(self._host, p, self._sleep_time, self._cont)
+            self._cw_instances.append(cw)
+
+            w = Process(target=cw.run)
+            w.start()
+            workers.append(w)
+
+        logging.debug("Waiting for workers ...")
+        for w in workers:
+            w.join()
diff --git a/Tests/TestTCPListen.py b/Tests/TestTCPListen.py
new file mode 100644
index 0000000..c214a3d
--- /dev/null
+++ b/Tests/TestTCPListen.py
@@ -0,0 +1,127 @@
+"""
+This module defines TCPListen module
+"""
+
+__author__ = """
+jtluka at redhat.com (Jan Tluka)
+"""
+
+import sys
+import socket
+import errno
+import logging
+import re
+from multiprocessing import Process
+from Common.TestsCommon import TestGeneric
+
+"""
+Test description:
+    Test spawns server(s) listening for TCP connection(s) on port(s) defined by
+    port or port_range options. When client connects to the port, server reads
+    the data sent and close the connection when no more data is available.
+    If cont option is set the connection is reopened and server reads data
+    again.
+
+Parameters:
+    addr ... optional, address to bind to, if undefined listen on all ifaces
+    port ... mandatory, port to listen on
+    cont ... optional, if set the listening port is reopened when the
+             connection is closed
+"""
+
+class TestTCPListen(TestGeneric):
+    def __init__(self, command):
+        self._addr = None
+        self._port = None
+        self._cont = None
+        TestGeneric.__init__(self, command)
+
+    def _parse_options(self):
+        addr = self.get_opt("addr")
+        if addr:
+            self._addr = addr
+
+        # either port or port_range should be set
+        port = self.get_opt("port")
+        if port:
+            self._port = port
+        else:
+            port_range = self.get_opt("port_range")
+            if port_range:
+                self._port_range = port_range
+            else:
+                e = TestOptionMissing()
+                raise e
+
+        cont = self.get_opt("cont")
+        if cont:
+            self._cont = cont
+
+    def _worker(self, host, port):
+        logging.debug("Starting listener (%s) on port %s " % (host, port))
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+        try:
+            s.bind((host, port))
+            s.listen(1)
+        except socket.error, msg:
+            s.close()
+            s = None
+            logging.error(msg)
+            return
+
+        loop = 1
+
+        while loop or self._cont:
+            conn, addr = s.accept()
+            logging.debug('Connected from ' + addr[0] + ' port:' +
+                          str(addr[1]))
+
+            while 1:
+                data = conn.recv(1024)
+                if not data:
+                    logging.debug('Client disconnected: ' + addr[0] +
+                                  ' port:' + str(addr[1]))
+                    break
+
+            conn.close()
+            loop = 0
+
+    def _parse_port_range(self):
+        if self._port_range == None:
+            return []
+
+        for c in [',','-']:
+            s = self._port_range.split(c)
+            if len(s) == 2:
+                break
+
+        if len(s) != 2:
+            logging.error("Port range malformed! ", self._port_range)
+
+        low = int(s[0])
+        high = int(s[1]) + 1
+
+        return range(low, high)
+
+    def run(self):
+        self._parse_options()
+
+        ports = []
+        if self._port:
+            ports.extend(self._port)
+        else:
+            r = self._parse_port_range()
+            ports.extend(r)
+
+        workers = []
+
+        for p in ports:
+            w = Process(target=self._worker, args=(self._addr, p))
+            w.start()
+            workers.append(w)
+
+
+        logging.debug("Waiting for workers ...")
+        for w in workers:
+            w.join()


More information about the LNST-developers mailing list