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 2017/05/24 19:44:34 UTC

[4/7] qpid-proton git commit: PROTON-1288: c++ reinstate engine_test as connection_driver_test

PROTON-1288: c++ reinstate engine_test as connection_driver_test


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

Branch: refs/heads/master
Commit: f2df847b552685f80429715832e55207d68bbbcb
Parents: 48a5e47
Author: Alan Conway <ac...@redhat.com>
Authored: Fri May 19 11:04:44 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Wed May 24 15:05:14 2017 -0400

----------------------------------------------------------------------
 examples/cpp/message_properties.cpp             | 101 +++++++
 proton-c/bindings/cpp/CMakeLists.txt            |   2 +-
 .../bindings/cpp/include/proton/terminus.hpp    |   2 +-
 .../bindings/cpp/src/connection_driver_test.cpp | 260 ++++++++++++++++++
 proton-c/bindings/cpp/src/engine_test.cpp       | 268 -------------------
 .../bindings/cpp/src/include/proton_bits.hpp    |   4 +-
 .../bindings/cpp/src/include/proton_event.hpp   |   5 +
 .../cpp/src/include/test_dummy_container.hpp    |   1 -
 8 files changed, 370 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/examples/cpp/message_properties.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/message_properties.cpp b/examples/cpp/message_properties.cpp
new file mode 100644
index 0000000..64d597b
--- /dev/null
+++ b/examples/cpp/message_properties.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+#include <proton/message.hpp>
+#include <proton/types.hpp>
+#include <iostream>
+#include <map>
+
+int main(int argc, char **argv) {
+    try {
+        proton::message m;
+
+        // Setting properties: legal types are converted automatically to their
+        // AMQP counterpart.
+        m.properties().put("short", int16_t(123));
+        m.properties().put("string", "foo");
+        m.properties().put("symbol", proton::symbol("sym"));
+        m.properties().put("bool", true);
+
+        // Examining properties using proton::get()
+
+        // 1 argument get<>() template specifies expected type of property.
+        std::string s = proton::get<std::string>(m.properties().get("string"));
+
+        // 2 argument get, property must have matching type to output argument.
+        int16_t i;
+        proton::get(m.properties().get("short"), i);
+
+        // Checking property types
+        proton::type_id type = m.properties().get("symbol").type();
+        if (type != proton::SYMBOL) {
+            throw std::logic_error("wrong type!");
+        }
+
+        // proton::scalar has its own ostream <<
+        std::cout << "using put/get:"
+                  << " short=" << i
+                  << " string=" << s
+                  << " symbol=" << m.properties().get("symbol")
+                  << " bool=" << m.properties().get("bool")
+                  << std::endl;
+
+        // Converting properties to a compatible type
+        std::cout << "using coerce:"
+                  << " short(as int)=" <<  proton::coerce<int>(m.properties().get("short"))
+                  << " bool(as int)=" << proton::coerce<int>(m.properties().get("bool"))
+                  << std::endl;
+
+        // Extract the properties map for more complex map operations.
+        proton::property_std_map props;
+        proton::get(m.properties().value(), props);
+        for (proton::property_std_map::iterator i = props.begin(); i != props.end(); ++i) {
+            std::cout << "props[" << i->first << "]=" << i->second << std::endl;
+        }
+        props["string"] = "bar";
+        props["short"] = 42;
+        // Update the properties in the message from props
+        m.properties().value() = props;
+
+        std::cout << "short=" << m.properties().get("short")
+                  << " string=" << m.properties().get("string")
+                  << std::endl;
+
+        // proton::get throws an exception if types do not match exactly.
+        try {
+            proton::get<uint32_t>(m.properties().get("short")); // bad: uint32_t != int16_t
+            throw std::logic_error("expected exception");
+        } catch (const proton::conversion_error& e) {
+            std::cout << "expected conversion_error: \"" << e.what() << '"' << std::endl;
+        }
+
+        // proton::coerce throws an exception if types are not convertible.
+        try {
+            proton::get<uint32_t>(m.properties().get("string"));  // bad: string to uint32_t
+            throw std::logic_error("expected exception");
+        } catch (const proton::conversion_error& e) {
+            std::cout << "expected conversion_error: \"" << e.what() << '"' << std::endl;
+        }
+
+        return 0;
+    } catch (const std::exception& e) {
+        std::cerr << "unexpected exception: " << e.what() << std::endl;
+        return 1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt
index 0cc4024..04cb568 100644
--- a/proton-c/bindings/cpp/CMakeLists.txt
+++ b/proton-c/bindings/cpp/CMakeLists.txt
@@ -172,7 +172,7 @@ macro(add_cpp_test test)
 endmacro(add_cpp_test)
 
 add_cpp_test(codec_test)
-#add_cpp_test(engine_test)
+add_cpp_test(connection_driver_test)
 add_cpp_test(thread_safe_test)
 add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests)
 add_cpp_test(message_test)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/include/proton/terminus.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/terminus.hpp b/proton-c/bindings/cpp/include/proton/terminus.hpp
index b63a8ad..e339b84 100644
--- a/proton-c/bindings/cpp/include/proton/terminus.hpp
+++ b/proton-c/bindings/cpp/include/proton/terminus.hpp
@@ -94,7 +94,7 @@ class terminus {
     PN_CPP_EXTERN value node_properties() const;
 
   protected:
-    pn_terminus_t *pn_object() { return object_; }
+    pn_terminus_t *pn_object() const { return object_; }
   private:
     pn_terminus_t* object_;
     pn_link_t* parent_;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/connection_driver_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/connection_driver_test.cpp b/proton-c/bindings/cpp/src/connection_driver_test.cpp
new file mode 100644
index 0000000..372240b
--- /dev/null
+++ b/proton-c/bindings/cpp/src/connection_driver_test.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ */
+
+
+#include "test_bits.hpp"
+#include "proton_bits.hpp"
+
+#include "proton/io/connection_driver.hpp"
+#include "proton/io/link_namer.hpp"
+#include "proton/link.hpp"
+#include "proton/messaging_handler.hpp"
+#include "proton/receiver_options.hpp"
+#include "proton/sender_options.hpp"
+#include "proton/source_options.hpp"
+#include "proton/types_fwd.hpp"
+#include "proton/uuid.hpp"
+
+#include <deque>
+#include <algorithm>
+
+namespace {
+
+using namespace std;
+using namespace proton;
+
+using proton::io::connection_driver;
+using proton::io::const_buffer;
+using proton::io::mutable_buffer;
+
+typedef std::deque<char> byte_stream;
+
+/// In memory connection_driver that reads and writes from byte_streams
+struct in_memory_driver : public connection_driver {
+
+    byte_stream& reads;
+    byte_stream& writes;
+
+    in_memory_driver(byte_stream& rd, byte_stream& wr) : reads(rd), writes(wr) {}
+
+    void do_read() {
+        mutable_buffer rbuf = read_buffer();
+        size_t size = std::min(reads.size(), rbuf.size);
+        if (size) {
+            copy(reads.begin(), reads.begin()+size, static_cast<char*>(rbuf.data));
+            read_done(size);
+            reads.erase(reads.begin(), reads.begin()+size);
+        }
+    }
+
+    void do_write() {
+        const_buffer wbuf = write_buffer();
+        if (wbuf.size) {
+            writes.insert(writes.begin(),
+                          static_cast<const char*>(wbuf.data),
+                          static_cast<const char*>(wbuf.data) + wbuf.size);
+            write_done(wbuf.size);
+        }
+    }
+
+    void process() {
+        if (!dispatch())
+            throw std::runtime_error("unexpected close: "+connection().error().what());
+        do_read();
+        do_write();
+        dispatch();
+    }
+};
+
+/// A pair of drivers that talk to each other in-memory, simulating a connection.
+struct driver_pair {
+    byte_stream ab, ba;
+    in_memory_driver a, b;
+
+    driver_pair(const connection_options& oa, const connection_options& ob)
+        : a(ba, ab), b(ab, ba)
+    {
+        a.connect(oa);
+        b.accept(ob);
+    }
+
+    void process() { a.process(); b.process(); }
+};
+
+template <class S> typename S::value_type quick_pop(S& s) {
+    ASSERT(!s.empty());
+    typename S::value_type x = s.front();
+    s.pop_front();
+    return x;
+}
+
+/// A handler that records incoming endpoints, errors etc.
+struct record_handler : public messaging_handler {
+    std::deque<proton::receiver> receivers;
+    std::deque<proton::sender> senders;
+    std::deque<proton::session> sessions;
+    std::deque<std::string> unhandled_errors, transport_errors, connection_errors;
+
+    void on_receiver_open(receiver &l) PN_CPP_OVERRIDE {
+        receivers.push_back(l);
+    }
+
+    void on_sender_open(sender &l) PN_CPP_OVERRIDE {
+        senders.push_back(l);
+    }
+
+    void on_session_open(session &s) PN_CPP_OVERRIDE {
+        sessions.push_back(s);
+    }
+
+    void on_transport_error(transport& t) PN_CPP_OVERRIDE {
+        transport_errors.push_back(t.error().what());
+    }
+
+    void on_connection_error(connection& c) PN_CPP_OVERRIDE {
+        connection_errors.push_back(c.error().what());
+    }
+
+    void on_error(const proton::error_condition& c) PN_CPP_OVERRIDE {
+        unhandled_errors.push_back(c.what());
+    }
+};
+
+struct namer : public io::link_namer {
+    char name;
+    namer(char c) : name(c) {}
+    std::string link_name() { return std::string(1, name++); }
+};
+
+void test_driver_link_id() {
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+    e.a.connect(ha);
+    e.b.accept(hb);
+
+    namer na('x');
+    namer nb('b');
+    connection ca = e.a.connection();
+    connection cb = e.b.connection();
+    set_link_namer(ca, na);
+    set_link_namer(cb, nb);
+
+    e.b.connection().open();
+
+    e.a.connection().open_sender("foo");
+    while (ha.senders.empty() || hb.receivers.empty()) e.process();
+    sender s = quick_pop(ha.senders);
+    ASSERT_EQUAL("x", s.name());
+
+    ASSERT_EQUAL("x", quick_pop(hb.receivers).name());
+
+    e.a.connection().open_receiver("bar");
+    while (ha.receivers.empty() || hb.senders.empty()) e.process();
+    ASSERT_EQUAL("y", quick_pop(ha.receivers).name());
+    ASSERT_EQUAL("y", quick_pop(hb.senders).name());
+
+    e.b.connection().open_receiver("");
+    while (ha.senders.empty() || hb.receivers.empty()) e.process();
+    ASSERT_EQUAL("b", quick_pop(ha.senders).name());
+    ASSERT_EQUAL("b", quick_pop(hb.receivers).name());
+}
+
+void test_endpoint_close() {
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+    e.a.connection().open_sender("x");
+    e.a.connection().open_receiver("y");
+    while (ha.senders.size()+ha.receivers.size() < 2 ||
+           hb.senders.size()+hb.receivers.size() < 2) e.process();
+    proton::link ax = quick_pop(ha.senders), ay = quick_pop(ha.receivers);
+    proton::link bx = quick_pop(hb.receivers), by = quick_pop(hb.senders);
+
+    // Close a link
+    ax.close(proton::error_condition("err", "foo bar"));
+    while (!bx.closed()) e.process();
+    proton::error_condition c = bx.error();
+    ASSERT_EQUAL("err", c.name());
+    ASSERT_EQUAL("foo bar", c.description());
+    ASSERT_EQUAL("err: foo bar", c.what());
+
+    // Close a link with an empty condition
+    ay.close(proton::error_condition());
+    while (!by.closed()) e.process();
+    ASSERT(by.error().empty());
+
+    // Close a connection
+    connection ca = e.a.connection(), cb = e.b.connection();
+    ca.close(proton::error_condition("conn", "bad connection"));
+    while (!cb.closed()) e.process();
+    ASSERT_EQUAL("conn: bad connection", cb.error().what());
+    ASSERT_EQUAL(1u, hb.connection_errors.size());
+    ASSERT_EQUAL("conn: bad connection", hb.connection_errors.front());
+}
+
+void test_driver_disconnected() {
+    // driver.disconnected() aborts the connection and calls the local on_transport_error()
+    record_handler ha, hb;
+    driver_pair e(ha, hb);
+    e.a.connect(ha);
+    e.b.accept(hb);
+    while (!e.a.connection().active() || !e.b.connection().active())
+        e.process();
+
+    // Close a with an error condition. The AMQP connection is still open.
+    e.a.disconnected(proton::error_condition("oops", "driver failure"));
+    ASSERT(!e.a.dispatch());
+    ASSERT(!e.a.connection().closed());
+    ASSERT(e.a.connection().error().empty());
+    ASSERT_EQUAL(0u, ha.connection_errors.size());
+    ASSERT_EQUAL("oops: driver failure", e.a.transport().error().what());
+    ASSERT_EQUAL(1u, ha.transport_errors.size());
+    ASSERT_EQUAL("oops: driver failure", ha.transport_errors.front());
+
+    // In a real app the IO code would detect the abort and do this:
+    e.b.disconnected(proton::error_condition("broken", "it broke"));
+    ASSERT(!e.b.dispatch());
+    ASSERT(!e.b.connection().closed());
+    ASSERT(e.b.connection().error().empty());
+    ASSERT_EQUAL(0u, hb.connection_errors.size());
+    // Proton-C adds (connection aborted) if transport closes too early,
+    // and provides a default message if there is no user message.
+    ASSERT_EQUAL("broken: it broke (connection aborted)", e.b.transport().error().what());
+    ASSERT_EQUAL(1u, hb.transport_errors.size());
+    ASSERT_EQUAL("broken: it broke (connection aborted)", hb.transport_errors.front());
+}
+
+void test_no_container() {
+    // An driver with no container should throw, not crash.
+    connection_driver e;
+    try {
+        e.connection().container();
+        FAIL("expected error");
+    } catch (proton::error) {}
+}
+
+}
+
+int main(int, char**) {
+    int failed = 0;
+    RUN_TEST(failed, test_driver_link_id());
+    RUN_TEST(failed, test_endpoint_close());
+    RUN_TEST(failed, test_driver_disconnected());
+    RUN_TEST(failed, test_no_container());
+    return failed;
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/engine_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/engine_test.cpp b/proton-c/bindings/cpp/src/engine_test.cpp
deleted file mode 100644
index 991836d..0000000
--- a/proton-c/bindings/cpp/src/engine_test.cpp
+++ /dev/null
@@ -1,268 +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.
- */
-
-
-#include "test_bits.hpp"
-#include "test_dummy_container.hpp"
-#include "proton_bits.hpp"
-
-#include "proton/container.hpp"
-#include "proton/uuid.hpp"
-#include "proton/io/connection_driver.hpp"
-#include "proton/io/link_namer.hpp"
-#include "proton/messaging_handler.hpp"
-#include "proton/types_fwd.hpp"
-#include "proton/link.hpp"
-#include <deque>
-#include <algorithm>
-
-namespace {
-
-using namespace std;
-using namespace proton;
-
-using proton::io::connection_driver;
-using proton::io::const_buffer;
-using proton::io::mutable_buffer;
-
-using test::dummy_container;
-
-typedef std::deque<char> byte_stream;
-
-/// In memory connection_driver that reads and writes from byte_streams
-struct in_memory_engine : public connection_driver {
-
-    byte_stream& reads;
-    byte_stream& writes;
-
-    in_memory_engine(byte_stream& rd, byte_stream& wr, class container& cont) :
-        connection_driver(cont), reads(rd), writes(wr) {}
-
-    void do_read() {
-        mutable_buffer rbuf = read_buffer();
-        size_t size = std::min(reads.size(), rbuf.size);
-        if (size) {
-            copy(reads.begin(), reads.begin()+size, static_cast<char*>(rbuf.data));
-            read_done(size);
-            reads.erase(reads.begin(), reads.begin()+size);
-        }
-    }
-
-    void do_write() {
-        const_buffer wbuf = write_buffer();
-        if (wbuf.size) {
-            writes.insert(writes.begin(),
-                          static_cast<const char*>(wbuf.data),
-                          static_cast<const char*>(wbuf.data) + wbuf.size);
-            write_done(wbuf.size);
-        }
-    }
-
-    void process() {
-        if (!dispatch())
-            throw std::runtime_error("unexpected close: "+connection().error().what());
-        do_read();
-        do_write();
-        dispatch();
-    }
-};
-
-/// A pair of engines that talk to each other in-memory, simulating a connection.
-struct engine_pair {
-    dummy_container conta, contb;
-    byte_stream ab, ba;
-    in_memory_engine a, b;
-
-    engine_pair(const connection_options& oa, const connection_options& ob,
-                const std::string& name=""
-    ) :
-        conta(name+"a"), contb(name+"b"), a(ba, ab, conta), b(ab, ba, contb)
-    {
-        a.connect(oa);
-        b.accept(ob);
-    }
-
-    void process() { a.process(); b.process(); }
-};
-
-template <class S> typename S::value_type quick_pop(S& s) {
-    ASSERT(!s.empty());
-    typename S::value_type x = s.front();
-    s.pop_front();
-    return x;
-}
-
-/// A handler that records incoming endpoints, errors etc.
-struct record_handler : public messaging_handler {
-    std::deque<proton::receiver> receivers;
-    std::deque<proton::sender> senders;
-    std::deque<proton::session> sessions;
-    std::deque<std::string> unhandled_errors, transport_errors, connection_errors;
-
-    void on_receiver_open(receiver &l) PN_CPP_OVERRIDE {
-        receivers.push_back(l);
-    }
-
-    void on_sender_open(sender &l) PN_CPP_OVERRIDE {
-        senders.push_back(l);
-    }
-
-    void on_session_open(session &s) PN_CPP_OVERRIDE {
-        sessions.push_back(s);
-    }
-
-    void on_transport_error(transport& t) PN_CPP_OVERRIDE {
-        transport_errors.push_back(t.error().what());
-    }
-
-    void on_connection_error(connection& c) PN_CPP_OVERRIDE {
-        connection_errors.push_back(c.error().what());
-    }
-
-    void on_error(const proton::error_condition& c) PN_CPP_OVERRIDE {
-        unhandled_errors.push_back(c.what());
-    }
-};
-
-struct namer : public io::link_namer {
-    char name;
-    namer(char c) : name(c) {}
-    std::string link_name() { return std::string(1, name++); }
-};
-
-void test_engine_container_link_id() {
-    record_handler ha, hb;
-    engine_pair e(ha, hb, "ids-");
-    e.a.connect(ha);
-    e.b.accept(hb);
-
-    namer na('x');
-    namer nb('b');
-    connection ca = e.a.connection();
-    connection cb = e.b.connection();
-    set_link_namer(ca, na);
-    set_link_namer(cb, nb);
-
-    ASSERT_EQUAL("ids-a", e.a.connection().container_id());
-    e.b.connection().open();
-    ASSERT_EQUAL("ids-b", e.b.connection().container_id());
-
-    e.a.connection().open_sender("foo");
-    while (ha.senders.empty() || hb.receivers.empty()) e.process();
-    sender s = quick_pop(ha.senders);
-    ASSERT_EQUAL("x", s.name());
-
-    ASSERT_EQUAL("x", quick_pop(hb.receivers).name());
-
-    e.a.connection().open_receiver("bar");
-    while (ha.receivers.empty() || hb.senders.empty()) e.process();
-    ASSERT_EQUAL("y", quick_pop(ha.receivers).name());
-    ASSERT_EQUAL("y", quick_pop(hb.senders).name());
-
-    e.b.connection().open_receiver("");
-    while (ha.senders.empty() || hb.receivers.empty()) e.process();
-    ASSERT_EQUAL("b", quick_pop(ha.senders).name());
-    ASSERT_EQUAL("b", quick_pop(hb.receivers).name());
-}
-
-void test_endpoint_close() {
-    record_handler ha, hb;
-    engine_pair e(ha, hb);
-    e.a.connection().open_sender("x");
-    e.a.connection().open_receiver("y");
-    while (ha.senders.size()+ha.receivers.size() < 2 ||
-           hb.senders.size()+hb.receivers.size() < 2) e.process();
-    proton::link ax = quick_pop(ha.senders), ay = quick_pop(ha.receivers);
-    proton::link bx = quick_pop(hb.receivers), by = quick_pop(hb.senders);
-
-    // Close a link
-    ax.close(proton::error_condition("err", "foo bar"));
-    while (!bx.closed()) e.process();
-    proton::error_condition c = bx.error();
-    ASSERT_EQUAL("err", c.name());
-    ASSERT_EQUAL("foo bar", c.description());
-    ASSERT_EQUAL("err: foo bar", c.what());
-
-    // Close a link with an empty condition
-    ay.close(proton::error_condition());
-    while (!by.closed()) e.process();
-    ASSERT(by.error().empty());
-
-    // Close a connection
-    connection ca = e.a.connection(), cb = e.b.connection();
-    ca.close(proton::error_condition("conn", "bad connection"));
-    while (!cb.closed()) e.process();
-    ASSERT_EQUAL("conn: bad connection", cb.error().what());
-    ASSERT_EQUAL(1u, hb.connection_errors.size());
-    ASSERT_EQUAL("conn: bad connection", hb.connection_errors.front());
-}
-
-void test_engine_disconnected() {
-    // engine.disconnected() aborts the connection and calls the local on_transport_error()
-    record_handler ha, hb;
-    engine_pair e(ha, hb, "disconnected");
-    e.a.connect(ha);
-    e.b.accept(hb);
-    while (!e.a.connection().active() || !e.b.connection().active())
-        e.process();
-
-    // Close a with an error condition. The AMQP connection is still open.
-    e.a.disconnected(proton::error_condition("oops", "engine failure"));
-    ASSERT(!e.a.dispatch());
-    ASSERT(!e.a.connection().closed());
-    ASSERT(e.a.connection().error().empty());
-    ASSERT_EQUAL(0u, ha.connection_errors.size());
-    ASSERT_EQUAL("oops: engine failure", e.a.transport().error().what());
-    ASSERT_EQUAL(1u, ha.transport_errors.size());
-    ASSERT_EQUAL("oops: engine failure", ha.transport_errors.front());
-
-    // In a real app the IO code would detect the abort and do this:
-    e.b.disconnected(proton::error_condition("broken", "it broke"));
-    ASSERT(!e.b.dispatch());
-    ASSERT(!e.b.connection().closed());
-    ASSERT(e.b.connection().error().empty());
-    ASSERT_EQUAL(0u, hb.connection_errors.size());
-    // Proton-C adds (connection aborted) if transport closes too early,
-    // and provides a default message if there is no user message.
-    ASSERT_EQUAL("broken: it broke (connection aborted)", e.b.transport().error().what());
-    ASSERT_EQUAL(1u, hb.transport_errors.size());
-    ASSERT_EQUAL("broken: it broke (connection aborted)", hb.transport_errors.front());
-}
-
-void test_no_container() {
-    // An engine with no container should throw, not crash.
-    connection_driver e;
-    try {
-        e.connection().container();
-        FAIL("expected error");
-    } catch (proton::error) {}
-    ASSERT(make_thread_safe<connection>(e.connection()).get());
-    ASSERT(!make_thread_safe<connection>(e.connection()).get()->event_loop());
-}
-
-}
-
-int main(int, char**) {
-    int failed = 0;
-    RUN_TEST(failed, test_engine_container_link_id());
-    RUN_TEST(failed, test_endpoint_close());
-    RUN_TEST(failed, test_engine_disconnected());
-    RUN_TEST(failed, test_no_container());
-    return failed;
-}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/include/proton_bits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_bits.hpp b/proton-c/bindings/cpp/src/include/proton_bits.hpp
index 97d4bee..53f2230 100644
--- a/proton-c/bindings/cpp/src/include/proton_bits.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_bits.hpp
@@ -124,7 +124,7 @@ template <class T>
 class factory {
 public:
     static T wrap(typename wrapped<T>::type* t) { return t; }
-    static typename wrapped<T>::type* unwrap(T t) { return t.pn_object(); }
+    static typename wrapped<T>::type* unwrap(const T& t) { return t.pn_object(); }
 };
 
 // Get attachments for various proton-c types
@@ -142,7 +142,7 @@ template <class U>
 U make_wrapper(typename internal::wrapped<U>::type* t) { return internal::factory<U>::wrap(t); }
 
 template <class T>
-typename internal::wrapped<T>::type* unwrap(T t) {return internal::factory<T>::unwrap(t); }
+typename internal::wrapped<T>::type* unwrap(const T& t) { return internal::factory<T>::unwrap(t); }
 
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/include/proton_event.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/proton_event.hpp b/proton-c/bindings/cpp/src/include/proton_event.hpp
index 00fdadf..374da85 100644
--- a/proton-c/bindings/cpp/src/include/proton_event.hpp
+++ b/proton-c/bindings/cpp/src/include/proton_event.hpp
@@ -272,12 +272,17 @@ class proton_event
     {}
 
     pn_event_t* pn_event() const { return pn_event_; }
+
+    /** Return a reference to the container, throws proton::error if there is none. */
     class container& container() const {
         if (!container_)
             throw proton::error("event does not have a container");
         return *container_;
     }
 
+    /** Return a pointer to the container if there is one, NULL otherwise. */
+    class container* container_ptr() const { return container_; }
+
     /// Get type of event
     event_type type() const { return event_type(pn_event_type(pn_event_)); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/f2df847b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/include/test_dummy_container.hpp b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
index 4af432a..daed435 100644
--- a/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
+++ b/proton-c/bindings/cpp/src/include/test_dummy_container.hpp
@@ -28,7 +28,6 @@ namespace test {
 
 using namespace proton;
 
-
 class dummy_container : public standard_container {
   public:
     dummy_container(const std::string cid="") :


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