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