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/09/21 15:36:36 UTC

[3/3] qpid-proton git commit: PROTON-1512: Fixes and doc clarifications for pn_delivery_aborted()

PROTON-1512: Fixes and doc clarifications for pn_delivery_aborted()

- added explict PN_ABORTED error code (PN_STATE_ERR has another meaning in this context)
- fixed initialization bug for aborted flag
- enforce discarding all data for aborted frames on sender and receiver, for interop sanity
- clarified docs - see below

Goal is to enable *correct* use of abort while minimizing interop problems with existing
abort-unaware proton code (and other AMQP clients)

The only correct use of abort is when part of a message has already been
sent. In a router, an incoming message can be aborted before any of it has been
forwarded, or even before enough headers have been acquired to know how to
forward it. Such messages should simply not be forwarded at all. Dispatch
doesn't (shouldn't) promise frame-by-frame identity for message routing so
silently dropping an early-aborted message is entirely valid and
unavoidable. Using abort is only valid when part of a message has already been
forwarded.

Here's the explanation of the backwards-compatibility problem:

/**
 * Check if a received delivery has been aborted.
 *
 * An aborted delivery means the sender cannot complete the message and the
 * receiver should discard any data already received. There is nothing further
 * to be done with the delivery: it is pn_delivery_settled() and pn_link_recv()
 * returns ::PN_ABORTED.
 *
 * For backward compatibility with code that does not check pn_delivery_aborted(),
 * the following are true of an aborted delivery:
 *
 * - pn_delivery_partial() is false - old code will not wait forever for more data
 *
 * - pn_delivery_pending() returns 1, not 0 - old code that checks for completion with
 *
 *       if (pn_delivery_pending(d)==0 && !pn_delivery_partial(d))
 *
 *   will not mistake this for successful completion, and will call pn_link_recv()
 *
 * - pn_link_recv() returns ::PN_ABORTED - old code will know there is some kind of error.
 *
 * @see pn_delivery_abort()
 * @param[in] delivery a delivery object
 * @return true if the delivery has been aborted, false otherwise
 */
PN_EXTERN bool pn_delivery_aborted(pn_delivery_t *delivery);


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

Branch: refs/heads/master
Commit: 6743ab4418736dab353b8566dae7d94fd2e34f2b
Parents: d341350
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Sep 21 10:29:47 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Thu Sep 21 11:28:10 2017 -0400

----------------------------------------------------------------------
 proton-c/include/proton/delivery.h     |  39 +++++++----
 proton-c/include/proton/error.h        |  13 ++--
 proton-c/include/proton/link.h         |   5 +-
 proton-c/src/core/engine.c             |  17 +++--
 proton-c/src/core/error.c              |   1 +
 proton-c/src/tests/connection_driver.c | 105 ++++++++++++++--------------
 proton-c/src/tests/proactor.c          |   2 +-
 proton-c/src/tests/test_handler.h      |  10 ++-
 proton-c/src/tests/test_tools.h        |  16 +++--
 9 files changed, 120 insertions(+), 88 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/include/proton/delivery.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/delivery.h b/proton-c/include/proton/delivery.h
index bab7c5c..6cdd854 100644
--- a/proton-c/include/proton/delivery.h
+++ b/proton-c/include/proton/delivery.h
@@ -174,8 +174,8 @@ PN_EXTERN size_t pn_delivery_pending(pn_delivery_t *delivery);
 /**
  * Check if a delivery only has partial message data.
  *
- * Note a partial message may be pn_delivery_aborted() which means the message
- * is incomplete but the rest of the message will never be delivered.
+ * The receiver can expect more ::PN_DELIVERY events for this delivery containing
+ * the remainder of this message.
  *
  * @param[in] delivery a delivery object
  * @return true if the delivery only contains part of a message, false otherwise
@@ -183,14 +183,25 @@ PN_EXTERN size_t pn_delivery_pending(pn_delivery_t *delivery);
 PN_EXTERN bool pn_delivery_partial(pn_delivery_t *delivery);
 
 /**
- * On the receiving side, check if the delivery has been aborted.
+ * Check if a received delivery has been aborted.
  *
- * Aborting a delivery means the sender cannot complete the message. It  will not
- * send any more data and the data received so far should be discarded by the receiver.
- * An aborted deliver is settled by the sender.
+ * An aborted delivery means the sender cannot complete the message and the
+ * receiver should discard any data already received. There is nothing further
+ * to be done with the delivery: it is pn_delivery_settled() and pn_link_recv()
+ * returns ::PN_ABORTED.
  *
- * Calling pn_link_recv() when the current delivery on the link is aborted will
- * return a PN_STATE error code.
+ * For backward compatibility with code that does not check pn_delivery_aborted(),
+ * the following are true of an aborted delivery:
+ *
+ * - pn_delivery_partial() is false - old code will not wait forever for more data
+ *
+ * - pn_delivery_pending() returns 1, not 0 - old code that checks for completion with
+ *
+ *       if (pn_delivery_pending(d)==0 && !pn_delivery_partial(d))
+ *
+ *   will not mistake this for successful completion, and will call pn_link_recv()
+ *
+ * - pn_link_recv() returns ::PN_ABORTED - old code will know there is some kind of error.
  *
  * @see pn_delivery_abort()
  * @param[in] delivery a delivery object
@@ -261,12 +272,16 @@ PN_EXTERN void pn_delivery_clear(pn_delivery_t *delivery);
 PN_EXTERN bool pn_delivery_current(pn_delivery_t *delivery);
 
 /**
- * On the sending side, abort a delivery.
+ * Abort a delivery being sent.
+ *
+ * Aborting means the sender cannot complete the delivery. It will not send any
+ * more data and all data received so far should be discarded by the receiver.
  *
- * Aborting a delivery means the sender cannot complete the message. It  will not
- * send any more data and the data received so far should be discarded by the receiver.
+ * The aborted delivery is automatically settled, and can never be used again.
  *
- * The aborted messages is also settled, and can never be used again.
+ * @note You should only use pn_delivery_abort() if you are "streaming" messages
+ * in multiple parts and you need to abort after part of the message has been sent
+ * with pn_link_send()
  *
  * @see pn_delivery_aborted()
  *

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/include/proton/error.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/error.h b/proton-c/include/proton/error.h
index c115ee1..5bb603a 100644
--- a/proton-c/include/proton/error.h
+++ b/proton-c/include/proton/error.h
@@ -53,7 +53,8 @@ typedef struct pn_error_t pn_error_t;
 #define PN_TIMEOUT (-7)        /**< Timeout */
 #define PN_INTR (-8)           /**< Interrupt */
 #define PN_INPROGRESS (-9)     /**< In-progress */
-#define PN_OUT_OF_MEMORY (-10) /**< Out-of-momory error */
+#define PN_OUT_OF_MEMORY (-10) /**< Out-of-memory error */
+#define PN_ABORTED (-11)       /**< Delivery aborted error */
 
 /**
  * Get the name of the error code. Returned pointer is to a static
@@ -63,9 +64,9 @@ PN_EXTERN const char *pn_code(int code);
 
 /**
  * Create an error object.
- */    
+ */
 PN_EXTERN pn_error_t *pn_error(void);
-    
+
 /**
  * Free an error object.
  */
@@ -106,12 +107,12 @@ PN_EXTERN const char *pn_error_text(pn_error_t *error);
 
 /**
  * Copy the src error.
- */    
+ */
 PN_EXTERN int pn_error_copy(pn_error_t *error, pn_error_t *src);
 
 /**
  * @cond INTERNAL
- */    
+ */
 #define PN_RETURN_IF_ERROR(x) \
 do {\
 int r = (x);\
@@ -120,7 +121,7 @@ if (r < 0) return r; \
 /**
  * @endcond
  */
-    
+
 /**
  * @}
  */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/include/proton/link.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/link.h b/proton-c/include/proton/link.h
index 864f8e0..bf5cddc 100644
--- a/proton-c/include/proton/link.h
+++ b/proton-c/include/proton/link.h
@@ -630,7 +630,10 @@ PN_EXTERN void pn_link_set_drain(pn_link_t *receiver, bool drain);
  * @param[in] receiver a receiving link object
  * @param[in] bytes a pointer to an empty buffer
  * @param[in] n the buffer capacity
- * @return the number of bytes received, PN_EOS, or an error code
+ * @return The number of bytes received, or an error code:
+ *   - ::PN_EOS: The message has been completely received
+ *   - ::PN_STATE_ERR: The link has no current delivery
+ *   - ::PN_ABORTED: See pn_delivery_aborted()
  */
 PN_EXTERN ssize_t pn_link_recv(pn_link_t *receiver, char *bytes, size_t n);
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/src/core/engine.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/engine.c b/proton-c/src/core/engine.c
index 0863caa..b8dacad 100644
--- a/proton-c/src/core/engine.c
+++ b/proton-c/src/core/engine.c
@@ -1555,6 +1555,7 @@ pn_delivery_t *pn_delivery(pn_link_t *link, pn_delivery_tag_t tag)
   delivery->tpwork = false;
   pn_buffer_clear(delivery->bytes);
   delivery->done = false;
+  delivery->aborted = false;
   pn_record_clear(delivery->context);
 
   // begin delivery state
@@ -1917,7 +1918,7 @@ ssize_t pn_link_recv(pn_link_t *receiver, char *bytes, size_t n)
       return delivery->done ? PN_EOS : 0;
     }
   } else {
-    return PN_STATE_ERR;
+    return delivery ? PN_ABORTED : PN_STATE_ERR;
   }
 }
 
@@ -2046,6 +2047,11 @@ bool pn_delivery_readable(pn_delivery_t *delivery)
 
 size_t pn_delivery_pending(pn_delivery_t *delivery)
 {
+  /* Aborted deliveries: for old clients that don't check pn_delivery_aborted(),
+     return 1 rather than 0. This will force them to call pn_link_recv() and get
+     the PN_ABORTED error return code.
+  */
+  if (delivery->aborted) return 1;
   return pn_buffer_size(delivery->bytes);
 }
 
@@ -2055,10 +2061,11 @@ bool pn_delivery_partial(pn_delivery_t *delivery)
 }
 
 void pn_delivery_abort(pn_delivery_t *delivery) {
-  if (!delivery->aborted) {
-    delivery->aborted = true;
-    pn_delivery_settle(delivery);
-  }
+  delivery->aborted = true;
+  /* Discard any data, aborted frames are always empty */
+  delivery->link->session->outgoing_bytes -= pn_buffer_size(delivery->bytes);
+  pn_buffer_clear(delivery->bytes);
+  pn_delivery_settle(delivery);
 }
 
 bool pn_delivery_aborted(pn_delivery_t *delivery) {

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/src/core/error.c
----------------------------------------------------------------------
diff --git a/proton-c/src/core/error.c b/proton-c/src/core/error.c
index e8e941f..070144a 100644
--- a/proton-c/src/core/error.c
+++ b/proton-c/src/core/error.c
@@ -132,6 +132,7 @@ const char *pn_code(int code)
   case PN_INTR: return "PN_INTR";
   case PN_INPROGRESS: return "PN_INPROGRESS";
   case PN_OUT_OF_MEMORY: return "PN_OUT_OF_MEMORY";
+  case PN_ABORTED: return "PN_ABORTED";
   default: return "<unknown>";
   }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/src/tests/connection_driver.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/connection_driver.c b/proton-c/src/tests/connection_driver.c
index 166ca06..b16efba 100644
--- a/proton-c/src/tests/connection_driver.c
+++ b/proton-c/src/tests/connection_driver.c
@@ -114,7 +114,7 @@ static void test_message_transfer(test_t *t) {
   ssize_t size = message_encode(m, &buf);
   pn_message_free(m);
   pn_delivery(snd, pn_dtag("x", 1));
-  TEST_CHECK(t, size == pn_link_send(snd, buf.start, size));
+  TEST_INT_EQUAL(t, size, pn_link_send(snd, buf.start, size));
   TEST_CHECK(t, pn_link_advance(snd));
   test_connection_drivers_run(&client, &server);
   TEST_HANDLER_EXPECT(&server.handler, PN_TRANSPORT, PN_DELIVERY, 0);
@@ -148,8 +148,8 @@ pn_event_type_t send_client_handler(test_handler_t *th, pn_event_t *e) {
     pn_session_open(ssn);
     pn_link_t *snd = pn_sender(ssn, "x");
     pn_link_open(snd);
-   }
     break;
+   }
    case PN_LINK_REMOTE_OPEN: {
     struct context *ctx = (struct context*) th->context;
     if (ctx) ctx->link = pn_event_link(e);
@@ -176,10 +176,8 @@ static void test_message_stream(test_t *t) {
   pn_link_t *snd = client_ctx.link;
   pn_link_flow(rcv, 1);
   test_connection_drivers_run(&client, &server);
-  test_handler_keep(&client.handler, 1);
-  TEST_HANDLER_EXPECT(&client.handler, PN_LINK_FLOW, 0);
-  test_handler_keep(&server.handler, 1);
-  TEST_HANDLER_EXPECT(&server.handler, PN_TRANSPORT, 0);
+  TEST_HANDLER_EXPECT_LAST(&client.handler, PN_LINK_FLOW);
+  TEST_HANDLER_EXPECT_LAST(&server.handler, PN_TRANSPORT);
 
   /* Encode a large (not very) message to send in chunks */
   pn_message_t *m = pn_message();
@@ -197,8 +195,8 @@ static void test_message_stream(test_t *t) {
     /* Send a chunk */
     ssize_t c = (i+CHUNK < size) ? CHUNK : size - i;
     TEST_CHECK(t, c == pn_link_send(snd, buf.start + i, c));
-    TEST_CHECK(t, &server == test_connection_drivers_run(&client, &server));
-    TEST_HANDLER_EXPECT(&server.handler, PN_DELIVERY, 0);
+    test_connection_drivers_run(&client, &server);
+    TEST_HANDLER_EXPECT_LAST(&server.handler, PN_DELIVERY);
     /* Receive a chunk */
     pn_delivery_t *dlv = server_ctx.delivery;
     pn_link_t *l = pn_delivery_link(dlv);
@@ -218,7 +216,7 @@ static void test_message_stream(test_t *t) {
   test_connection_driver_destroy(&server);
 }
 
-// Test aborting a message mid stream.
+// Test aborting a delivery
 static void test_message_abort(test_t *t) {
   /* Set up the link, give credit, start the delivery */
   test_connection_driver_t client, server;
@@ -231,55 +229,54 @@ static void test_message_abort(test_t *t) {
   test_connection_drivers_run(&client, &server);
   pn_link_t *rcv = server_ctx.link;
   pn_link_t *snd = client_ctx.link;
+  char data[100] = {0};          /* Dummy data to send. */
+  char rbuf[sizeof(data)] = {0}; /* Read buffer for incoming data. */
+
+  /* Send 2 frames with data */
   pn_link_flow(rcv, 1);
   test_connection_drivers_run(&client, &server);
-
-  /* Encode a large (not very) message to send in chunks, and abort */
-  pn_message_t *m = pn_message();
-  char body[1024] = { 0 };
-  pn_data_put_binary(pn_message_body(m), pn_bytes(sizeof(body), body));
-  pn_rwbytes_t buf = { 0 };
-  ssize_t size = message_encode(m, &buf);
-
-  /* Send 3 chunks, then abort */
-  static const ssize_t CHUNK = 100;
-  pn_delivery(snd, pn_dtag("x", 1));
-  pn_rwbytes_t buf2 = { 0 };
-  ssize_t received = 0;
-  for (ssize_t i = 0; i < CHUNK*3; i += CHUNK) {
-    /* Send a chunk */
-    ssize_t c = (i+CHUNK < size) ? CHUNK : size - i;
-    TEST_CHECK(t, c == pn_link_send(snd, buf.start + i, c));
-    TEST_CHECK(t, &server == test_connection_drivers_run(&client, &server));
-    test_handler_keep(&server.handler, 1);
-    TEST_HANDLER_EXPECT(&server.handler, PN_DELIVERY, 0);
-    /* Receive a chunk */
-    pn_delivery_t *dlv = server_ctx.delivery;
-    pn_link_t *l = pn_delivery_link(dlv);
-    ssize_t dsize = pn_delivery_pending(dlv);
-    rwbytes_ensure(&buf2, received+dsize);
-    TEST_ASSERT(dsize == pn_link_recv(l, buf2.start + received, dsize));
-    received += dsize;
+  pn_delivery_t *sd = pn_delivery(snd, pn_dtag("1", 1)); /* Sender delivery */
+  for (size_t i = 0; i < 2; ++i) {
+    TEST_INT_EQUAL(t, sizeof(data), pn_link_send(snd, data, sizeof(data)));
+    test_connection_drivers_run(&client, &server);
+    TEST_HANDLER_EXPECT_LAST(&server.handler, PN_DELIVERY);
+    pn_delivery_t *rd = server_ctx.delivery;
+    TEST_CHECK(t, !pn_delivery_aborted(rd));
+    TEST_CHECK(t, pn_delivery_partial(rd));
+    TEST_INT_EQUAL(t, sizeof(data), pn_delivery_pending(rd));
+    TEST_INT_EQUAL(t, sizeof(rbuf), pn_link_recv(pn_delivery_link(rd), rbuf, sizeof(rbuf)));
+    TEST_INT_EQUAL(t, 0, pn_link_recv(pn_delivery_link(rd), rbuf, sizeof(rbuf)));
   }
-  /* Now abort the message on the sender*/
-  pn_delivery_t *d = pn_link_current(snd);
-  pn_delivery_abort(d);
-  TEST_CHECK(t, pn_link_current(snd) != d);
-  TEST_CHECK(t, &server == test_connection_drivers_run(&client, &server));
-  TEST_HANDLER_EXPECT(&server.handler, PN_DELIVERY, 0);
-  /* And verify we see it aborted on the receiver */
-  d = pn_link_current(rcv);
-  TEST_CHECK(t, pn_delivery_aborted(d));
-  /* Aborted implies settled, !partial, pending == 0, pn_link_recv returns error */
-  TEST_CHECK(t, pn_delivery_settled(d));
-  TEST_CHECK(t, !pn_delivery_partial(d));
-  TEST_INT_EQUAL(t, 0, pn_delivery_pending(d));
-  char b[16];
-  TEST_INT_EQUAL(t, PN_STATE_ERR, pn_link_recv(rcv, b, sizeof(b)));
+  /* Abort the delivery */
+  pn_delivery_abort(sd);
+  TEST_CHECK(t, pn_link_current(snd) != sd); /* Settled */
+  test_connection_drivers_run(&client, &server);
+  TEST_HANDLER_EXPECT_LAST(&server.handler, PN_DELIVERY);
+  /* Receive the aborted frame, should be empty */
+  pn_delivery_t *rd = server_ctx.delivery;
+  TEST_CHECK(t, pn_delivery_aborted(rd));
+  TEST_CHECK(t, !pn_delivery_partial(rd)); /* Aborted deliveries are never partial */
+  TEST_CHECK(t, pn_delivery_settled(rd)); /* Aborted deliveries are always settled */
+  TEST_INT_EQUAL(t, 1, pn_delivery_pending(rd));
+  TEST_INT_EQUAL(t, PN_ABORTED, pn_link_recv(pn_delivery_link(rd), rbuf, sizeof(rbuf)));
+
+  /* Send a single aborted frame, with data. */
+  pn_link_flow(rcv, 1);
+  test_connection_drivers_run(&client, &server);
+  sd = pn_delivery(snd, pn_dtag("x", 1));
+  TEST_INT_EQUAL(t, sizeof(data), pn_link_send(snd, data, sizeof(data)));
+  pn_delivery_abort(sd);                     /* Abort after send creates an aborted frame with data */
+  TEST_CHECK(t, pn_link_current(snd) != sd); /* Settled */
+  test_connection_drivers_run(&client, &server);
+  TEST_HANDLER_EXPECT_LAST(&server.handler, PN_DELIVERY);
+  /* Receive the aborted frame */
+  rd = server_ctx.delivery;
+  TEST_CHECK(t, pn_delivery_aborted(rd));
+  TEST_CHECK(t, !pn_delivery_partial(rd)); /* Aborted deliveries are never partial */
+  TEST_CHECK(t, pn_delivery_settled(rd)); /* Aborted deliveries are always settled */
+  TEST_INT_EQUAL(t, 1, pn_delivery_pending(rd)); /* Has no data */
+  TEST_INT_EQUAL(t, PN_ABORTED, pn_link_recv(pn_delivery_link(rd), rbuf, sizeof(rbuf)));
 
-  pn_message_free(m);
-  free(buf.start);
-  free(buf2.start);
   test_connection_driver_destroy(&client);
   test_connection_driver_destroy(&server);
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index f22452e..3995c1d 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -632,7 +632,7 @@ static void test_proton_1586(test_t *t) {
   pn_proactor_connect(tps[0].proactor, pn_connection(), ":yyy");
   TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, TEST_PROACTORS_RUN(tps));
   TEST_COND_DESC(t, ":yyy", last_condition);
-  test_handler_keep(&tps[0].handler, 0); /* Clear events */
+  test_handler_clear(&tps[0].handler, 0); /* Clear events */
   /* There should be no events generated after PN_TRANSPORT_CLOSED */
   TEST_ETYPE_EQUAL(t, PN_PROACTOR_INACTIVE, TEST_PROACTORS_RUN(tps));
   TEST_HANDLER_EXPECT(&tps[0].handler,PN_PROACTOR_INACTIVE, 0);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/src/tests/test_handler.h
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/test_handler.h b/proton-c/src/tests/test_handler.h
index 420e910..65fcfe7 100644
--- a/proton-c/src/tests/test_handler.h
+++ b/proton-c/src/tests/test_handler.h
@@ -53,7 +53,7 @@ void test_handler_log(test_handler_t *th, pn_event_t *e) {
 }
 
 /* Keep at most n events in the handler's log, remove old events if necessary */
-void test_handler_keep(test_handler_t *th, size_t n) {
+void test_handler_clear(test_handler_t *th, size_t n) {
   if (n == 0) {
     th->log_size = 0;
   } else if (n < th->log_size) {
@@ -92,7 +92,13 @@ void test_etypes_expect_(test_t *t, pn_event_type_t *etypes, size_t size, const
 
 #define TEST_HANDLER_EXPECT(TH, ...) do {                               \
     test_etypes_expect_((TH)->t, (TH)->log, (TH)->log_size, __FILE__, __LINE__, __VA_ARGS__); \
-    test_handler_keep((TH), 0);                                         \
+    test_handler_clear((TH), 0);                                         \
+  } while(0)
+
+#define TEST_HANDLER_EXPECT_LAST(TH, ETYPE) do {                        \
+    test_handler_clear((TH), 1);                                        \
+    test_etypes_expect_((TH)->t, (TH)->log, (TH)->log_size, __FILE__, __LINE__, ETYPE, 0); \
+    test_handler_clear((TH), 0);                                         \
   } while(0)
 
 /* A pn_connection_driver_t with a test_handler */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/6743ab44/proton-c/src/tests/test_tools.h
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/test_tools.h b/proton-c/src/tests/test_tools.h
index 6b2f91f..58d3ce0 100644
--- a/proton-c/src/tests/test_tools.h
+++ b/proton-c/src/tests/test_tools.h
@@ -138,19 +138,21 @@ bool test_etype_equal_(test_t *t, pn_event_type_t want, pn_event_type_t got, con
                      pn_event_type_name(want),
                      pn_event_type_name(got));
 }
+#define TEST_ETYPE_EQUAL(TEST, WANT, GOT) test_etype_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
 
-#define TEST_INT_EQUAL(TEST, WANT, GOT)                                 \
-  test_check_((TEST), (int)(WANT) == (int)(GOT), NULL, __FILE__, __LINE__, "want %d, got %d", (int)(WANT), (int)(GOT))
+bool test_int_equal_(test_t *t, int want, int got, const char *file, int line) {
+  return test_check_(t, want == got, NULL, file, line, "want %d, got %d", want, got);
+}
+#define TEST_INT_EQUAL(TEST, WANT, GOT) test_int_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
 
-#define TEST_STR_EQUAL(TEST, WANT, GOT)                                 \
-  test_check_((TEST), !strcmp((WANT), (GOT)), NULL, __FILE__, __LINE__, "want '%s', got '%s'", (WANT), (GOT))
+bool test_str_equal_(test_t *t, const char* want, const char* got, const char *file, int line) {
+  return test_check_(t, !strcmp(want, got), NULL, file, line, "want '%s', got '%s'", want, got);
+}
+#define TEST_STR_EQUAL(TEST, WANT, GOT) test_str_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
 
 #define TEST_STR_IN(TEST, WANT, GOT)                                    \
   test_check_((TEST), strstr((GOT), (WANT)), NULL, __FILE__, __LINE__, "'%s' not in '%s'", (WANT), (GOT))
 
-#define TEST_ETYPE_EQUAL(TEST, WANT, GOT)                       \
-  test_etype_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
-
 #define TEST_COND_EMPTY(TEST, C)                                        \
   TEST_CHECKNF((TEST), (!(C) || !pn_condition_is_set(C)), "Unexpected condition - %s:%s", \
               pn_condition_get_name(C), pn_condition_get_description(C))


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