PROTON-1062: c++: Simplified example test runner for connection_engine tests.
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/9da5b56a Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/9da5b56a Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/9da5b56a Branch: refs/heads/fix Commit: 9da5b56a0551d5a669a48e378b97f73aa1bdb541 Parents: 68f7d3c Author: Alan Conway <[email protected]> Authored: Tue Jan 26 13:01:01 2016 -0500 Committer: Alan Conway <[email protected]> Committed: Tue Jan 26 14:13:41 2016 -0500 ---------------------------------------------------------------------- examples/cpp/engine/example_test.py | 229 ++++++++++++++--------------- proton-c/bindings/cpp/src/handler.cpp | 2 +- 2 files changed, 114 insertions(+), 117 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9da5b56a/examples/cpp/engine/example_test.py ---------------------------------------------------------------------- diff --git a/examples/cpp/engine/example_test.py b/examples/cpp/engine/example_test.py index a4c4c17..ef42455 100644 --- a/examples/cpp/engine/example_test.py +++ b/examples/cpp/engine/example_test.py @@ -20,141 +20,143 @@ # This is a test script to run the examples and verify that they behave as expected. import unittest -import os, sys, socket, time +import os, sys, socket, time, re from random import randrange from subprocess import Popen, PIPE, STDOUT from copy import copy import platform from os.path import dirname as dirname +from threading import Thread, Event -def cmdline(*args): - """Adjust executable name args[0] for windows and/or valgrind""" - args = list(args) - if platform.system() == "Windows": - args[0] += ".exe" - if "VALGRIND" in os.environ and os.environ["VALGRIND"]: - args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", - "--leak-check=full"] + args - return args - -def background(*args): - """Run executable in the backround, return the popen""" - p = Popen(cmdline(*args), stdout=PIPE, stderr=sys.stderr) - p.args = args # Save arguments for debugging output - return p - -def verify(p): - """Wait for executable to exit and verify status.""" - try: - out, err = p.communicate() - except Exception as e: - raise Exception("Error running %s: %s", p.args, e) - if p.returncode: - raise Exception("""%s exit code %s -vvvvvvvvvvvvvvvv -%s -^^^^^^^^^^^^^^^^ -""" % (p.args, p.returncode, out)) - if platform.system() == "Windows": - # Just \n please - if out: - out = out.translate(None, '\r') - return out - -def execute(*args): - return verify(background(*args)) - -NULL = open(os.devnull, 'w') - -def wait_addr(addr, timeout=10): - """Wait up to timeout for something to listen on port""" - deadline = time.time() + timeout - while time.time() < deadline: +class ExampleTest(unittest.TestCase): + """Base class for tests that run example programs and verify their output.""" + + def setUp(self): + self.procs = [] + + def tearDown(self): + for p in self.procs: + try: p.kill() + except: pass + + def cmdline(self, *args): + """Adjust executable name args[0] for windows and/or valgrind""" + args = list(args) + if platform.system() == "Windows": + args[0] += ".exe" + if "VALGRIND" in os.environ and os.environ["VALGRIND"]: + args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", + "--leak-check=full"] + args + return args + + NULL = open(os.devnull, 'w') + + @staticmethod + def wait_line(io, pattern, timeout=5): + found = Event() + def find_line(): + try: + while True: + l = io.readline() + if re.search(pattern, l): + found.set() + break + except Exception, e: pass + t = Thread(target = find_line) + t.daemon = True + t.start() + if not found.wait(timeout): + raise Exception("Timed out waiting for '%s' in output" % pattern) + + @staticmethod + def pick_addr(): + """Pick a new host:port address.""" + # TODO aconway 2015-07-14: need a safer way to pick ports. + p = randrange(10000, 20000) + return "127.0.0.1:%s" % p + + def background(self, *args): + """Run executable in the backround, return the popen""" + p = Popen(self.cmdline(*args), stdout=PIPE, stderr=sys.stderr) + p.args = args # Save arguments for debugging output + self.procs.append(p) + return p + + def verify(self, p): + """Wait for executable to exit and verify status, return the output""" try: - c = socket.create_connection(addr.split(":"), deadline - time.time()) - c.close() - return - except socket.error as e: - time.sleep(0.01) - raise Exception("Timed out waiting for %s", addr) - -def pick_addr(): - """Pick a new host:port address.""" - # TODO aconway 2015-07-14: need a safer way to pick ports. - p = randrange(10000, 20000) - return "127.0.0.1:%s" % p - -def ssl_certs_dir(): - """Absolute path to the test SSL certificates""" - pn_root = dirname(dirname(dirname(sys.argv[0]))) - return os.path.join(pn_root, "examples/cpp/ssl_certs") - -class Broker(object): - """Run the test broker""" + out, err = p.communicate() + except Exception as e: + raise Exception("Error running %s: %s", p.args, e) + if p.returncode: + raise Exception("""%s exit code %s + vvvvvvvvvvvvvvvv + %s + ^^^^^^^^^^^^^^^^ + """ % (p.args, p.returncode, out)) + if platform.system() == "Windows": + # Just \n please + if out: + out = out.translate(None, '\r') + return out + + def execute(self, *args): + """Run a program, verify its exit status and return its output""" + return self.verify(self.background(*args)) + +class BrokerExampleTest(ExampleTest): + """ + ExampleTest that starts a broker in setUpClass and kills it in tearDownClass. + Derived classes should have a 'broker_exe' attribute with the executable. + """ @classmethod - def get(cls): - if not hasattr(cls, "_broker"): - cls._broker = Broker() - return cls._broker + def setUpClass(cls): + if not getattr(cls, "broker", None): + cls.addr = cls.pick_addr() + "/examples" + cls.broker = Popen([cls.broker_exe, "-a", cls.addr], stdout=PIPE, stderr=sys.stderr) + cls.wait_line(cls.broker.stdout, "listening") @classmethod - def stop(cls): - if cls.get() and cls._broker.process: - cls._broker.process.kill() - cls._broker = None - - def __init__(self): - broker_exe = os.environ.get("TEST_BROKER") or "broker" - self.addr = pick_addr() - cmd = cmdline(broker_exe, "-a", self.addr) - try: - self.process = Popen(cmd, stdout=NULL, stderr=sys.stderr) - wait_addr(self.addr) - self.addr += "/examples" - except Exception as e: - raise Exception("Error running %s: %s", cmd, e) + def tearDownClass(cls): + cls.broker.kill() + cls.broker = None -class ExampleTest(unittest.TestCase): + +class ConnectionEngineTest(BrokerExampleTest): """Run the examples, verify they behave as expected.""" - @classmethod - def tearDownClass(self): - Broker.stop() + broker_exe = "broker" def test_helloworld(self): - b = Broker.get() - hw = execute("helloworld", b.addr) + hw = self.execute("helloworld", self.addr) self.assertEqual('Hello World!\n', hw) def test_simple_send_recv(self): - b = Broker.get() - send = execute("simple_send", "-a", b.addr) + send = self.execute("simple_send", "-a", self.addr) self.assertEqual("all messages confirmed\n", send) - recv = execute("simple_recv", "-a", b.addr) - recv_expect = "simple_recv listening on amqp://%s\n" % (b.addr) + recv = self.execute("simple_recv", "-a", self.addr) + recv_expect = "simple_recv listening on amqp://%s\n" % (self.addr) recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)]) self.assertEqual(recv_expect, recv) def test_simple_send_direct_recv(self): - addr = pick_addr() - recv = background("direct_recv", "-a", addr) - while not "listening" in recv.stdout.readline(): - pass - self.assertEqual("all messages confirmed\n", execute("simple_send", "-a", addr)) + addr = self.pick_addr() + recv = self.background("direct_recv", "-a", addr) + self.wait_line(recv.stdout, "listening") + self.assertEqual("all messages confirmed\n", self.execute("simple_send", "-a", addr)) recv_expect = "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)]) - self.assertEqual(recv_expect, verify(recv)) + self.assertEqual(recv_expect, self.verify(recv)) def test_simple_recv_direct_send(self): - addr = pick_addr() - send = background("direct_send", "-a", addr) - while not "listening" in send.stdout.readline(): - pass + addr = self.pick_addr() + send = self.background("direct_send", "-a", addr) + self.wait_line(send.stdout, "listening") recv_expect = "simple_recv listening on amqp://%s\n" % (addr) recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)]) - self.assertEqual(recv_expect, execute("simple_recv", "-a", addr)) + self.assertEqual(recv_expect, self.execute("simple_recv", "-a", addr)) send_expect = "all messages confirmed\n" - self.assertEqual(send_expect, verify(send)) + self.assertEqual(send_expect, self.verify(send)) CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES Did gire and gymble in the wabe. => DID GIRE AND GYMBLE IN THE WABE. @@ -163,20 +165,15 @@ And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE. """ def test_simple_recv_send(self): # Start receiver first, then run sender""" - b = Broker.get() - recv = background("simple_recv", "-a", b.addr) - self.assertEqual("all messages confirmed\n", execute("simple_send", "-a", b.addr)) - recv_expect = "simple_recv listening on amqp://%s\n" % (b.addr) + recv = self.background("simple_recv", "-a", self.addr) + self.assertEqual("all messages confirmed\n", self.execute("simple_send", "-a", self.addr)) + recv_expect = "simple_recv listening on amqp://%s\n" % (self.addr) recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)]) - self.assertEqual(recv_expect, verify(recv)) + self.assertEqual(recv_expect, self.verify(recv)) def test_client_server(self): - b = Broker.get() - server = background("server", "-a", b.addr) - try: - self.assertEqual(execute("client", "-a", b.addr), self.CLIENT_EXPECT) - finally: - server.kill() + server = self.background("server", "-a", self.addr) + self.assertEqual(self.execute("client", "-a", self.addr), self.CLIENT_EXPECT) if __name__ == "__main__": unittest.main() http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/9da5b56a/proton-c/bindings/cpp/src/handler.cpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/src/handler.cpp b/proton-c/bindings/cpp/src/handler.cpp index 34c19e6..9d8ca76 100644 --- a/proton-c/bindings/cpp/src/handler.cpp +++ b/proton-c/bindings/cpp/src/handler.cpp @@ -63,6 +63,6 @@ void handler::on_transaction_declare(event &e) { on_unhandled(e); } void handler::on_unhandled(event &) {} // XXXXX: FIXME - temporarily disabled exception to keep tests passing //void handler::on_unhandled_error(event &, const condition& c) { throw std::runtime_error(c.str()); } -void handler::on_unhandled_error(event &, const condition& c) {} +void handler::on_unhandled_error(event &, const condition&) {} } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
