You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2016/01/27 22:57:24 UTC

[1/2] qpid-proton git commit: PROTON-1062: c++: Fix error message code in io.cpp.

Repository: qpid-proton
Updated Branches:
  refs/heads/master 6f8bc907c -> 7b4fa65a2


PROTON-1062: c++: Fix error message code in io.cpp.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2bc4d25b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2bc4d25b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2bc4d25b

Branch: refs/heads/master
Commit: 2bc4d25b143ce085364f2e03f368cd971aa62fab
Parents: 6f8bc90
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Jan 26 13:19:17 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jan 27 16:49:21 2016 -0500

----------------------------------------------------------------------
 proton-c/bindings/cpp/src/posix/io.cpp | 22 +++++++---------------
 1 file changed, 7 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2bc4d25b/proton-c/bindings/cpp/src/posix/io.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/posix/io.cpp b/proton-c/bindings/cpp/src/posix/io.cpp
index 2fef3ea..6532995 100644
--- a/proton-c/bindings/cpp/src/posix/io.cpp
+++ b/proton-c/bindings/cpp/src/posix/io.cpp
@@ -34,22 +34,14 @@ namespace io {
 const descriptor INVALID_DESCRIPTOR = -1;
 
 std::string error_str() {
-#ifdef USE_STRERROR_R
-    char buf[256];
-    strerror_r(errno, buf, sizeof(buf));
-    return buf;
-#elifdef USE_STRERROR_S
-    char buf[256];
-    strerror_s(buf, sizeof(buf), errno);
-    return buf;
-#elifdef USE_OLD_STRERROR
-    char buf[256];
-    strncpy(buf, strerror(errno), sizeof(buf));
-    return buf;
+    char buf[512] = "Unknown error";
+#ifdef _GNU_SOURCE
+    // GNU strerror_r returns the message
+    return ::strerror_r(errno, buf, sizeof(buf));
 #else
-    std::ostringstream os;
-    os <<  "system error (" << errno << ")";
-    return os.str();
+    // POSIX strerror_r doesn't return the buffer
+    ::strerror_r(errno, buf, sizeof(buf));
+    return std::string(buf)
 #endif
 }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[2/2] qpid-proton git commit: PROTON-1062: c++: Improved example test runner for connection_engine tests.

Posted by ac...@apache.org.
PROTON-1062: c++: Improved example test runner for connection_engine tests.

Fixes a test hang on windows.

Monitor stdout to for 'ready' messages instead of testing ports: faster, more portable.
Detect & raise broker errors, restart broker for remaining tests.
Keep all process output for verificiation and error reporting.
Clean up stray processes.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/7b4fa65a
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/7b4fa65a
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/7b4fa65a

Branch: refs/heads/master
Commit: 7b4fa65a20da04ce32bd570b6552f7287adee665
Parents: 2bc4d25
Author: Alan Conway <ac...@redhat.com>
Authored: Tue Jan 26 13:01:01 2016 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed Jan 27 16:55:07 2016 -0500

----------------------------------------------------------------------
 examples/cpp/CMakeLists.txt         |  70 +++---
 examples/cpp/broker.cpp             |   4 +-
 examples/cpp/engine/CMakeLists.txt  |  39 +---
 examples/cpp/engine/example_test.py | 182 ----------------
 examples/cpp/engine/helloworld.cpp  |   1 -
 examples/cpp/example_test.py        | 361 +++++++++++++++++++------------
 examples/cpp/helloworld.cpp         |   1 -
 examples/cpp/server.cpp             |   4 +-
 8 files changed, 268 insertions(+), 394 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index 14d5748..4f6b742 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -21,43 +21,47 @@ find_package(ProtonCpp REQUIRED)
 
 include_directories(${ProtonCpp_INCLUDE_DIRS})
 
-set(examples
-  broker
-  helloworld
-  helloworld_direct
-  simple_recv
-  simple_send
-  direct_recv
-  direct_send
-  client
-  server
-  server_direct
-  recurring_timer
-  connection_options
-  queue_browser
-  selected_recv
-  ssl
-  ssl_client_cert
-  encode_decode)
-
-foreach(example ${examples})
+foreach(example
+    broker
+    helloworld
+    helloworld_direct
+    simple_recv
+    simple_send
+    direct_recv
+    direct_send
+    client
+    server
+    server_direct
+    recurring_timer
+    connection_options
+    queue_browser
+    selected_recv
+    ssl
+    ssl_client_cert
+    encode_decode)
   add_executable(${example} ${example}.cpp)
   target_link_libraries(${example} ${ProtonCpp_LIBRARIES})
   set_source_files_properties(${example}.cpp PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
 endforeach()
 
-set(env_py "${CMAKE_SOURCE_DIR}/proton-c/env.py")
-set(test_bin_dir "$<TARGET_FILE_DIR:broker>")
-if (WIN32)
-  # Ignore existing path (usualy containting spaces, escape chars).
-  # Choose just enough path for Windows, ';' separated.
-  set(test_path "${test_bin_dir}" "$<TARGET_FILE_DIR:qpid-proton>" "$<TARGET_FILE_DIR:qpid-proton-cpp>")
-else(WIN32)
-  # ':' separated path with test_bin_dir first.
-  set(test_path "${test_bin_dir}:$ENV{PATH}")
-endif(WIN32)
+add_subdirectory(engine)
 
-add_test(NAME cpp_example_test
-  COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v)
+set(env_py ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py)
 
-add_subdirectory(engine)
+function(set_test_path dir)
+  if (WIN32)
+    set(test_path "${dir}" "$<TARGET_FILE_DIR:qpid-proton>" "$<TARGET_FILE_DIR:qpid-proton-cpp>" PARENT_SCOPE)
+  else(WIN32)
+    set(test_path "${dir}:$ENV{PATH}" PARENT_SCOPE)
+  endif(WIN32)
+endfunction()
+
+set_test_path("$<TARGET_FILE_DIR:broker>")
+
+add_test(NAME cpp_container_example_test
+  COMMAND ${env_py} -- "PATH=${test_path}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleTest)
+
+set_test_path("$<TARGET_FILE_DIR:engine-broker>")
+
+add_test(NAME cpp_engine_example_test
+  COMMAND ${env_py} -- "PATH=${test_path}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ConnectionEngineExampleTest)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/broker.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/broker.cpp b/examples/cpp/broker.cpp
index 48efa93..ae42b20 100644
--- a/examples/cpp/broker.cpp
+++ b/examples/cpp/broker.cpp
@@ -62,10 +62,10 @@ int main(int argc, char **argv) {
     options opts(argc, argv);
 
     opts.add_value(url, 'a', "address", "listen on URL", "URL");
-    
+
     try {
         opts.parse();
-        
+
         broker b(url);
         proton::container(b.handler()).run();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/engine/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/engine/CMakeLists.txt b/examples/cpp/engine/CMakeLists.txt
index ceecc2b..bafa20c 100644
--- a/examples/cpp/engine/CMakeLists.txt
+++ b/examples/cpp/engine/CMakeLists.txt
@@ -21,38 +21,17 @@ find_package(ProtonCpp REQUIRED)
 
 include_directories(${ProtonCpp_INCLUDE_DIRS})
 
-set(examples
-  broker
-  helloworld
-  simple_recv
-  simple_send
-  direct_recv
-  direct_send
-  client
-  server)
-
-foreach(example ${examples})
-  set(extra_source "")
-  if (example EQUAL broker)
-    set(extra_source broker.hpp)
-  endif()
+foreach(example
+    broker
+    helloworld
+    simple_recv
+    simple_send
+    direct_recv
+    direct_send
+    client
+    server)
   add_executable(engine-${example} ${example}.cpp ${extra_source})
   target_link_libraries(engine-${example} ${ProtonCpp_LIBRARIES})
   set_source_files_properties(engine-${example}.cpp PROPERTIES COMPILE_FLAGS "${CXX_WARNING_FLAGS}")
   set_target_properties(engine-${example} PROPERTIES OUTPUT_NAME ${example})
 endforeach()
-
-set(env_py "${CMAKE_SOURCE_DIR}/proton-c/env.py")
-set(test_bin_dir "$<TARGET_FILE_DIR:engine-broker>")
-
-if (WIN32)
-  # Ignore existing path (usualy containting spaces, escape chars).
-  # Choose just enough path for Windows, ';' separated.
-  set(test_path "${test_bin_dir}" "$<TARGET_FILE_DIR:qpid-proton>" "$<TARGET_FILE_DIR:qpid-proton-cpp>")
-else(WIN32)
-  # ':' separated path with test_bin_dir first.
-  set(test_path "${test_bin_dir}:$ENV{PATH}")
-endif(WIN32)
-
-add_test(NAME cpp_example_engine_test
-  COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/engine/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/engine/example_test.py b/examples/cpp/engine/example_test.py
deleted file mode 100644
index a4c4c17..0000000
--- a/examples/cpp/engine/example_test.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License
-#
-
-# This is a test script to run the examples and verify that they behave as expected.
-
-import unittest
-import os, sys, socket, time
-from  random import randrange
-from subprocess import Popen, PIPE, STDOUT
-from copy import copy
-import platform
-from os.path import dirname as dirname
-
-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:
-        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"""
-
-    @classmethod
-    def get(cls):
-        if not hasattr(cls, "_broker"):
-            cls._broker = Broker()
-        return cls._broker
-
-    @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)
-
-class ExampleTest(unittest.TestCase):
-    """Run the examples, verify they behave as expected."""
-
-    @classmethod
-    def tearDownClass(self):
-        Broker.stop()
-
-    def test_helloworld(self):
-        b = Broker.get()
-        hw = execute("helloworld", b.addr)
-        self.assertEqual('Hello World!\n', hw)
-
-    def test_simple_send_recv(self):
-        b = Broker.get()
-        send = execute("simple_send", "-a", b.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_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))
-        recv_expect = "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
-        self.assertEqual(recv_expect, 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
-        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))
-        send_expect = "all messages confirmed\n"
-        self.assertEqual(send_expect, 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.
-All mimsy were the borogroves, => ALL MIMSY WERE THE BOROGROVES,
-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_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
-        self.assertEqual(recv_expect, 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()
-
-if __name__ == "__main__":
-    unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/engine/helloworld.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/engine/helloworld.cpp b/examples/cpp/engine/helloworld.cpp
index 4440e4d..43c4a03 100644
--- a/examples/cpp/engine/helloworld.cpp
+++ b/examples/cpp/engine/helloworld.cpp
@@ -54,7 +54,6 @@ class hello_world : public proton::handler {
 int main(int argc, char **argv) {
     try {
         proton::url url(argc > 1 ? argv[1] : "127.0.0.1:5672/examples");
-
         hello_world hw(url.path());
         proton::io::socket_engine(url, hw).run();
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 9aa390c..d6675ff 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -20,179 +20,210 @@
 # 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
+def pick_addr():
+    """Pick a new host:port address."""
+    # TODO Conway 2015-07-14: need a safer way to pick ports.
+    p =  randrange(10000, 20000)
+    return "127.0.0.1:%s" % p
+
+class ProcError(Exception):
+    """An exception that captures failed process output"""
+    def __init__(self, proc, what="non-0 exit"):
+        out = proc.out.strip()
         if out:
-            out = out.translate(None, '\r')
-    return out
+            out = "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^\n" % out
+        else:
+            out = ", no output)"
+        super(Exception, self, ).__init__(
+            "%s %s, code=%s%s" % (proc.args, what, proc.returncode, out))
 
-def execute(*args):
-    return verify(background(*args))
+class Proc(Popen):
+    """A example process that stores its stdout and can scan it for a 'ready' pattern'"""
 
-NULL = open(os.devnull, 'w')
+    if "VALGRIND" in os.environ and os.environ["VALGRIND"]:
+        env_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"]
+    else:
+        env_args = []
 
-def wait_addr(addr, timeout=10):
-    """Wait up to timeout for something to listen on port"""
-    deadline = time.time() + timeout
-    while time.time() < deadline:
+    def __init__(self, args, ready=None, timeout=10, **kwargs):
+        """Start an example process"""
+        args = list(args)
+        if platform.system() == "Windows":
+            args[0] += ".exe"
+        self.timeout = timeout
+        self.args = args
+        self.out = ""
+        args = self.env_args + args
         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)
+            Popen.__init__(self, args, stdout=PIPE, stderr=STDOUT, **kwargs)
+        except Exception, e:
+            raise ProcError(self, str(e))
+        # Start reader thread.
+        self.pattern = ready
+        self.ready = Event()
+        self.error = None
+        self.thread = Thread(target=self.run_)
+        self.thread.daemon = True
+        self.thread.start()
+        if self.pattern:
+            self.wait_ready()
 
-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 run_(self):
+        try:
+            while True:
+                l = self.stdout.readline()
+                if not l: break
+                self.out += l.translate(None, "\r")
+                if self.pattern is not None:
+                    if re.search(self.pattern, l):
+                        self.ready.set()
+            if self.wait() != 0:
+                self.error = ProcError(self)
+        except Exception, e:
+            self.error = sys.exc_info()
+        finally:
+            self.ready.set()
+
+    def safe_kill(self):
+        """Kill and clean up zombie but don't wait forever. No exceptions."""
+        try:
+            self.kill()
+            self.thread.join(self.timeout)
+        except: pass
+        return self.out
+
+    def check_(self):
+        if self.error:
+            if isinstance(self.error, Exception):
+                raise self.error
+            raise self.error[0], self.error[1], self.error[2] # with traceback
+
+    def wait_ready(self):
+        """Wait for ready to appear in output"""
+        if self.ready.wait(self.timeout):
+            self.check_()
+            return self.out
+        else:
+            self.safe_kill()
+            raise ProcError(self, "timeout waiting for '%s'" % self.pattern)
+
+    def wait_exit(self):
+        """Wait for process to exit, return output. Raise ProcError on failure."""
+        self.thread.join(self.timeout)
+        if self.poll() is not None:
+            self.check_()
+            return self.out
+        else:
+            raise ProcError(self, "timeout waiting for exit")
 
-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"""
+class ExampleTestCase(unittest.TestCase):
+    def setUp(self):
+        self.procs = []
+
+    def tearDown(self):
+        for p in self.procs:
+            p.safe_kill()
+
+    def proc(self, *args, **kwargs):
+        p = Proc(*args, **kwargs)
+        self.procs.append(p)
+        return p
+
+
+class BrokerTestCase(ExampleTestCase):
+    """
+    ExampleTest that starts a broker in setUpClass and kills it in tearDownClass.
+    """
 
     @classmethod
-    def get(cls):
-        if not hasattr(cls, "_broker"):
-            cls._broker = Broker()
-        return cls._broker
+    def setUpClass(cls):
+        cls.addr = pick_addr() + "/examples"
+        cls.broker = Proc(["broker", "-a", cls.addr], ready="listening")
+        cls.broker.wait_ready()
 
     @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.safe_kill()
 
-class ExampleTest(unittest.TestCase):
-    """Run the examples, verify they behave as expected."""
+    def tearDown(self):
+        super(BrokerTestCase, self).tearDown()
+        b = type(self).broker
+        if b.poll() !=  None: # Broker crashed
+            type(self).setUpClass() # Start another for the next test.
+            raise ProcError(b, "broker crash")
 
-    @classmethod
-    def tearDownClass(self):
-        Broker.stop()
+
+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.
+All mimsy were the borogroves, => ALL MIMSY WERE THE BOROGROVES,
+And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE.
+"""
+
+def recv_expect(name, addr):
+    return "%s listening on amqp://%s\n%s" % (
+        name, addr, "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)]))
+
+class ContainerExampleTest(BrokerTestCase):
+    """Run the container examples, verify they behave as expected."""
 
     def test_helloworld(self):
-        b = Broker.get()
-        hw = execute("helloworld", b.addr)
-        self.assertEqual('Hello World!\n', hw)
+        self.assertEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit())
 
     def test_helloworld_direct(self):
-        addr = pick_addr()
-        hw = execute("helloworld_direct", addr)
-        self.assertEqual('Hello World!\n', hw)
+        self.assertEqual('Hello World!\n', self.proc(["helloworld_direct", pick_addr()]).wait_exit())
 
     def test_simple_send_recv(self):
-        b = Broker.get()
-        send = execute("simple_send", "-a", b.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_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
-        self.assertEqual(recv_expect, recv)
+        self.assertEqual("all messages confirmed\n",
+                         self.proc(["simple_send", "-a", self.addr]).wait_exit())
+        self.assertEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
+
+    def test_simple_recv_send(self):
+        # Start receiver first, then run sender"""
+        recv = self.proc(["simple_recv", "-a", self.addr])
+        self.assertEqual("all messages confirmed\n",
+                         self.proc(["simple_send", "-a", self.addr]).wait_exit())
+        self.assertEqual(recv_expect("simple_recv", self.addr), recv.wait_exit())
+
 
     def test_simple_send_direct_recv(self):
         addr = pick_addr()
-        recv = background("direct_recv", "-a", addr)
-        wait_addr(addr)
-        self.assertEqual("all messages confirmed\n", execute("simple_send", "-a", addr))
-        recv_expect = "direct_recv listening on amqp://%s\n" % (addr)
-        recv_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
-        self.assertEqual(recv_expect, verify(recv))
+        recv = self.proc(["direct_recv", "-a", addr], "listening")
+        self.assertEqual("all messages confirmed\n",
+                         self.proc(["simple_send", "-a", addr]).wait_exit())
+        self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
 
     def test_simple_recv_direct_send(self):
         addr = pick_addr()
-        send = background("direct_send", "-a", addr)
-        wait_addr(addr)
-        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))
-        send_expect = "direct_send listening on amqp://%s\nall messages confirmed\n" % (addr)
-        self.assertEqual(send_expect, 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.
-All mimsy were the borogroves, => ALL MIMSY WERE THE BOROGROVES,
-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_expect += "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])
-        self.assertEqual(recv_expect, verify(recv))
+        send = self.proc(["direct_send", "-a", addr], "listening")
+        self.assertEqual(recv_expect("simple_recv", addr),
+                         self.proc(["simple_recv", "-a", addr]).wait_exit())
+
+        self.assertEqual(
+            "direct_send listening on amqp://%s\nall messages confirmed\n" % addr,
+            send.wait_exit())
 
     def test_request_response(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.proc(["server", "-a", self.addr], "connected")
+        self.assertEqual(CLIENT_EXPECT,
+                         self.proc(["client", "-a", self.addr]).wait_exit())
 
     def test_request_response_direct(self):
         addr = pick_addr()
-        server = background("server_direct", "-a", addr+"/examples")
-        wait_addr(addr)
-        try:
-            self.assertEqual(execute("client", "-a", addr+"/examples"), self.CLIENT_EXPECT)
-        finally:
-            server.kill()
+        server = self.proc(["server_direct", "-a", addr+"/examples"], "listening")
+        self.assertEqual(CLIENT_EXPECT,
+                         self.proc(["client", "-a", addr+"/examples"]).wait_exit())
 
     def test_encode_decode(self):
-        expect="""
+        want="""
 == Array, list and map of uniform type.
 array<int>[int(1), int(2), int(3)]
 [ 1 2 3 ]
@@ -215,7 +246,7 @@ list[int(42), boolean(false), symbol(x)]
 map{string(k1):int(42), symbol(k2):boolean(false)}
 """
         self.maxDiff = None
-        self.assertEqual(expect, execute("encode_decode"))
+        self.assertEqual(want, self.proc(["encode_decode"]).wait_exit())
 
     def test_recurring_timer(self):
         env = copy(os.environ)        # Disable valgrind, this test is time-sensitive.
@@ -227,18 +258,22 @@ Tick...
 Tock...
 """
             self.maxDiff = None
-            self.assertEqual(expect, execute("recurring_timer", "-t", ".05", "-k", ".01"))
+            self.assertEqual(expect, self.proc(["recurring_timer", "-t", ".05", "-k", ".01"]).wait_exit())
         finally:
             os.environ = env    # Restore environment
 
+    def ssl_certs_dir(self):
+        """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")
+
     def test_ssl(self):
         # SSL without SASL
-        expect="""Outgoing client connection connected via SSL.  Server certificate identity CN=test_server
-Hello World!
-"""
         addr = "amqps://" + pick_addr() + "/examples"
-        ignore_first_line, ignore_nl, ssl_hw = execute("ssl", addr, ssl_certs_dir()).partition('\n')
-        self.assertEqual(expect, ssl_hw)
+        out = self.proc(["ssl", addr, self.ssl_certs_dir()]).wait_exit()
+        expect = "Outgoing client connection connected via SSL.  Server certificate identity CN=test_server\nHello World!"
+        self.assertIn(expect, out)
+
 
     def test_ssl_client_cert(self):
         # SSL with SASL EXTERNAL
@@ -247,8 +282,48 @@ Outgoing client connection connected via SSL.  Server certificate identity CN=te
 Hello World!
 """
         addr = "amqps://" + pick_addr() + "/examples"
-        ignore_first_line, ignore_nl, ssl_hw = execute("ssl_client_cert", addr, ssl_certs_dir()).partition('\n')
-        self.assertEqual(expect, ssl_hw)
+        out = self.proc(["ssl_client_cert", addr, self.ssl_certs_dir()]).wait_exit()
+        self.assertIn(expect, out)
+
+
+class ConnectionEngineExampleTest(BrokerTestCase):
+    """Run the connction_engine examples, verify they behave as expected."""
+
+    def test_helloworld(self):
+        self.assertEqual('Hello World!\n',
+                         self.proc(["helloworld", self.addr]).wait_exit())
+
+    def test_simple_send_recv(self):
+        self.assertEqual("all messages confirmed\n",
+                         self.proc(["simple_send", "-a", self.addr]).wait_exit())
+        self.assertEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit())
+
+    def test_simple_recv_send(self):
+        # Start receiver first, then run sender"""
+        recv = self.proc(["simple_recv", "-a", self.addr])
+        self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit())
+        self.assertEqual(recv_expect("simple_recv", self.addr), recv.wait_exit())
+
+
+    def test_simple_send_direct_recv(self):
+        addr = pick_addr()
+        recv = self.proc(["direct_recv", "-a", addr], "listening")
+        self.assertEqual("all messages confirmed\n",
+                         self.proc(["simple_send", "-a", addr]).wait_exit())
+        self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit())
+
+    def test_simple_recv_direct_send(self):
+        addr = pick_addr()
+        send = self.proc(["direct_send", "-a", addr], "listening")
+        self.assertEqual(recv_expect("simple_recv", addr),
+                         self.proc(["simple_recv", "-a", addr]).wait_exit())
+        self.assertEqual("direct_send listening on amqp://%s\nall messages confirmed\n" % addr,
+                         send.wait_exit())
+
+    def test_request_response(self):
+        server = self.proc(["server", "-a", self.addr], "connected")
+        self.assertEqual(CLIENT_EXPECT,
+                         self.proc(["client", "-a", self.addr]).wait_exit())
 
 if __name__ == "__main__":
     unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/helloworld.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/helloworld.cpp b/examples/cpp/helloworld.cpp
index a969f27..5d92981 100644
--- a/examples/cpp/helloworld.cpp
+++ b/examples/cpp/helloworld.cpp
@@ -57,7 +57,6 @@ int main(int argc, char **argv) {
 
         hello_world hw(url);
         proton::container(hw).run();
-
         return 0;
     } catch (const std::exception& e) {
         std::cerr << e.what() << std::endl;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/7b4fa65a/examples/cpp/server.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/server.cpp b/examples/cpp/server.cpp
index d913ee1..8ac34cc 100644
--- a/examples/cpp/server.cpp
+++ b/examples/cpp/server.cpp
@@ -71,7 +71,7 @@ class server : public proton::handler {
         if (!senders[reply_to]) {
             senders[reply_to] = connection.open_sender(reply_to);
         }
-        
+
         senders[reply_to].send(reply);
     }
 };
@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
 
     try {
         opts.parse();
-        
+
         server srv(address);
         proton::container(srv).run();
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org