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/04/04 13:34:28 UTC

[2/3] qpid-proton git commit: NO-JIRA: proactor test: verify expected behavior transport close

NO-JIRA: proactor test: verify expected behavior transport close


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

Branch: refs/heads/master
Commit: 588e2e40afa5eaf9c34df67684a9578d1de5fd82
Parents: f086571
Author: Alan Conway <ac...@redhat.com>
Authored: Fri Mar 31 11:08:49 2017 -0400
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Apr 4 09:14:55 2017 -0400

----------------------------------------------------------------------
 proton-c/src/tests/proactor.c   | 81 +++++++++++++++++++++++++++++++++++-
 proton-c/src/tests/test_tools.h | 57 ++++++++++++++++++-------
 2 files changed, 122 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/588e2e40/proton-c/src/tests/proactor.c
----------------------------------------------------------------------
diff --git a/proton-c/src/tests/proactor.c b/proton-c/src/tests/proactor.c
index be32b35..ef12a81 100644
--- a/proton-c/src/tests/proactor.c
+++ b/proton-c/src/tests/proactor.c
@@ -36,11 +36,15 @@ static const char *localhost = ""; /* host for connect/listen */
 
 typedef pn_event_type_t (*test_handler_fn)(test_t *, pn_event_t*);
 
+#define MAX_EVENT_LOG 2048         /* Max number of event types stored per proactor_test */
+
 /* Proactor and handler that take part in a test */
 typedef struct proactor_test_t {
   test_handler_fn handler;
   test_t *t;
   pn_proactor_t *proactor;
+  pn_event_type_t log[MAX_EVENT_LOG]; /* Log of event types generated by proactor */
+  size_t log_len;                     /* Number of events in the log */
 } proactor_test_t;
 
 
@@ -49,6 +53,7 @@ static void proactor_test_init(proactor_test_t *pts, size_t n, test_t *t) {
   for (proactor_test_t *pt = pts; pt < pts + n; ++pt) {
     if (!pt->t) pt->t = t;
     if (!pt->proactor) pt->proactor = pn_proactor();
+    pt->log_len = 0;
     pn_proactor_set_timeout(pt->proactor, timeout);
   }
 }
@@ -63,6 +68,25 @@ static void proactor_test_free(proactor_test_t *pts, size_t n) {
 
 #define PROACTOR_TEST_FREE(A) proactor_test_free(A, sizeof(A)/sizeof(*A))
 
+/* Clear the event logs in an array of proactors */
+static void proactor_test_clear_logs(proactor_test_t *pts, size_t n) {
+  for (proactor_test_t *pt = pts; pt < pts + n; ++pt) {
+    pt->log_len = 0;
+  }
+}
+
+#define PROACTOR_TEST_CLEAR_LOGS(A) proactor_test_clear_logs(A, sizeof(A)/sizeof(*A))
+
+#define TEST_LOG_EQUAL(T, A, PT) \
+  TEST_ETYPES_EQUAL((T), (A), sizeof(A)/sizeof(*A), (PT).log, (PT).log_len)
+
+#if 0                           /* FIXME aconway 2017-03-31:  */
+/* Return the last event in the proactor_test's log or PN_EVENT_NONE if it is empty */
+static pn_event_type_t  proactor_test_last_event(proactor_test_t *pt) {
+  return pt->log_len ? pt->log[pt->log_len - 1] : PN_EVENT_NONE;
+}
+#endif
+
 /* Set this to a pn_condition() to save condition data */
 pn_condition_t *last_condition = NULL;
 
@@ -95,6 +119,8 @@ static pn_event_type_t proactor_test_get(proactor_test_t *pts, size_t n) {
         busy = true;
         pn_event_type_t ret = PN_EVENT_NONE;
         for (pn_event_t* e = pn_event_batch_next(eb); e; e = pn_event_batch_next(eb)) {
+          TEST_ASSERT(pt->log_len < MAX_EVENT_LOG);
+          pt->log[pt->log_len++] = pn_event_type(e);
           save_condition(e);
           ret = pt->handler(pt->t, e);
           if (ret) break;
@@ -304,6 +330,57 @@ static void test_connection_wake(test_t *t) {
   pn_connection_free(c);
 }
 
+/* Close the transport to abort a connection, i.e. close the socket abruptly */
+static pn_event_type_t open_abort_handler(test_t *t, pn_event_t *e) {
+  switch (pn_event_type(e)) {
+   case PN_CONNECTION_REMOTE_OPEN:
+    /* Close the transport - abruptly closes the socket */
+    pn_transport_close(pn_connection_transport(pn_event_connection(e)));
+    return PN_EVENT_NONE;
+
+   default:
+    /* Don't auto-close the listener to keep the event sequences simple */
+    return listen_handler(t, e);
+  }
+}
+
+/* Test an aborted connection */
+static void test_abort(test_t *t) {
+  proactor_test_t pts[] ={ { open_close_handler }, { open_abort_handler } };
+  PROACTOR_TEST_INIT(pts, t);
+  pn_proactor_t *client = pts[0].proactor, *server = pts[1].proactor;
+  test_port_t port = test_port(localhost);
+  pn_listener_t *l = pn_listener();
+  pn_proactor_listen(server, l, port.host_port, 4);
+  TEST_ETYPE_EQUAL(t, PN_LISTENER_OPEN, PROACTOR_TEST_RUN(pts));
+  sock_close(port.sock);
+
+  /* Run to completion, then examine logs */
+  PROACTOR_TEST_CLEAR_LOGS(pts);
+  pn_proactor_connect(client, pn_connection(), port.host_port);
+  /* server transport closes */
+  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts));
+  if (TEST_CHECK(t, last_condition) && TEST_CHECK(t, pn_condition_is_set(last_condition))) {
+    TEST_STR_EQUAL(t, "amqp:connection:framing-error", pn_condition_get_name(last_condition));
+    TEST_STR_IN(t, "abort", pn_condition_get_description(last_condition));
+  }
+  /* client transport closes */
+  TEST_ETYPE_EQUAL(t, PN_TRANSPORT_CLOSED, PROACTOR_TEST_RUN(pts)); /* client */
+  if (TEST_CHECK(t, last_condition) && TEST_CHECK(t, pn_condition_is_set(last_condition))) {
+    TEST_STR_EQUAL(t, "amqp:connection:framing-error", pn_condition_get_name(last_condition));
+    TEST_STR_IN(t, "abort", pn_condition_get_description(last_condition));
+  }
+
+  /* Make sure there are PN_CONNECTION_CLOSE events in the shutdown sequence */
+  static const pn_event_type_t want_client[] = { PN_CONNECTION_INIT, PN_CONNECTION_LOCAL_OPEN, PN_CONNECTION_BOUND, PN_TRANSPORT_TAIL_CLOSED, PN_TRANSPORT_ERROR, PN_TRANSPORT_HEAD_CLOSED, PN_TRANSPORT_CLOSED };
+  TEST_LOG_EQUAL(t, want_client, pts[0]);
+  static const pn_event_type_t want_server[] = { PN_LISTENER_ACCEPT, PN_CONNECTION_INIT, PN_CONNECTION_BOUND, PN_CONNECTION_REMOTE_OPEN, PN_TRANSPORT_TAIL_CLOSED, PN_TRANSPORT_ERROR, PN_TRANSPORT_HEAD_CLOSED, PN_TRANSPORT_CLOSED };
+  TEST_LOG_EQUAL(t, want_server, pts[1]);
+
+  PROACTOR_TEST_FREE(pts);
+  pn_listener_free(l);
+}
+
 /* Test that INACTIVE event is generated when last connections/listeners closes. */
 static void test_inactive(test_t *t) {
   proactor_test_t pts[] =  { { open_wake_handler }, { listen_handler } };
@@ -540,6 +617,7 @@ static void test_ssl(test_t *t) {
   PROACTOR_TEST_FREE(pts);
 }
 
+
 /* Test pn_proactor_addr funtions */
 
 /* FIXME aconway 2017-03-30: windows will need winsock2.h etc.
@@ -608,7 +686,7 @@ static void test_addr(test_t *t) {
   pn_connection_free(s);
 }
 
-/* Test simple client/server connection with 2 proactors */
+/* Test pn_proactor_disconnect */
 static void test_disconnect(test_t *t) {
   proactor_test_t pts[] ={ { open_wake_handler }, { listen_handler } };
   PROACTOR_TEST_INIT(pts, t);
@@ -693,6 +771,7 @@ int main(int argc, char **argv) {
   RUN_ARGV_TEST(failed, t, test_interrupt_timeout(&t));
   RUN_ARGV_TEST(failed, t, test_errors(&t));
   RUN_ARGV_TEST(failed, t, test_client_server(&t));
+  RUN_ARGV_TEST(failed, t, test_abort(&t));
   RUN_ARGV_TEST(failed, t, test_connection_wake(&t));
   RUN_ARGV_TEST(failed, t, test_ipv4_ipv6(&t));
   RUN_ARGV_TEST(failed, t, test_free_cleanup(&t));

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/588e2e40/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 5404380..4b75cbc 100644
--- a/proton-c/src/tests/test_tools.h
+++ b/proton-c/src/tests/test_tools.h
@@ -41,7 +41,7 @@ typedef struct test_t {
    All output from test marcros goes to stderr so it interleaves with PN_TRACE logs.
 */
 
-static void test_vlogf_(test_t *t, const char *prefix, const char* expr,
+void test_vlogf_(test_t *t, const char *prefix, const char* expr,
                         const char* file, int line, const char *fmt, va_list ap)
 {
   fprintf(stderr, "%s:%d", file, line);
@@ -56,7 +56,7 @@ static void test_vlogf_(test_t *t, const char *prefix, const char* expr,
   fflush(stdout);
 }
 
-static void test_errorf_(test_t *t, const char* expr,
+void test_errorf_(test_t *t, const char* expr,
                          const char* file, int line, const char *fmt, ...) {
   ++t->errors;
   va_list ap;
@@ -65,7 +65,7 @@ static void test_errorf_(test_t *t, const char* expr,
   va_end(ap);
 }
 
-static bool test_check_(test_t *t, bool expr, const char *sexpr,
+bool test_check_(test_t *t, bool expr, const char *sexpr,
                         const char *file, int line, const char* fmt, ...) {
   if (!expr) {
     ++t->errors;
@@ -77,7 +77,7 @@ static bool test_check_(test_t *t, bool expr, const char *sexpr,
   return expr;
 }
 
-static void test_logf_(test_t *t, const char *prefix, const char* expr,
+void test_logf_(test_t *t, const char *prefix, const char* expr,
                        const char* file, int line, const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
@@ -86,7 +86,7 @@ static void test_logf_(test_t *t, const char *prefix, const char* expr,
 }
 
 /* Call via TEST_ASSERT macros */
-static void assert_fail_(const char* expr, const char* file, int line, const char *fmt, ...) {
+void assert_fail_(const char* expr, const char* file, int line, const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
   test_vlogf_(NULL, "assertion failed", expr, file, line, fmt, ap);
@@ -124,10 +124,33 @@ static void assert_fail_(const char* expr, const char* file, int line, const cha
 #define TEST_CHECK(TEST, EXPR) \
   test_check_((TEST), (EXPR), #EXPR, __FILE__, __LINE__, "")
 
-static inline bool test_etype_equal_(test_t *t, int want, int got, const char *file, int line) {
+bool test_etype_equal_(test_t *t, pn_event_type_t want, pn_event_type_t got, const char *file, int line) {
   return test_check_(t, want == got, NULL, file, line, "want %s got %s",
-                     pn_event_type_name((pn_event_type_t)want),
-                     pn_event_type_name((pn_event_type_t)got));
+                     pn_event_type_name(want),
+                     pn_event_type_name(got));
+}
+
+void print_bad_etypes(const char* prefix, const pn_event_type_t* seq, size_t len, size_t bad) {
+  fprintf(stderr, "%s", prefix);
+  for (int i = 0; i < len; ++i) {
+    fprintf(stderr, (i == bad) ? ">>>>%s" : "%s", pn_event_type_name(seq[i]));
+    if (i < len-1) fprintf(stderr, ", ");
+  }
+  if (bad > len) fprintf(stderr, " >>>>");
+  fprintf(stderr, "\n");
+}
+
+bool test_etypes_equal_(test_t *t, const pn_event_type_t* want, size_t want_len, const pn_event_type_t* got, size_t got_len, const char *file, int line) {
+  size_t len = want_len < got_len ? want_len : got_len;
+  for (int i = 0; i < len; ++i) {
+    if (want[i] != got[i]) {
+      test_errorf_(t, NULL, file, line, "event sequences don't match:");
+      print_bad_etypes("  want: ", want, want_len, i);
+      print_bad_etypes("  got:  ", got, got_len, i);
+      return false;
+    }
+  }
+  return want_len == got_len;
 }
 
 #define TEST_STR_EQUAL(TEST, WANT, GOT) \
@@ -140,7 +163,11 @@ static inline bool test_etype_equal_(test_t *t, int want, int got, const char *f
 #define TEST_ETYPE_EQUAL(TEST, WANT, GOT) \
   test_etype_equal_((TEST), (WANT), (GOT), __FILE__, __LINE__)
 
-static inline pn_event_t *test_event_type_(test_t *t, pn_event_type_t want, pn_event_t *got, const char *file, int line) {
+/* Compare arrays of pn_event_type_t */
+#define TEST_ETYPES_EQUAL(TEST, WANT, WLEN, GOT, GLEN)                       \
+  test_etypes_equal_((TEST), (WANT), (WLEN), (GOT), (GLEN), __FILE__, __LINE__)
+
+pn_event_t *test_event_type_(test_t *t, pn_event_type_t want, pn_event_t *got, const char *file, int line) {
   test_check_(t, want == pn_event_type(got), NULL, file, line, "want %s got %s",
               pn_event_type_name(want),
               pn_event_type_name(pn_event_type(got)));
@@ -192,14 +219,14 @@ static inline pn_event_t *test_event_type_(test_t *t, pn_event_type_t want, pn_e
 #include <winsock2.h>
 #include <ws2tcpip.h>
 typedef SOCKET sock_t;
-static inline void sock_close(sock_t sock) { closesocket(sock); }
+void sock_close(sock_t sock) { closesocket(sock); }
 
 #else  /* POSIX */
 
 typedef int sock_t;
 # include <netinet/in.h>
 # include <unistd.h>
-static inline void sock_close(sock_t sock) { close(sock); }
+void sock_close(sock_t sock) { close(sock); }
 #endif
 
 
@@ -208,7 +235,7 @@ static inline void sock_close(sock_t sock) { close(sock); }
    Close the returned fd when the other process is listening.
    Asserts on error.
 */
-static sock_t sock_bind0(void) {
+sock_t sock_bind0(void) {
   int sock =  socket(AF_INET, SOCK_STREAM, 0);
   TEST_ASSERT_ERRNO(sock >= 0, errno);
   int on = 1;
@@ -221,7 +248,7 @@ static sock_t sock_bind0(void) {
   return sock;
 }
 
-static int sock_port(sock_t sock) {
+int sock_port(sock_t sock) {
   struct sockaddr addr = {0};
   socklen_t len = sizeof(addr);
   TEST_ASSERT_ERRNO(getsockname(sock, &addr, &len) == 0, errno);
@@ -243,13 +270,13 @@ typedef struct test_port_t {
 } test_port_t;
 
 /* Modifies tp->host_port to use host, returns the new tp->host_port */
-static const char *test_port_use_host(test_port_t *tp, const char *host) {
+const char *test_port_use_host(test_port_t *tp, const char *host) {
   snprintf(tp->host_port, sizeof(tp->host_port), "%s:%d", host, tp->port);
   return tp->host_port;
 }
 
 /* Create a test_port_t  */
-static inline test_port_t test_port(const char* host) {
+test_port_t test_port(const char* host) {
   test_port_t tp = {0};
   tp.sock = sock_bind0();
   tp.port = sock_port(tp.sock);


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