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 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_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 _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 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 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* 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