On FreeBSD some of the test-vconn.c tests failed intermittently due
to timing variations in a TCP localhost connection.

- If we receive EAGAIN for certain functions, retry.

- Allow EPIPE in addition to ECONNRESET in some cases.  A write() to a
socket where the other side has closed returns EPIPE on FreeBSD and
ECONNRESET on Linux.

Signed-off-by: Ed Maste <ema...@freebsd.org>
---
 tests/test-vconn.c |   65 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 58 insertions(+), 7 deletions(-)

diff --git a/tests/test-vconn.c b/tests/test-vconn.c
index f37bc38..fa244ef 100644
--- a/tests/test-vconn.c
+++ b/tests/test-vconn.c
@@ -67,6 +67,50 @@ check_errno(int a, int b, const char *as, const char *file, 
int line)
 
 #define CHECK_ERRNO(A, B) check_errno(A, B, #A, __FILE__, __LINE__)
 
+/* Fail if the value in a is not one of the permissible ones in the INT_MAX
+ * terminated list b.
+ */
+static void
+check_errno_list(int a, int *b, const char *as, const char *file, int line)
+{
+    int cnt = 0;
+
+    /* Fall back to check_errno for the single element case so that we produce
+     * the same error message.
+     */
+    if (b[0] != INT_MAX && b[1] == INT_MAX) {
+        check_errno(a, b[0], as, file, line);
+        return;
+    }
+    while (b[cnt] != INT_MAX) {
+        if (a == b[cnt]) {
+            return;
+        }
+        cnt++;
+    }
+    ovs_fatal(0, "%s:%d: %s is %d (%s) which is not one of %d permissible",
+              file, line, as, a, strerror(abs(a)), cnt);
+}
+
+#define CHECK_ERRNO_RETRY_FN(A, B, CHECK_FN) do {                       \
+    int count = 0;                                                      \
+    int retval;                                                         \
+    do {                                                                \
+        retval = A;                                                     \
+    } while (retval == EAGAIN && count++ < 10000);                      \
+    CHECK_FN(retval, B, #A, __FILE__, __LINE__);                        \
+} while (0)
+
+/* Retry function A on EAGAIN.  Final return value must be that given by B.
+ */
+#define CHECK_ERRNO_RETRY(A, B) CHECK_ERRNO_RETRY_FN(A, B, check_errno)
+
+/* Retry function A on EAGAIN.  Final return value must be in the list given
+ * by B.
+ */
+#define CHECK_ERRNO_RETRY_LIST(A, B) \
+    CHECK_ERRNO_RETRY_FN(A, B, check_errno_list)
+
 static void
 fpv_create(const char *type, struct fake_pvconn *fpv)
 {
@@ -137,26 +181,33 @@ fpv_destroy(struct fake_pvconn *fpv)
     free(fpv->vconn_name);
 }
 
+/* Permissible return values for a write to a socket with the other side
+ * closed */
+static int expected_error_tcp_closed[] = {ECONNRESET, EPIPE, INT_MAX};
+
 /* Connects to a fake_pvconn with vconn_open(), then closes the listener and
  * verifies that vconn_connect() reports 'expected_error'. */
 static void
 test_refuse_connection(int argc OVS_UNUSED, char *argv[])
 {
     const char *type = argv[1];
-    int expected_error;
+    int *expected_error;
     struct fake_pvconn fpv;
     struct vconn *vconn;
+    int expected_error_unix[] = {EPIPE, INT_MAX};
+    int expected_error_other[] = {EPROTO, INT_MAX};
 
-    expected_error = (!strcmp(type, "unix") ? EPIPE
-                      : !strcmp(type, "tcp") ? ECONNRESET
-                      : EPROTO);
+    expected_error = (!strcmp(type, "unix") ? expected_error_unix
+                      : !strcmp(type, "tcp") ? expected_error_tcp_closed
+                      : expected_error_other);
 
     fpv_create(type, &fpv);
     CHECK_ERRNO(vconn_open(fpv.vconn_name, OFP10_VERSION, &vconn,
                            DSCP_DEFAULT), 0);
     fpv_close(&fpv);
     vconn_run(vconn);
-    CHECK_ERRNO(vconn_connect(vconn), expected_error);
+    CHECK_ERRNO_RETRY_LIST(vconn_connect(vconn), expected_error);
     vconn_close(vconn);
     fpv_destroy(&fpv);
 }
@@ -229,7 +280,7 @@ test_read_hello(int argc OVS_UNUSED, char *argv[])
        poll_block();
     }
     stream_close(stream);
-    CHECK_ERRNO(vconn_connect(vconn), ECONNRESET);
+    CHECK_ERRNO_RETRY_LIST(vconn_connect(vconn), expected_error_tcp_closed);
     vconn_close(vconn);
 }
 
@@ -322,7 +373,7 @@ test_send_hello(const char *type, const void *out, size_t 
out_size,
        poll_block();
     }
     stream_close(stream);
-    CHECK_ERRNO(vconn_recv(vconn, &msg), EOF);
+    CHECK_ERRNO_RETRY(vconn_recv(vconn, &msg), EOF);
     vconn_close(vconn);
 }
 
-- 
1.7.10.3

To: 
Cc: 
Bcc: 
Subject: 
Reply-To: 

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to