31c279f981f91eacbb095f9be2a0102d6375f702
[platform/upstream/dbus.git] / bus / test.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* test.c  unit test routines
3  *
4  * Copyright (C) 2003 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
31 /* The "debug client" watch/timeout handlers don't dispatch messages,
32  * as we manually pull them in order to verify them. This is why they
33  * are different from the real handlers in connection.c
34  */
35 static DBusList *clients = NULL;
36 static DBusLoop *client_loop = NULL;
37
38 static dbus_bool_t
39 client_watch_callback (DBusWatch     *watch,
40                        unsigned int   condition,
41                        void          *data)
42 {
43   DBusConnection *connection = data;
44   dbus_bool_t retval;
45   
46   dbus_connection_ref (connection);
47   
48   retval = dbus_connection_handle_watch (connection, watch, condition);
49
50   dbus_connection_unref (connection);
51
52   return retval;
53 }
54
55 static dbus_bool_t
56 add_client_watch (DBusWatch      *watch,
57                   void           *data)
58 {
59   DBusConnection *connection = data;
60   
61   return _dbus_loop_add_watch (client_loop,
62                                watch, client_watch_callback, connection,
63                                NULL);
64 }
65
66 static void
67 remove_client_watch (DBusWatch      *watch,
68                      void           *data)
69 {
70   DBusConnection *connection = data;
71   
72   _dbus_loop_remove_watch (client_loop,
73                            watch, client_watch_callback, connection);
74 }
75
76 static void
77 client_timeout_callback (DBusTimeout   *timeout,
78                          void          *data)
79 {
80   DBusConnection *connection = data;
81
82   dbus_connection_ref (connection);
83
84   /* can return FALSE on OOM but we just let it fire again later */
85   dbus_timeout_handle (timeout);
86
87   dbus_connection_unref (connection);
88 }
89
90 static dbus_bool_t
91 add_client_timeout (DBusTimeout    *timeout,
92                     void           *data)
93 {
94   DBusConnection *connection = data;
95   
96   return _dbus_loop_add_timeout (client_loop, timeout, client_timeout_callback, connection, NULL);
97 }
98
99 static void
100 remove_client_timeout (DBusTimeout    *timeout,
101                        void           *data)
102 {
103   DBusConnection *connection = data;
104   
105   _dbus_loop_remove_timeout (client_loop, timeout, client_timeout_callback, connection);
106 }
107
108 static DBusHandlerResult
109 client_disconnect_handler (DBusMessageHandler *handler,
110                            DBusConnection     *connection,
111                            DBusMessage        *message,
112                            void               *user_data)
113 {
114   _dbus_verbose ("Removing client %p in disconnect handler\n",
115                  connection);
116   
117   _dbus_list_remove (&clients, connection);
118
119   dbus_connection_unref (connection);
120   
121   if (clients == NULL)
122     {
123       _dbus_loop_unref (client_loop);
124       client_loop = NULL;
125     }
126   
127   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
128 }
129
130 static int handler_slot = -1;
131 static int handler_slot_refcount = 0;
132
133 static dbus_bool_t
134 handler_slot_ref (void)
135 {
136   if (handler_slot < 0)
137     {
138       handler_slot = dbus_connection_allocate_data_slot ();
139       
140       if (handler_slot < 0)
141         return FALSE;
142
143       _dbus_assert (handler_slot_refcount == 0);
144     }  
145
146   handler_slot_refcount += 1;
147
148   return TRUE;
149
150 }
151
152 static void
153 handler_slot_unref (void)
154 {
155   _dbus_assert (handler_slot_refcount > 0);
156
157   handler_slot_refcount -= 1;
158   
159   if (handler_slot_refcount == 0)
160     {
161       dbus_connection_free_data_slot (handler_slot);
162       handler_slot = -1;
163     }
164 }
165
166 static void
167 free_handler (void *data)
168 {
169   DBusMessageHandler *handler = data;
170
171   dbus_message_handler_unref (handler);
172   handler_slot_unref ();
173 }
174
175 dbus_bool_t
176 bus_setup_debug_client (DBusConnection *connection)
177 {
178   DBusMessageHandler *disconnect_handler;
179   const char *to_handle[] = { DBUS_MESSAGE_LOCAL_DISCONNECT };
180   dbus_bool_t retval;
181   
182   disconnect_handler = dbus_message_handler_new (client_disconnect_handler,
183                                                  NULL, NULL);
184
185   if (disconnect_handler == NULL)
186     return FALSE;
187
188   if (!dbus_connection_register_handler (connection,
189                                          disconnect_handler,
190                                          to_handle,
191                                          _DBUS_N_ELEMENTS (to_handle)))
192     {
193       dbus_message_handler_unref (disconnect_handler);
194       return FALSE;
195     }
196
197   retval = FALSE;
198
199   if (client_loop == NULL)
200     {
201       client_loop = _dbus_loop_new ();
202       if (client_loop == NULL)
203         goto out;
204     }
205   
206   if (!dbus_connection_set_watch_functions (connection,
207                                             add_client_watch,
208                                             remove_client_watch,
209                                             NULL,
210                                             connection,
211                                             NULL))
212     goto out;
213       
214   if (!dbus_connection_set_timeout_functions (connection,
215                                               add_client_timeout,
216                                               remove_client_timeout,
217                                               NULL,
218                                               connection, NULL))
219     goto out;
220
221   if (!_dbus_list_append (&clients, connection))
222     goto out;
223
224   if (!handler_slot_ref ())
225     goto out;
226
227   /* Set up handler to be destroyed */  
228   if (!dbus_connection_set_data (connection, handler_slot,
229                                  disconnect_handler,
230                                  free_handler))
231     {
232       handler_slot_unref ();
233       goto out;
234     }
235   
236   retval = TRUE;
237   
238  out:
239   if (!retval)
240     {
241       dbus_message_handler_unref (disconnect_handler); /* unregisters it */
242       
243       dbus_connection_set_watch_functions (connection,
244                                            NULL, NULL, NULL, NULL, NULL);
245       dbus_connection_set_timeout_functions (connection,
246                                              NULL, NULL, NULL, NULL, NULL);
247
248       _dbus_list_remove_last (&clients, connection);
249
250       if (clients == NULL)
251         {
252           _dbus_loop_unref (client_loop);
253           client_loop = NULL;
254         }
255     }
256       
257   return retval;
258 }
259
260 void
261 bus_test_clients_foreach (BusConnectionForeachFunction  function,
262                           void                         *data)
263 {
264   DBusList *link;
265   
266   link = _dbus_list_get_first_link (&clients);
267   while (link != NULL)
268     {
269       DBusConnection *connection = link->data;
270       DBusList *next = _dbus_list_get_next_link (&clients, link);
271
272       if (!(* function) (connection, data))
273         break;
274       
275       link = next;
276     }
277 }
278
279 dbus_bool_t
280 bus_test_client_listed (DBusConnection *connection)
281 {
282   DBusList *link;
283   
284   link = _dbus_list_get_first_link (&clients);
285   while (link != NULL)
286     {
287       DBusConnection *c = link->data;
288       DBusList *next = _dbus_list_get_next_link (&clients, link);
289
290       if (c == connection)
291         return TRUE;
292       
293       link = next;
294     }
295
296   return FALSE;
297 }
298
299 void
300 bus_test_run_clients_loop (void)
301 {
302   if (client_loop == NULL)
303     return;
304   
305   /* Do one blocking wait, since we're expecting data */
306   _dbus_loop_iterate (client_loop, TRUE);
307
308   /* Then mop everything up */
309   while (_dbus_loop_iterate (client_loop, FALSE))
310     ;
311 }
312
313 void
314 bus_test_run_bus_loop (BusContext *context)
315 {
316   /* Do one blocking wait, since we're expecting data */
317   _dbus_loop_iterate (bus_context_get_loop (context), TRUE);
318
319   /* Then mop everything up */
320   while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE))
321     ;
322 }
323
324 void
325 bus_test_run_everything (BusContext *context)
326 {
327   int i;
328
329   i = 0;
330   while (i < 2)
331     {
332       while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE) ||
333              (client_loop == NULL || _dbus_loop_iterate (client_loop, FALSE)))
334         ;
335       ++i;
336     }
337 }
338
339 BusContext*
340 bus_context_new_test (const DBusString *test_data_dir,
341                       const char       *filename)
342 {
343   DBusError error;
344   DBusString config_file;
345   DBusString relative;
346   BusContext *context;
347   
348   if (!_dbus_string_init (&config_file))
349     {
350       _dbus_warn ("No memory\n");
351       return NULL;
352     }
353
354   if (!_dbus_string_copy (test_data_dir, 0,
355                           &config_file, 0))
356     {
357       _dbus_warn ("No memory\n");
358       _dbus_string_free (&config_file);
359       return NULL;
360     }
361
362   _dbus_string_init_const (&relative, filename);
363
364   if (!_dbus_concat_dir_and_file (&config_file, &relative))
365     {
366       _dbus_warn ("No memory\n");
367       _dbus_string_free (&config_file);
368       return NULL;
369     }
370   
371   dbus_error_init (&error);
372   context = bus_context_new (&config_file, -1, &error);
373   if (context == NULL)
374     {
375       _DBUS_ASSERT_ERROR_IS_SET (&error);
376       
377       _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n",
378                   filename, error.message);
379
380       dbus_error_free (&error);
381       
382       _dbus_string_free (&config_file);
383       
384       return NULL;
385     }
386
387   _dbus_string_free (&config_file);
388   
389   return context;
390 }
391
392 #endif