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
add_client_watch(DBusWatch * watch,void * data)40 add_client_watch (DBusWatch      *watch,
41                   void           *data)
42 {
43   return _dbus_loop_add_watch (client_loop, watch);
44 }
45 
46 static void
remove_client_watch(DBusWatch * watch,void * data)47 remove_client_watch (DBusWatch      *watch,
48                      void           *data)
49 {
50   _dbus_loop_remove_watch (client_loop, watch);
51 }
52 
53 static void
toggle_client_watch(DBusWatch * watch,void * data)54 toggle_client_watch (DBusWatch      *watch,
55                      void           *data)
56 {
57   _dbus_loop_toggle_watch (client_loop, watch);
58 }
59 
60 static dbus_bool_t
add_client_timeout(DBusTimeout * timeout,void * data)61 add_client_timeout (DBusTimeout    *timeout,
62                     void           *data)
63 {
64   return _dbus_loop_add_timeout (client_loop, timeout);
65 }
66 
67 static void
remove_client_timeout(DBusTimeout * timeout,void * data)68 remove_client_timeout (DBusTimeout    *timeout,
69                        void           *data)
70 {
71   _dbus_loop_remove_timeout (client_loop, timeout);
72 }
73 
74 static DBusHandlerResult
client_disconnect_filter(DBusConnection * connection,DBusMessage * message,void * user_data)75 client_disconnect_filter (DBusConnection     *connection,
76                           DBusMessage        *message,
77                           void               *user_data)
78 {
79   if (!dbus_message_is_signal (message,
80                                DBUS_INTERFACE_LOCAL,
81                                "Disconnected"))
82     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
83 
84   _dbus_verbose ("Removing client %p in disconnect handler\n",
85                  connection);
86 
87   _dbus_list_remove (&clients, connection);
88 
89   dbus_connection_unref (connection);
90 
91   if (clients == NULL)
92     {
93       _dbus_loop_unref (client_loop);
94       client_loop = NULL;
95     }
96 
97   return DBUS_HANDLER_RESULT_HANDLED;
98 }
99 
100 dbus_bool_t
bus_setup_debug_client(DBusConnection * connection)101 bus_setup_debug_client (DBusConnection *connection)
102 {
103   dbus_bool_t retval;
104 
105   if (!dbus_connection_add_filter (connection,
106                                    client_disconnect_filter,
107                                    NULL, NULL))
108     return FALSE;
109 
110   retval = FALSE;
111 
112   if (client_loop == NULL)
113     {
114       client_loop = _dbus_loop_new ();
115       if (client_loop == NULL)
116         goto out;
117     }
118 
119   if (!dbus_connection_set_watch_functions (connection,
120                                             add_client_watch,
121                                             remove_client_watch,
122                                             toggle_client_watch,
123                                             connection,
124                                             NULL))
125     goto out;
126 
127   if (!dbus_connection_set_timeout_functions (connection,
128                                               add_client_timeout,
129                                               remove_client_timeout,
130                                               NULL,
131                                               connection, NULL))
132     goto out;
133 
134   if (!_dbus_list_append (&clients, connection))
135     goto out;
136 
137   retval = TRUE;
138 
139  out:
140   if (!retval)
141     {
142       dbus_connection_remove_filter (connection,
143                                      client_disconnect_filter,
144                                      NULL);
145 
146       dbus_connection_set_watch_functions (connection,
147                                            NULL, NULL, NULL, NULL, NULL);
148       dbus_connection_set_timeout_functions (connection,
149                                              NULL, NULL, NULL, NULL, NULL);
150 
151       _dbus_list_remove_last (&clients, connection);
152 
153       if (clients == NULL)
154         {
155           _dbus_loop_unref (client_loop);
156           client_loop = NULL;
157         }
158     }
159 
160   return retval;
161 }
162 
163 void
bus_test_clients_foreach(BusConnectionForeachFunction function,void * data)164 bus_test_clients_foreach (BusConnectionForeachFunction  function,
165                           void                         *data)
166 {
167   DBusList *link;
168 
169   link = _dbus_list_get_first_link (&clients);
170   while (link != NULL)
171     {
172       DBusConnection *connection = link->data;
173       DBusList *next = _dbus_list_get_next_link (&clients, link);
174 
175       if (!(* function) (connection, data))
176         break;
177 
178       link = next;
179     }
180 }
181 
182 dbus_bool_t
bus_test_client_listed(DBusConnection * connection)183 bus_test_client_listed (DBusConnection *connection)
184 {
185   DBusList *link;
186 
187   link = _dbus_list_get_first_link (&clients);
188   while (link != NULL)
189     {
190       DBusConnection *c = link->data;
191       DBusList *next = _dbus_list_get_next_link (&clients, link);
192 
193       if (c == connection)
194         return TRUE;
195 
196       link = next;
197     }
198 
199   return FALSE;
200 }
201 
202 void
bus_test_run_clients_loop(dbus_bool_t block_once)203 bus_test_run_clients_loop (dbus_bool_t block_once)
204 {
205   if (client_loop == NULL)
206     return;
207 
208   _dbus_verbose ("---> Dispatching on \"client side\"\n");
209 
210   /* dispatch before we block so pending dispatches
211    * won't make our block return early
212    */
213   _dbus_loop_dispatch (client_loop);
214 
215   /* Do one blocking wait, since we're expecting data */
216   if (block_once)
217     {
218       _dbus_verbose ("---> blocking on \"client side\"\n");
219       _dbus_loop_iterate (client_loop, TRUE);
220     }
221 
222   /* Then mop everything up */
223   while (_dbus_loop_iterate (client_loop, FALSE))
224     ;
225 
226   _dbus_verbose ("---> Done dispatching on \"client side\"\n");
227 }
228 
229 void
bus_test_run_bus_loop(BusContext * context,dbus_bool_t block_once)230 bus_test_run_bus_loop (BusContext *context,
231                        dbus_bool_t block_once)
232 {
233   _dbus_verbose ("---> Dispatching on \"server side\"\n");
234 
235   /* dispatch before we block so pending dispatches
236    * won't make our block return early
237    */
238   _dbus_loop_dispatch (bus_context_get_loop (context));
239 
240   /* Do one blocking wait, since we're expecting data */
241   if (block_once)
242     {
243       _dbus_verbose ("---> blocking on \"server side\"\n");
244       _dbus_loop_iterate (bus_context_get_loop (context), TRUE);
245     }
246 
247   /* Then mop everything up */
248   while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE))
249     ;
250 
251   _dbus_verbose ("---> Done dispatching on \"server side\"\n");
252 }
253 
254 void
bus_test_run_everything(BusContext * context)255 bus_test_run_everything (BusContext *context)
256 {
257   while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE) ||
258          (client_loop == NULL || _dbus_loop_iterate (client_loop, FALSE)))
259     ;
260 }
261 
262 BusContext*
bus_context_new_test(const DBusString * test_data_dir,const char * filename)263 bus_context_new_test (const DBusString *test_data_dir,
264                       const char       *filename)
265 {
266   DBusError error;
267   DBusString config_file;
268   DBusString relative;
269   BusContext *context;
270 
271   if (!_dbus_string_init (&config_file))
272     {
273       _dbus_warn ("No memory\n");
274       return NULL;
275     }
276 
277   if (!_dbus_string_copy (test_data_dir, 0,
278                           &config_file, 0))
279     {
280       _dbus_warn ("No memory\n");
281       _dbus_string_free (&config_file);
282       return NULL;
283     }
284 
285   _dbus_string_init_const (&relative, filename);
286 
287   if (!_dbus_concat_dir_and_file (&config_file, &relative))
288     {
289       _dbus_warn ("No memory\n");
290       _dbus_string_free (&config_file);
291       return NULL;
292     }
293 
294   dbus_error_init (&error);
295   context = bus_context_new (&config_file, BUS_CONTEXT_FLAG_NONE, NULL, NULL, NULL, &error);
296   if (context == NULL)
297     {
298       _DBUS_ASSERT_ERROR_IS_SET (&error);
299 
300       _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n",
301                   filename, error.message);
302 
303       dbus_error_free (&error);
304 
305       _dbus_string_free (&config_file);
306 
307       return NULL;
308     }
309 
310   _dbus_string_free (&config_file);
311 
312   return context;
313 }
314 
315 #endif
316