Home | History | Annotate | Download | only in bus
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 /* test.c  unit test routines
      3  *
      4  * Copyright (C) 2003 Red Hat, Inc.
      5  *
      6  * Licensed under the Academic Free License version 2.1
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License as published by
     10  * the Free Software Foundation; either version 2 of the License, or
     11  * (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     21  *
     22  */
     23 
     24 #include <config.h>
     25 
     26 #ifdef DBUS_BUILD_TESTS
     27 #include "test.h"
     28 #include <dbus/dbus-internals.h>
     29 #include <dbus/dbus-list.h>
     30 #include <dbus/dbus-sysdeps.h>
     31 
     32 /* The "debug client" watch/timeout handlers don't dispatch messages,
     33  * as we manually pull them in order to verify them. This is why they
     34  * are different from the real handlers in connection.c
     35  */
     36 static DBusList *clients = NULL;
     37 static DBusLoop *client_loop = NULL;
     38 
     39 static dbus_bool_t
     40 client_watch_callback (DBusWatch     *watch,
     41                        unsigned int   condition,
     42                        void          *data)
     43 {
     44   /* FIXME this can be done in dbus-mainloop.c
     45    * if the code in activation.c for the babysitter
     46    * watch handler is fixed.
     47    */
     48 
     49   return dbus_watch_handle (watch, condition);
     50 }
     51 
     52 static dbus_bool_t
     53 add_client_watch (DBusWatch      *watch,
     54                   void           *data)
     55 {
     56   DBusConnection *connection = data;
     57 
     58   return _dbus_loop_add_watch (client_loop,
     59                                watch, client_watch_callback, connection,
     60                                NULL);
     61 }
     62 
     63 static void
     64 remove_client_watch (DBusWatch      *watch,
     65                      void           *data)
     66 {
     67   DBusConnection *connection = data;
     68 
     69   _dbus_loop_remove_watch (client_loop,
     70                            watch, client_watch_callback, connection);
     71 }
     72 
     73 static void
     74 client_timeout_callback (DBusTimeout   *timeout,
     75                          void          *data)
     76 {
     77   DBusConnection *connection = data;
     78 
     79   dbus_connection_ref (connection);
     80 
     81   /* can return FALSE on OOM but we just let it fire again later */
     82   dbus_timeout_handle (timeout);
     83 
     84   dbus_connection_unref (connection);
     85 }
     86 
     87 static dbus_bool_t
     88 add_client_timeout (DBusTimeout    *timeout,
     89                     void           *data)
     90 {
     91   DBusConnection *connection = data;
     92 
     93   return _dbus_loop_add_timeout (client_loop, timeout, client_timeout_callback, connection, NULL);
     94 }
     95 
     96 static void
     97 remove_client_timeout (DBusTimeout    *timeout,
     98                        void           *data)
     99 {
    100   DBusConnection *connection = data;
    101 
    102   _dbus_loop_remove_timeout (client_loop, timeout, client_timeout_callback, connection);
    103 }
    104 
    105 static DBusHandlerResult
    106 client_disconnect_filter (DBusConnection     *connection,
    107                           DBusMessage        *message,
    108                           void               *user_data)
    109 {
    110   if (!dbus_message_is_signal (message,
    111                                DBUS_INTERFACE_LOCAL,
    112                                "Disconnected"))
    113     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    114 
    115   _dbus_verbose ("Removing client %p in disconnect handler\n",
    116                  connection);
    117 
    118   _dbus_list_remove (&clients, connection);
    119 
    120   dbus_connection_unref (connection);
    121 
    122   if (clients == NULL)
    123     {
    124       _dbus_loop_unref (client_loop);
    125       client_loop = NULL;
    126     }
    127 
    128   return DBUS_HANDLER_RESULT_HANDLED;
    129 }
    130 
    131 dbus_bool_t
    132 bus_setup_debug_client (DBusConnection *connection)
    133 {
    134   dbus_bool_t retval;
    135 
    136   if (!dbus_connection_add_filter (connection,
    137                                    client_disconnect_filter,
    138                                    NULL, NULL))
    139     return FALSE;
    140 
    141   retval = FALSE;
    142 
    143   if (client_loop == NULL)
    144     {
    145       client_loop = _dbus_loop_new ();
    146       if (client_loop == NULL)
    147         goto out;
    148     }
    149 
    150   if (!dbus_connection_set_watch_functions (connection,
    151                                             add_client_watch,
    152                                             remove_client_watch,
    153                                             NULL,
    154                                             connection,
    155                                             NULL))
    156     goto out;
    157 
    158   if (!dbus_connection_set_timeout_functions (connection,
    159                                               add_client_timeout,
    160                                               remove_client_timeout,
    161                                               NULL,
    162                                               connection, NULL))
    163     goto out;
    164 
    165   if (!_dbus_list_append (&clients, connection))
    166     goto out;
    167 
    168   retval = TRUE;
    169 
    170  out:
    171   if (!retval)
    172     {
    173       dbus_connection_remove_filter (connection,
    174                                      client_disconnect_filter,
    175                                      NULL);
    176 
    177       dbus_connection_set_watch_functions (connection,
    178                                            NULL, NULL, NULL, NULL, NULL);
    179       dbus_connection_set_timeout_functions (connection,
    180                                              NULL, NULL, NULL, NULL, NULL);
    181 
    182       _dbus_list_remove_last (&clients, connection);
    183 
    184       if (clients == NULL)
    185         {
    186           _dbus_loop_unref (client_loop);
    187           client_loop = NULL;
    188         }
    189     }
    190 
    191   return retval;
    192 }
    193 
    194 void
    195 bus_test_clients_foreach (BusConnectionForeachFunction  function,
    196                           void                         *data)
    197 {
    198   DBusList *link;
    199 
    200   link = _dbus_list_get_first_link (&clients);
    201   while (link != NULL)
    202     {
    203       DBusConnection *connection = link->data;
    204       DBusList *next = _dbus_list_get_next_link (&clients, link);
    205 
    206       if (!(* function) (connection, data))
    207         break;
    208 
    209       link = next;
    210     }
    211 }
    212 
    213 dbus_bool_t
    214 bus_test_client_listed (DBusConnection *connection)
    215 {
    216   DBusList *link;
    217 
    218   link = _dbus_list_get_first_link (&clients);
    219   while (link != NULL)
    220     {
    221       DBusConnection *c = link->data;
    222       DBusList *next = _dbus_list_get_next_link (&clients, link);
    223 
    224       if (c == connection)
    225         return TRUE;
    226 
    227       link = next;
    228     }
    229 
    230   return FALSE;
    231 }
    232 
    233 void
    234 bus_test_run_clients_loop (dbus_bool_t block_once)
    235 {
    236   if (client_loop == NULL)
    237     return;
    238 
    239   _dbus_verbose ("---> Dispatching on \"client side\"\n");
    240 
    241   /* dispatch before we block so pending dispatches
    242    * won't make our block return early
    243    */
    244   _dbus_loop_dispatch (client_loop);
    245 
    246   /* Do one blocking wait, since we're expecting data */
    247   if (block_once)
    248     {
    249       _dbus_verbose ("---> blocking on \"client side\"\n");
    250       _dbus_loop_iterate (client_loop, TRUE);
    251     }
    252 
    253   /* Then mop everything up */
    254   while (_dbus_loop_iterate (client_loop, FALSE))
    255     ;
    256 
    257   _dbus_verbose ("---> Done dispatching on \"client side\"\n");
    258 }
    259 
    260 void
    261 bus_test_run_bus_loop (BusContext *context,
    262                        dbus_bool_t block_once)
    263 {
    264   _dbus_verbose ("---> Dispatching on \"server side\"\n");
    265 
    266   /* dispatch before we block so pending dispatches
    267    * won't make our block return early
    268    */
    269   _dbus_loop_dispatch (bus_context_get_loop (context));
    270 
    271   /* Do one blocking wait, since we're expecting data */
    272   if (block_once)
    273     {
    274       _dbus_verbose ("---> blocking on \"server side\"\n");
    275       _dbus_loop_iterate (bus_context_get_loop (context), TRUE);
    276     }
    277 
    278   /* Then mop everything up */
    279   while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE))
    280     ;
    281 
    282   _dbus_verbose ("---> Done dispatching on \"server side\"\n");
    283 }
    284 
    285 void
    286 bus_test_run_everything (BusContext *context)
    287 {
    288   while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE) ||
    289          (client_loop == NULL || _dbus_loop_iterate (client_loop, FALSE)))
    290     ;
    291 }
    292 
    293 BusContext*
    294 bus_context_new_test (const DBusString *test_data_dir,
    295                       const char       *filename)
    296 {
    297   DBusError error;
    298   DBusString config_file;
    299   DBusString relative;
    300   BusContext *context;
    301 
    302   if (!_dbus_string_init (&config_file))
    303     {
    304       _dbus_warn ("No memory\n");
    305       return NULL;
    306     }
    307 
    308   if (!_dbus_string_copy (test_data_dir, 0,
    309                           &config_file, 0))
    310     {
    311       _dbus_warn ("No memory\n");
    312       _dbus_string_free (&config_file);
    313       return NULL;
    314     }
    315 
    316   _dbus_string_init_const (&relative, filename);
    317 
    318   if (!_dbus_concat_dir_and_file (&config_file, &relative))
    319     {
    320       _dbus_warn ("No memory\n");
    321       _dbus_string_free (&config_file);
    322       return NULL;
    323     }
    324 
    325   dbus_error_init (&error);
    326   context = bus_context_new (&config_file, FALSE, NULL, NULL, NULL, FALSE, &error);
    327   if (context == NULL)
    328     {
    329       _DBUS_ASSERT_ERROR_IS_SET (&error);
    330 
    331       _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n",
    332                   filename, error.message);
    333 
    334       dbus_error_free (&error);
    335 
    336       _dbus_string_free (&config_file);
    337 
    338       return NULL;
    339     }
    340 
    341   _dbus_string_free (&config_file);
    342 
    343   return context;
    344 }
    345 
    346 #endif
    347