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