test: Skip TCP tests if getaddrinfo doesn't work
authorSimon McVittie <smcv@collabora.com>
Mon, 4 Jun 2018 15:27:50 +0000 (16:27 +0100)
committerSimon McVittie <smcv@collabora.com>
Mon, 4 Jun 2018 16:56:31 +0000 (17:56 +0100)
For example, this can be the case in bubblewrap or Debian pbuilder after
unsharing the network namespace:

    bwrap \
    --bind / / \
    --dev-bind /dev /dev \
    --bind /dev/shm /dev/shm \
    --bind /dev/pts /dev/pts \
    --unshare-net \
    ${builddir}/test/test-loopback --tap
    ...
    ok 1 /connect/tcp # SKIP Name resolution does not work here:
    getaddrinfo("127.0.0.1", "0", {flags=ADDRCONFIG, family=INET,
    socktype=STREAM, protocol=TCP}): Name or service not known

On some systems this can be circumvented by using nss_wrapper from
<https://cwrap.org/nss_wrapper.html>:

    cat > hosts <<EOF
    127.0.0.1 localhost
    EOF
    bwrap \
    ... \
    env \
    LD_PRELOAD=libnss_wrapper.so \
    NSS_WRAPPER_HOSTS=$(pwd)/hosts \
    ${builddir}/test/test-loopback --tap
    ...
    # listening at tcp:host=127.0.0.1,port=39219,family=ipv4,guid=...

but for systems where that does't work, we should be prepared to skip
the affected tests.

Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall <withnall@endlessm.com>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=106812
(cherry picked from commit f1faafd59bec67d347edb10447c4b9b18193458c)

test/corrupt.c
test/fdpass.c
test/internals/server-oom.c
test/loopback.c
test/relay.c
test/test-utils-glib.c
test/test-utils-glib.h

index a2fad64..a6a912f 100644 (file)
@@ -36,6 +36,7 @@
 typedef struct {
     DBusError e;
     TestMainContext *ctx;
+    gboolean skip;
 
     DBusServer *server;
     DBusConnection *server_conn;
@@ -85,6 +86,14 @@ setup (Fixture *f,
   dbus_error_init (&f->e);
   g_queue_init (&f->client_messages);
 
+  if ((g_str_has_prefix (addr, "tcp:") ||
+       g_str_has_prefix (addr, "nonce-tcp:")) &&
+      !test_check_tcp_works ())
+    {
+      f->skip = TRUE;
+      return;
+    }
+
   f->server = dbus_server_listen (addr, &f->e);
   assert_no_error (&f->e);
   g_assert (f->server != NULL);
@@ -101,6 +110,9 @@ test_connect (Fixture *f,
   dbus_bool_t have_mem;
   char *address = NULL;
 
+  if (f->skip)
+    return;
+
   g_assert (f->server_conn == NULL);
 
   address = dbus_server_get_address (f->server);
@@ -129,6 +141,9 @@ test_message (Fixture *f,
   dbus_uint32_t serial;
   DBusMessage *outgoing, *incoming;
 
+  if (f->skip)
+    return;
+
   test_connect (f, addr);
 
   outgoing = dbus_message_new_signal ("/com/example/Hello",
@@ -213,6 +228,9 @@ test_corrupt (Fixture *f,
   int fd;
   DBusMessage *incoming;
 
+  if (f->skip)
+    return;
+
   test_message (f, addr);
 
   dbus_connection_flush (f->server_conn);
@@ -277,6 +295,9 @@ test_byte_order (Fixture *f,
   DBusMessage *message;
   dbus_bool_t mem;
 
+  if (f->skip)
+    return;
+
   test_message (f, addr);
 
   message = dbus_message_new_signal ("/", "a.b", "c");
index 0ea7518..4a3edc4 100644 (file)
@@ -79,6 +79,7 @@ _DBUS_STATIC_ASSERT (MAX_MESSAGE_UNIX_FDS < TOO_MANY_FDS);
 typedef struct {
     TestMainContext *ctx;
     DBusError e;
+    gboolean skip;
 
     DBusServer *server;
 
@@ -172,6 +173,9 @@ test_connect (Fixture *f,
 {
   char *address;
 
+  if (f->skip)
+    return;
+
   g_assert (f->left_server_conn == NULL);
   g_assert (f->right_server_conn == NULL);
 
@@ -251,6 +255,14 @@ setup_common (Fixture *f,
   dbus_error_init (&f->e);
   g_queue_init (&f->messages);
 
+  if ((g_str_has_prefix (address, "tcp:") ||
+       g_str_has_prefix (address, "nonce-tcp:")) &&
+      !test_check_tcp_works ())
+    {
+      f->skip = TRUE;
+      return;
+    }
+
   f->server = dbus_server_listen (address, &f->e);
   assert_no_error (&f->e);
   g_assert (f->server != NULL);
@@ -289,6 +301,9 @@ static void
 test_unsupported (Fixture *f,
     gconstpointer data)
 {
+  if (f->skip)
+    return;
+
   test_connect (f, FALSE);
 
   if (dbus_connection_can_send_type (f->left_client_conn,
@@ -321,6 +336,9 @@ test_relay (Fixture *f,
   struct stat stat_before;
   struct stat stat_after;
 
+  if (f->skip)
+    return;
+
   test_connect (f, TRUE);
 
   outgoing = dbus_message_new_signal ("/com/example/Hello",
@@ -403,6 +421,9 @@ test_limit (Fixture *f,
   DBusMessage *outgoing, *incoming;
   int i;
 
+  if (f->skip)
+    return;
+
   test_connect (f, TRUE);
 
   outgoing = dbus_message_new_signal ("/com/example/Hello",
@@ -461,6 +482,9 @@ test_too_many (Fixture *f,
   DBusMessage *outgoing;
   unsigned int i;
 
+  if (f->skip)
+    return;
+
   test_connect (f, TRUE);
 
   outgoing = dbus_message_new_signal ("/com/example/Hello",
@@ -513,6 +537,12 @@ test_too_many_split (Fixture *f,
   DBusString buffer;
   int fds[TOO_MANY_FDS];
   int done;
+#ifdef HAVE_GETRLIMIT
+  struct rlimit lim;
+#endif
+
+  if (f->skip)
+    return;
 
   /* This test deliberately pushes up against OS limits, so skip it
    * if we don't have enough fds. 4 times the maximum per message
@@ -520,8 +550,6 @@ test_too_many_split (Fixture *f,
    * we actually send, the copy that we potentially receive, and some
    * spare capacity for everything else. */
 #ifdef HAVE_GETRLIMIT
-  struct rlimit lim;
-
   if (getrlimit (RLIMIT_NOFILE, &lim) == 0)
     {
       if (lim.rlim_cur != RLIM_INFINITY &&
@@ -643,6 +671,9 @@ test_flood (Fixture *f,
   DBusMessage *outgoing[SOME_MESSAGES];
   dbus_uint32_t serial;
 
+  if (f->skip)
+    return;
+
   test_connect (f, TRUE);
 
   for (j = 0; j < SOME_MESSAGES; j++)
@@ -715,6 +746,9 @@ test_odd_limit (Fixture *f,
   DBusMessage *outgoing;
   int i;
 
+  if (f->skip)
+    return;
+
   test_connect (f, TRUE);
   dbus_connection_set_max_message_unix_fds (f->left_server_conn, 7);
   dbus_connection_set_max_message_unix_fds (f->right_server_conn, 7);
index 9aeadd3..4c3ab05 100644 (file)
@@ -84,6 +84,11 @@ test_oom_wrapper (gconstpointer data)
 {
   const OOMTestCase *test = data;
 
+  if ((g_str_has_prefix (test->data, "tcp:") ||
+       g_str_has_prefix (test->data, "nonce-tcp:")) &&
+      !test_check_tcp_works ())
+    return;
+
   if (!_dbus_test_oom_handling (test->name, test->function,
                                 (void *) test->data))
     {
index c0bf400..b8725b7 100644 (file)
@@ -40,6 +40,7 @@
 typedef struct {
     TestMainContext *ctx;
     DBusError e;
+    gboolean skip;
 
     DBusServer *server;
     DBusConnection *server_conn;
@@ -97,6 +98,14 @@ setup (Fixture *f,
   dbus_error_init (&f->e);
   g_queue_init (&f->server_messages);
 
+  if ((g_str_has_prefix (addr, "tcp:") ||
+       g_str_has_prefix (addr, "nonce-tcp:")) &&
+      !test_check_tcp_works ())
+    {
+      f->skip = TRUE;
+      return;
+    }
+
   f->server = dbus_server_listen (addr, &f->e);
   assert_no_error (&f->e);
   g_assert (f->server != NULL);
@@ -124,6 +133,9 @@ setup_runtime (Fixture *f,
 
   setup (f, addr);
 
+  if (f->skip)
+    return;
+
   listening_at = dbus_server_get_address (f->server);
   g_test_message ("listening at %s", listening_at);
   g_assert (g_str_has_prefix (listening_at, "unix:path="));
@@ -146,6 +158,9 @@ setup_no_runtime (Fixture *f,
 
   setup (f, addr);
 
+  if (f->skip)
+    return;
+
   listening_at = dbus_server_get_address (f->server);
   g_test_message ("listening at %s", listening_at);
   /* we have fallen back to something in /tmp, either abstract or not */
@@ -166,6 +181,9 @@ test_connect (Fixture *f,
   int n_entries;
   dbus_bool_t ok;
 
+  if (f->skip)
+    return;
+
   g_assert (f->server_conn == NULL);
 
   address = dbus_server_get_address (f->server);
@@ -266,13 +284,17 @@ test_bad_guid (Fixture *f,
     gconstpointer addr G_GNUC_UNUSED)
 {
   DBusMessage *incoming;
-  char *address = dbus_server_get_address (f->server);
+  char *address;
   gchar *guid;
 
+  if (f->skip)
+    return;
+
   g_test_bug ("39720");
 
   g_assert (f->server_conn == NULL);
 
+  address = dbus_server_get_address (f->server);
   g_assert (strstr (address, "guid=") != NULL);
   guid = strstr (address, "guid=");
   g_assert_cmpuint (strlen (guid), >=, 5 + 32);
@@ -328,6 +350,9 @@ test_message (Fixture *f,
   dbus_uint32_t serial;
   DBusMessage *outgoing, *incoming;
 
+  if (f->skip)
+    return;
+
   test_connect (f, addr);
 
   outgoing = dbus_message_new_signal ("/com/example/Hello",
index 5f90546..2b3efb9 100644 (file)
@@ -46,6 +46,7 @@
 typedef struct {
     TestMainContext *ctx;
     DBusError e;
+    gboolean skip;
 
     DBusServer *server;
 
@@ -128,6 +129,14 @@ setup (Fixture *f,
   dbus_error_init (&f->e);
   g_queue_init (&f->messages);
 
+  if ((g_str_has_prefix (address, "tcp:") ||
+       g_str_has_prefix (address, "nonce-tcp:")) &&
+      !test_check_tcp_works ())
+    {
+      f->skip = TRUE;
+      return;
+    }
+
   f->server = dbus_server_listen (address, &f->e);
   assert_no_error (&f->e);
   g_assert (f->server != NULL);
@@ -144,6 +153,9 @@ test_connect (Fixture *f,
   dbus_bool_t have_mem;
   char *address;
 
+  if (f->skip)
+    return;
+
   g_assert (f->left_server_conn == NULL);
   g_assert (f->right_server_conn == NULL);
 
@@ -205,6 +217,9 @@ test_relay (Fixture *f,
 {
   DBusMessage *incoming;
 
+  if (f->skip)
+    return;
+
   test_connect (f, data);
 
   send_one (f, "First");
@@ -237,6 +252,9 @@ test_limit (Fixture *f,
   DBusMessage *incoming;
   guint i;
 
+  if (f->skip)
+    return;
+
   test_connect (f, data);
 
   /* This was an attempt to reproduce fd.o #34393. It didn't work. */
index adbe21c..28a3684 100644 (file)
 # include <io.h>
 # include <windows.h>
 #else
+# include <netdb.h>
 # include <signal.h>
 # include <unistd.h>
+# include <sys/socket.h>
 # include <sys/types.h>
 # include <pwd.h>
 #endif
@@ -645,3 +647,58 @@ test_mkdir (const gchar *path,
                g_strerror (saved_errno));
     }
 }
+
+gboolean
+test_check_tcp_works (void)
+{
+#ifdef DBUS_UNIX
+  /* In pathological container environments, we might not have a
+   * working 127.0.0.1 */
+  int res;
+  struct addrinfo *addrs = NULL;
+  struct addrinfo hints;
+  int saved_errno;
+
+  _DBUS_ZERO (hints);
+#ifdef AI_ADDRCONFIG
+  hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+  hints.ai_flags = AI_ADDRCONFIG;
+  hints.ai_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = IPPROTO_TCP;
+
+  res = getaddrinfo ("127.0.0.1", "0", &hints, &addrs);
+  saved_errno = errno;
+
+  if (res != 0)
+    {
+      const gchar *system_message;
+      gchar *skip_message;
+
+#ifdef EAI_SYSTEM
+      if (res == EAI_SYSTEM)
+        system_message = g_strerror (saved_errno);
+      else
+#endif
+        system_message = gai_strerror (res);
+
+      skip_message = g_strdup_printf ("Name resolution does not work here: "
+                                      "getaddrinfo(\"127.0.0.1\", \"0\", "
+                                      "{flags=ADDRCONFIG, family=INET,"
+                                      "socktype=STREAM, protocol=TCP}): "
+                                      "%s",
+                                      system_message);
+      g_test_skip (skip_message);
+      free (skip_message);
+    }
+
+  if (addrs != NULL)
+    freeaddrinfo (addrs);
+
+  return (res == 0);
+#else
+  /* Assume that on Windows, TCP always works */
+  return TRUE;
+#endif
+}
index b170e87..e62121c 100644 (file)
@@ -106,4 +106,6 @@ backported_g_steal_pointer (gpointer pointer_to_pointer)
 }
 #endif
 
+gboolean test_check_tcp_works (void);
+
 #endif