Nir Soffer has uploaded a new change for review.

Change subject: tests: Add protocoldetector tests
......................................................................

tests: Add protocoldetector tests

Add tests for protocoldetector.MultiProtocolAcceptor using both ssl and
non-ssl transport.

Change-Id: I3ca9d0013126f3c2cbca05cabb70b0622fabb683
Signed-off-by: Nir Soffer <[email protected]>
---
M tests/Makefile.am
A tests/protocoldetectorTests.py
2 files changed, 225 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/80/33980/1

diff --git a/tests/Makefile.am b/tests/Makefile.am
index 449d7b1..dc10dfe 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -61,6 +61,7 @@
        permutationTests.py \
        persistentDictTests.py \
        profileTests.py \
+       protocoldetectorTests.py \
        qemuimgTests.py \
        remoteFileHandlerTests.py \
        resourceManagerTests.py \
diff --git a/tests/protocoldetectorTests.py b/tests/protocoldetectorTests.py
new file mode 100644
index 0000000..82299e1
--- /dev/null
+++ b/tests/protocoldetectorTests.py
@@ -0,0 +1,224 @@
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+#
+# Refer to the README and COPYING files for full details of the license
+#
+
+import socket
+import ssl
+import threading
+import time
+from contextlib import contextmanager, closing
+
+import protocoldetector
+
+from vdsm import sslutils
+from sslhelper import KEY_FILE, CRT_FILE
+from testlib import VdsmTestCase, expandPermutations, permutations
+
+
+class Detector(object):
+    """
+    A detector returning response to the client, so we can tell if detection
+    was successful and transport is useable after detection.
+    """
+
+    # Must be defined by sub classes
+    NAME = None
+    REQUIRED_SIZE = None
+
+    def detect(self, data):
+        return data.startswith(self.NAME)
+
+    def handleSocket(self, client_socket, socket_address):
+        def run():
+            try:
+                assert client_socket.gettimeout() is None
+                rfile = client_socket.makefile('rb', -1)
+                with closing(rfile):
+                    request = rfile.readline()
+                    response = self.response(request)
+                    client_socket.sendall(response)
+            finally:
+                client_socket.shutdown(socket.SHUT_RDWR)
+                client_socket.close()
+
+        t = threading.Thread(target=run)
+        t.daemon = True
+        t.start()
+
+
+class Echo(Detector):
+    """ A detector echoing sent line """
+
+    NAME = "echo"
+    REQUIRED_SIZE = len(NAME)
+
+    def response(self, data):
+        return data
+
+
+class Uppercase(Detector):
+    """ A detector echoing sent line in UPPERCASE """
+
+    NAME = "uppercase"
+    REQUIRED_SIZE = len(NAME)
+
+    def response(self, data):
+        return data.upper()
+
+
+@expandPermutations
+class AcceptorTests(VdsmTestCase):
+
+    TIMEOUT = 2.0
+    CONCURRENCY = 5
+    PERMUTATIONS = ((False,), (True,))
+    SSLCTX = sslutils.SSLContext(CRT_FILE, KEY_FILE, ca_cert=CRT_FILE)
+    BUFSIZE = 512
+
+    def setUp(self):
+        self.acceptor = None
+        self.acceptor_address = None
+
+    def tearDown(self):
+        if self.acceptor:
+            self.acceptor.stop()
+
+    # Testing
+
+    @permutations(PERMUTATIONS)
+    def test_reject_unknown_protocol(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        self.check_reject(use_ssl)
+
+    @permutations(PERMUTATIONS)
+    def test_reject_concurrency(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        self.check_concurrently(self.check_reject, use_ssl)
+
+    @permutations(PERMUTATIONS)
+    def test_detect_echo(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        data = "echo testing is fun\n"
+        self.check_detect(use_ssl, data, data)
+
+    @permutations(PERMUTATIONS)
+    def test_detect_uppercase(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        data = "uppercase testing is fun\n"
+        self.check_detect(use_ssl, data, data.upper())
+
+    @permutations(PERMUTATIONS)
+    def test_detect_concurrency(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        data = "echo testing is fun\n"
+        self.check_concurrently(self.check_detect, use_ssl, data, data)
+
+    @permutations(PERMUTATIONS)
+    def test_detect_slow_client(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        self.check_slow_client(use_ssl)
+
+    @permutations(PERMUTATIONS)
+    def test_setect_slow_client_concurrency(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        self.check_concurrently(self.check_slow_client, use_ssl)
+
+    @permutations(PERMUTATIONS)
+    def test_reject_very_slow_client(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        self.check_very_slow_client(use_ssl)
+
+    @permutations(PERMUTATIONS)
+    def test_reject_very_slow_client_concurrency(self, use_ssl):
+        self.start_acceptor(use_ssl)
+        self.check_concurrently(self.check_very_slow_client, use_ssl)
+
+    # Checking
+
+    def check_detect(self, use_ssl, request, response):
+        with self.connect(use_ssl) as client:
+            client.sendall(request)
+            self.assertEqual(client.recv(self.BUFSIZE), response)
+
+    def check_reject(self, use_ssl):
+        with self.connect(use_ssl) as client:
+            client.sendall("no such protocol\n")
+            if use_ssl:
+                self.assertEqual(client.recv(self.BUFSIZE), '')
+            else:
+                self.assertRaises(socket.error, client.recv, self.BUFSIZE)
+
+    def check_slow_client(self, use_ssl):
+        with self.connect(use_ssl) as client:
+            time.sleep(self.acceptor.CLEANUP_INTERVAL - 0.2)
+            data = "echo let me in\n"
+            client.sendall(data)
+            self.assertEqual(client.recv(self.BUFSIZE), data)
+
+    def check_very_slow_client(self, use_ssl):
+        with self.connect(use_ssl) as client:
+            time.sleep(self.acceptor.CLEANUP_INTERVAL * 2)
+            client.sendall("echo too slow probably\n")
+            self.assertEqual(client.recv(self.BUFSIZE), '')
+
+    # Helpers
+
+    def start_acceptor(self, use_ssl):
+        self.acceptor = protocoldetector.MultiProtocolAcceptor(
+            '127.0.0.1', 0, sslctx=self.SSLCTX if use_ssl else None)
+        self.acceptor.CLEANUP_INTERVAL = 1
+        self.acceptor.add_detector(Echo())
+        self.acceptor.add_detector(Uppercase())
+        self.acceptor_address = self.acceptor._socket.getsockname()
+        t = threading.Thread(target=self.acceptor.serve_forever)
+        t.deamon = True
+        t.start()
+
+    @contextmanager
+    def connect(self, use_ssl):
+        s = socket.socket()
+        try:
+            s.settimeout(self.TIMEOUT)
+            if use_ssl:
+                s = ssl.wrap_socket(s, KEY_FILE, CRT_FILE, ca_certs=CRT_FILE,
+                                    server_side=False)
+            s.connect(self.acceptor_address)
+            yield s
+        finally:
+            s.close()
+
+    def check_concurrently(self, func, *args, **kw):
+        done = [False] * self.CONCURRENCY
+
+        def run(i):
+            func(*args, **kw)
+            done[i] = True
+
+        threads = []
+        try:
+            for i in range(self.CONCURRENCY):
+                t = threading.Thread(target=run, args=(i,))
+                t.daemon = True
+                t.start()
+                threads.append(t)
+        finally:
+            for t in threads:
+                t.join()
+
+        self.assertTrue(all(done))


-- 
To view, visit http://gerrit.ovirt.org/33980
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3ca9d0013126f3c2cbca05cabb70b0622fabb683
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Nir Soffer <[email protected]>
_______________________________________________
vdsm-patches mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to