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 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., 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
client_watch_callback(DBusWatch * watch,unsigned int condition,void * data)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
add_client_watch(DBusWatch * watch,void * data)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
remove_client_watch(DBusWatch * watch,void * data)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
client_timeout_callback(DBusTimeout * timeout,void * data)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
add_client_timeout(DBusTimeout * timeout,void * data)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
remove_client_timeout(DBusTimeout * timeout,void * data)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
client_disconnect_filter(DBusConnection * connection,DBusMessage * message,void * user_data)105 client_disconnect_filter (DBusConnection *connection,
106 DBusMessage *message,
107 void *user_data)
108 {
109 if (!dbus_message_is_signal (message,
110 DBUS_INTERFACE_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
bus_setup_debug_client(DBusConnection * connection)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
bus_test_clients_foreach(BusConnectionForeachFunction function,void * data)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
bus_test_client_listed(DBusConnection * connection)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
bus_test_run_clients_loop(dbus_bool_t block_once)233 bus_test_run_clients_loop (dbus_bool_t block_once)
234 {
235 if (client_loop == NULL)
236 return;
237
238 _dbus_verbose ("---> Dispatching on \"client side\"\n");
239
240 /* dispatch before we block so pending dispatches
241 * won't make our block return early
242 */
243 _dbus_loop_dispatch (client_loop);
244
245 /* Do one blocking wait, since we're expecting data */
246 if (block_once)
247 {
248 _dbus_verbose ("---> blocking on \"client side\"\n");
249 _dbus_loop_iterate (client_loop, TRUE);
250 }
251
252 /* Then mop everything up */
253 while (_dbus_loop_iterate (client_loop, FALSE))
254 ;
255
256 _dbus_verbose ("---> Done dispatching on \"client side\"\n");
257 }
258
259 void
bus_test_run_bus_loop(BusContext * context,dbus_bool_t block_once)260 bus_test_run_bus_loop (BusContext *context,
261 dbus_bool_t block_once)
262 {
263 _dbus_verbose ("---> Dispatching on \"server side\"\n");
264
265 /* dispatch before we block so pending dispatches
266 * won't make our block return early
267 */
268 _dbus_loop_dispatch (bus_context_get_loop (context));
269
270 /* Do one blocking wait, since we're expecting data */
271 if (block_once)
272 {
273 _dbus_verbose ("---> blocking on \"server side\"\n");
274 _dbus_loop_iterate (bus_context_get_loop (context), TRUE);
275 }
276
277 /* Then mop everything up */
278 while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE))
279 ;
280
281 _dbus_verbose ("---> Done dispatching on \"server side\"\n");
282 }
283
284 void
bus_test_run_everything(BusContext * context)285 bus_test_run_everything (BusContext *context)
286 {
287 while (_dbus_loop_iterate (bus_context_get_loop (context), FALSE) ||
288 (client_loop == NULL || _dbus_loop_iterate (client_loop, FALSE)))
289 ;
290 }
291
292 BusContext*
bus_context_new_test(const DBusString * test_data_dir,const char * filename)293 bus_context_new_test (const DBusString *test_data_dir,
294 const char *filename)
295 {
296 DBusError error;
297 DBusString config_file;
298 DBusString relative;
299 BusContext *context;
300
301 if (!_dbus_string_init (&config_file))
302 {
303 _dbus_warn ("No memory\n");
304 return NULL;
305 }
306
307 if (!_dbus_string_copy (test_data_dir, 0,
308 &config_file, 0))
309 {
310 _dbus_warn ("No memory\n");
311 _dbus_string_free (&config_file);
312 return NULL;
313 }
314
315 _dbus_string_init_const (&relative, filename);
316
317 if (!_dbus_concat_dir_and_file (&config_file, &relative))
318 {
319 _dbus_warn ("No memory\n");
320 _dbus_string_free (&config_file);
321 return NULL;
322 }
323
324 dbus_error_init (&error);
325 context = bus_context_new (&config_file, FALSE, -1, -1, &error);
326 if (context == NULL)
327 {
328 _DBUS_ASSERT_ERROR_IS_SET (&error);
329
330 _dbus_warn ("Failed to create debug bus context from configuration file %s: %s\n",
331 filename, error.message);
332
333 dbus_error_free (&error);
334
335 _dbus_string_free (&config_file);
336
337 return NULL;
338 }
339
340 _dbus_string_free (&config_file);
341
342 return context;
343 }
344
345 #endif
346