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
