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