Home | History | Annotate | Download | only in test
      1 /* Integration tests for the dbus-daemon
      2  *
      3  * Author: Simon McVittie <simon.mcvittie (at) collabora.co.uk>
      4  * Copyright  2010-2011 Nokia Corporation
      5  *
      6  * Permission is hereby granted, free of charge, to any person
      7  * obtaining a copy of this software and associated documentation files
      8  * (the "Software"), to deal in the Software without restriction,
      9  * including without limitation the rights to use, copy, modify, merge,
     10  * publish, distribute, sublicense, and/or sell copies of the Software,
     11  * and to permit persons to whom the Software is furnished to do so,
     12  * subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be
     15  * included in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     24  * SOFTWARE.
     25  */
     26 
     27 #include <config.h>
     28 
     29 #include <glib.h>
     30 
     31 #include <dbus/dbus.h>
     32 #include <dbus/dbus-glib-lowlevel.h>
     33 
     34 #include <string.h>
     35 
     36 #ifdef DBUS_WIN
     37 # include <io.h>
     38 # include <windows.h>
     39 #else
     40 # include <signal.h>
     41 # include <unistd.h>
     42 #endif
     43 
     44 typedef struct {
     45     gboolean skip;
     46 
     47     DBusError e;
     48     GError *ge;
     49 
     50     GPid daemon_pid;
     51 
     52     DBusConnection *left_conn;
     53 
     54     DBusConnection *right_conn;
     55     gboolean right_conn_echo;
     56 } Fixture;
     57 
     58 #define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
     59 static void
     60 _assert_no_error (const DBusError *e,
     61     const char *file,
     62     int line)
     63 {
     64   if (G_UNLIKELY (dbus_error_is_set (e)))
     65     g_error ("%s:%d: expected success but got error: %s: %s",
     66         file, line, e->name, e->message);
     67 }
     68 
     69 static gchar *
     70 spawn_dbus_daemon (gchar *binary,
     71     gchar *configuration,
     72     GPid *daemon_pid)
     73 {
     74   GError *error = NULL;
     75   GString *address;
     76   gint address_fd;
     77   gchar *argv[] = {
     78       binary,
     79       configuration,
     80       "--nofork",
     81       "--print-address=1", /* stdout */
     82       NULL
     83   };
     84 
     85   g_spawn_async_with_pipes (NULL, /* working directory */
     86       argv,
     87       NULL, /* envp */
     88       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
     89       NULL, /* child_setup */
     90       NULL, /* user data */
     91       daemon_pid,
     92       NULL, /* child's stdin = /dev/null */
     93       &address_fd,
     94       NULL, /* child's stderr = our stderr */
     95       &error);
     96   g_assert_no_error (error);
     97 
     98   address = g_string_new (NULL);
     99 
    100   /* polling until the dbus-daemon writes out its address is a bit stupid,
    101    * but at least it's simple, unlike dbus-launch... in principle we could
    102    * use select() here, but life's too short */
    103   while (1)
    104     {
    105       gssize bytes;
    106       gchar buf[4096];
    107       gchar *newline;
    108 
    109       bytes = read (address_fd, buf, sizeof (buf));
    110 
    111       if (bytes > 0)
    112         g_string_append_len (address, buf, bytes);
    113 
    114       newline = strchr (address->str, '\n');
    115 
    116       if (newline != NULL)
    117         {
    118           g_string_truncate (address, newline - address->str);
    119           break;
    120         }
    121 
    122       g_usleep (G_USEC_PER_SEC / 10);
    123     }
    124 
    125   return g_string_free (address, FALSE);
    126 }
    127 
    128 static DBusConnection *
    129 connect_to_bus (const gchar *address)
    130 {
    131   DBusConnection *conn;
    132   DBusError error = DBUS_ERROR_INIT;
    133   dbus_bool_t ok;
    134 
    135   conn = dbus_connection_open_private (address, &error);
    136   assert_no_error (&error);
    137   g_assert (conn != NULL);
    138 
    139   ok = dbus_bus_register (conn, &error);
    140   assert_no_error (&error);
    141   g_assert (ok);
    142   g_assert (dbus_bus_get_unique_name (conn) != NULL);
    143 
    144   dbus_connection_setup_with_g_main (conn, NULL);
    145   return conn;
    146 }
    147 
    148 static DBusHandlerResult
    149 echo_filter (DBusConnection *connection,
    150     DBusMessage *message,
    151     void *user_data)
    152 {
    153   DBusMessage *reply;
    154 
    155   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
    156     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    157 
    158   reply = dbus_message_new_method_return (message);
    159 
    160   if (reply == NULL)
    161     g_error ("OOM");
    162 
    163   if (!dbus_connection_send (connection, reply, NULL))
    164     g_error ("OOM");
    165 
    166   dbus_message_unref (reply);
    167 
    168   return DBUS_HANDLER_RESULT_HANDLED;
    169 }
    170 
    171 typedef struct {
    172     const char *bug_ref;
    173     guint min_messages;
    174     const char *config_file;
    175 } Config;
    176 
    177 static void
    178 setup (Fixture *f,
    179     gconstpointer context)
    180 {
    181   const Config *config = context;
    182   gchar *dbus_daemon;
    183   gchar *arg;
    184   gchar *address;
    185 
    186   f->ge = NULL;
    187   dbus_error_init (&f->e);
    188 
    189   if (config != NULL && config->config_file != NULL)
    190     {
    191       if (g_getenv ("DBUS_TEST_DATA") == NULL)
    192         {
    193           g_message ("SKIP: set DBUS_TEST_DATA to a directory containing %s",
    194               config->config_file);
    195           f->skip = TRUE;
    196           return;
    197         }
    198 
    199       arg = g_strdup_printf (
    200           "--config-file=%s/%s",
    201           g_getenv ("DBUS_TEST_DATA"), config->config_file);
    202     }
    203   else if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
    204     {
    205       arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
    206           g_getenv ("DBUS_TEST_SYSCONFDIR"));
    207     }
    208   else if (g_getenv ("DBUS_TEST_DATA") != NULL)
    209     {
    210       arg = g_strdup_printf (
    211           "--config-file=%s/valid-config-files/session.conf",
    212           g_getenv ("DBUS_TEST_DATA"));
    213     }
    214   else
    215     {
    216       arg = g_strdup ("--session");
    217     }
    218 
    219   dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
    220 
    221   if (dbus_daemon == NULL)
    222     dbus_daemon = g_strdup ("dbus-daemon");
    223 
    224   address = spawn_dbus_daemon (dbus_daemon, arg, &f->daemon_pid);
    225 
    226   g_free (dbus_daemon);
    227   g_free (arg);
    228 
    229   f->left_conn = connect_to_bus (address);
    230   f->right_conn = connect_to_bus (address);
    231   g_free (address);
    232 }
    233 
    234 static void
    235 add_echo_filter (Fixture *f)
    236 {
    237   if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
    238     g_error ("OOM");
    239 
    240   f->right_conn_echo = TRUE;
    241 }
    242 
    243 static void
    244 pc_count (DBusPendingCall *pc,
    245     void *data)
    246 {
    247   guint *received_p = data;
    248 
    249   (*received_p)++;
    250 }
    251 
    252 static void
    253 test_echo (Fixture *f,
    254     gconstpointer context)
    255 {
    256   const Config *config = context;
    257   guint count = 2000;
    258   guint sent;
    259   guint received = 0;
    260   double elapsed;
    261 
    262   if (f->skip)
    263     return;
    264 
    265   if (config != NULL && config->bug_ref != NULL)
    266     g_test_bug (config->bug_ref);
    267 
    268   if (g_test_perf ())
    269     count = 100000;
    270 
    271   if (config != NULL)
    272     count = MAX (config->min_messages, count);
    273 
    274   add_echo_filter (f);
    275 
    276   g_test_timer_start ();
    277 
    278   for (sent = 0; sent < count; sent++)
    279     {
    280       DBusMessage *m = dbus_message_new_method_call (
    281           dbus_bus_get_unique_name (f->right_conn), "/",
    282           "com.example", "Spam");
    283       DBusPendingCall *pc;
    284 
    285       if (m == NULL)
    286         g_error ("OOM");
    287 
    288       if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
    289                                             DBUS_TIMEOUT_INFINITE) ||
    290           pc == NULL)
    291         g_error ("OOM");
    292 
    293       if (dbus_pending_call_get_completed (pc))
    294         pc_count (pc, &received);
    295       else if (!dbus_pending_call_set_notify (pc, pc_count, &received,
    296             NULL))
    297         g_error ("OOM");
    298 
    299       dbus_pending_call_unref (pc);
    300       dbus_message_unref (m);
    301     }
    302 
    303   while (received < count)
    304     g_main_context_iteration (NULL, TRUE);
    305 
    306   elapsed = g_test_timer_elapsed ();
    307 
    308   g_test_maximized_result (count / elapsed, "%u messages / %f seconds",
    309       count, elapsed);
    310 }
    311 
    312 static void
    313 teardown (Fixture *f,
    314     gconstpointer context G_GNUC_UNUSED)
    315 {
    316   dbus_error_free (&f->e);
    317   g_clear_error (&f->ge);
    318 
    319   if (f->left_conn != NULL)
    320     {
    321       dbus_connection_close (f->left_conn);
    322       dbus_connection_unref (f->left_conn);
    323       f->left_conn = NULL;
    324     }
    325 
    326   if (f->right_conn != NULL)
    327     {
    328       if (f->right_conn_echo)
    329         {
    330           dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
    331           f->right_conn_echo = FALSE;
    332         }
    333 
    334       dbus_connection_close (f->right_conn);
    335       dbus_connection_unref (f->right_conn);
    336       f->right_conn = NULL;
    337     }
    338 
    339   if (f->daemon_pid != 0)
    340     {
    341 #ifdef DBUS_WIN
    342       TerminateProcess (f->daemon_pid, 1);
    343 #else
    344       kill (f->daemon_pid, SIGTERM);
    345 #endif
    346 
    347       g_spawn_close_pid (f->daemon_pid);
    348       f->daemon_pid = 0;
    349     }
    350 }
    351 
    352 static Config limited_config = {
    353     "34393", 10000, "valid-config-files/incoming-limit.conf"
    354 };
    355 
    356 int
    357 main (int argc,
    358     char **argv)
    359 {
    360   g_test_init (&argc, &argv, NULL);
    361   g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
    362 
    363   g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
    364   g_test_add ("/echo/limited", Fixture, &limited_config,
    365       setup, test_echo, teardown);
    366 
    367   return g_test_run ();
    368 }
    369