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