Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: David Zeuthen <davidz@redhat.com>
21 : : */
22 : :
23 : : #include <gio/gio.h>
24 : : #include <unistd.h>
25 : : #include <string.h>
26 : :
27 : : #include <sys/types.h>
28 : :
29 : : #include "gdbus-tests.h"
30 : :
31 : : /* all tests rely on a shared mainloop */
32 : : static GMainLoop *loop = NULL;
33 : :
34 : : #if 0
35 : : G_GNUC_UNUSED static void
36 : : _log (const gchar *format, ...)
37 : : {
38 : : GTimeVal now;
39 : : time_t now_time;
40 : : struct tm *now_tm;
41 : : gchar time_buf[128];
42 : : gchar *str;
43 : : va_list var_args;
44 : :
45 : : va_start (var_args, format);
46 : : str = g_strdup_vprintf (format, var_args);
47 : : va_end (var_args);
48 : :
49 : : g_get_current_time (&now);
50 : : now_time = (time_t) now.tv_sec;
51 : : now_tm = localtime (&now_time);
52 : : strftime (time_buf, sizeof time_buf, "%H:%M:%S", now_tm);
53 : :
54 : : g_printerr ("%s.%06d: %s\n",
55 : : time_buf, (gint) now.tv_usec / 1000,
56 : : str);
57 : : g_free (str);
58 : : }
59 : : #else
60 : : #define _log(...)
61 : : #endif
62 : :
63 : : static gboolean
64 : 0 : test_connection_quit_mainloop (gpointer user_data)
65 : : {
66 : 0 : gboolean *quit_mainloop_fired = user_data; /* (atomic) */
67 : : _log ("quit_mainloop_fired");
68 : 0 : g_atomic_int_set (quit_mainloop_fired, TRUE);
69 : 0 : g_main_loop_quit (loop);
70 : 0 : return G_SOURCE_CONTINUE;
71 : : }
72 : :
73 : : /* ---------------------------------------------------------------------------------------------------- */
74 : : /* Connection life-cycle testing */
75 : : /* ---------------------------------------------------------------------------------------------------- */
76 : :
77 : : static const GDBusInterfaceInfo boo_interface_info =
78 : : {
79 : : -1,
80 : : "org.example.Boo",
81 : : (GDBusMethodInfo **) NULL,
82 : : (GDBusSignalInfo **) NULL,
83 : : (GDBusPropertyInfo **) NULL,
84 : : NULL,
85 : : };
86 : :
87 : : static const GDBusInterfaceVTable boo_vtable =
88 : : {
89 : : NULL, /* _method_call */
90 : : NULL, /* _get_property */
91 : : NULL, /* _set_property */
92 : : { 0 }
93 : : };
94 : :
95 : : /* Runs in a worker thread. */
96 : : static GDBusMessage *
97 : 1 : some_filter_func (GDBusConnection *connection,
98 : : GDBusMessage *message,
99 : : gboolean incoming,
100 : : gpointer user_data)
101 : : {
102 : 1 : return message;
103 : : }
104 : :
105 : : static void
106 : 0 : on_name_owner_changed (GDBusConnection *connection,
107 : : const gchar *sender_name,
108 : : const gchar *object_path,
109 : : const gchar *interface_name,
110 : : const gchar *signal_name,
111 : : GVariant *parameters,
112 : : gpointer user_data)
113 : : {
114 : 0 : }
115 : :
116 : : static void
117 : 3 : a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop (gpointer user_data)
118 : : {
119 : 3 : gboolean *val = user_data; /* (atomic) */
120 : 3 : g_atomic_int_set (val, TRUE);
121 : : _log ("destroynotify fired for %p", val);
122 : 3 : g_main_loop_quit (loop);
123 : 3 : }
124 : :
125 : : static void
126 : 1 : test_connection_bus_failure (void)
127 : : {
128 : : GDBusConnection *c;
129 : 1 : GError *error = NULL;
130 : :
131 : : /*
132 : : * Check for correct behavior when no bus is present
133 : : *
134 : : */
135 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
136 : 1 : g_assert_nonnull (error);
137 : 1 : g_assert_false (g_dbus_error_is_remote_error (error));
138 : 1 : g_assert_null (c);
139 : 1 : g_error_free (error);
140 : 1 : }
141 : :
142 : : static void
143 : 1 : test_connection_life_cycle (void)
144 : : {
145 : : gboolean ret;
146 : : GDBusConnection *c;
147 : : GDBusConnection *c2;
148 : : GError *error;
149 : : gboolean on_signal_registration_freed_called; /* (atomic) */
150 : : gboolean on_filter_freed_called; /* (atomic) */
151 : : gboolean on_register_object_freed_called; /* (atomic) */
152 : : gboolean quit_mainloop_fired; /* (atomic) */
153 : : guint quit_mainloop_id;
154 : : guint registration_id;
155 : :
156 : 1 : error = NULL;
157 : :
158 : : /*
159 : : * Check for correct behavior when a bus is present
160 : : */
161 : 1 : session_bus_up ();
162 : : /* case 1 */
163 : 1 : error = NULL;
164 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
165 : 1 : g_assert_no_error (error);
166 : 1 : g_assert_nonnull (c);
167 : 1 : g_assert_false (g_dbus_connection_is_closed (c));
168 : :
169 : : /*
170 : : * Check that singleton handling work
171 : : */
172 : 1 : error = NULL;
173 : 1 : c2 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
174 : 1 : g_assert_no_error (error);
175 : 1 : g_assert_nonnull (c2);
176 : 1 : g_assert_true (c == c2);
177 : 1 : g_object_unref (c2);
178 : :
179 : : /*
180 : : * Check that private connections work
181 : : */
182 : 1 : c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
183 : 1 : g_assert_no_error (error);
184 : 1 : g_assert_nonnull (c2);
185 : 1 : g_assert_true (c != c2);
186 : 1 : g_object_unref (c2);
187 : :
188 : 1 : c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
189 : 1 : g_assert_no_error (error);
190 : 1 : g_assert_nonnull (c2);
191 : 1 : g_assert_false (g_dbus_connection_is_closed (c2));
192 : 1 : ret = g_dbus_connection_close_sync (c2, NULL, &error);
193 : 1 : g_assert_no_error (error);
194 : 1 : g_assert_true (ret);
195 : 1 : _g_assert_signal_received (c2, "closed");
196 : 1 : g_assert_true (g_dbus_connection_is_closed (c2));
197 : 1 : ret = g_dbus_connection_close_sync (c2, NULL, &error);
198 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
199 : 1 : g_error_free (error);
200 : 1 : g_assert_false (ret);
201 : 1 : g_object_unref (c2);
202 : :
203 : : /*
204 : : * Check that the finalization code works
205 : : *
206 : : * (and that the GDestroyNotify for filters and objects and signal
207 : : * registrations are run as expected)
208 : : */
209 : 1 : error = NULL;
210 : 1 : c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
211 : 1 : g_assert_no_error (error);
212 : 1 : g_assert_nonnull (c2);
213 : : /* signal registration */
214 : 1 : g_atomic_int_set (&on_signal_registration_freed_called, FALSE);
215 : 1 : g_dbus_connection_signal_subscribe (c2,
216 : : "org.freedesktop.DBus", /* bus name */
217 : : "org.freedesktop.DBus", /* interface */
218 : : "NameOwnerChanged", /* member */
219 : : "/org/freesktop/DBus", /* path */
220 : : NULL, /* arg0 */
221 : : G_DBUS_SIGNAL_FLAGS_NONE,
222 : : on_name_owner_changed,
223 : : (gpointer) &on_signal_registration_freed_called,
224 : : a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop);
225 : : /* filter func */
226 : 1 : g_atomic_int_set (&on_filter_freed_called, FALSE);
227 : 1 : g_dbus_connection_add_filter (c2,
228 : : some_filter_func,
229 : : (gpointer) &on_filter_freed_called,
230 : : a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop);
231 : : /* object registration */
232 : 1 : g_atomic_int_set (&on_register_object_freed_called, FALSE);
233 : 1 : error = NULL;
234 : 1 : registration_id = g_dbus_connection_register_object (c2,
235 : : "/foo",
236 : : (GDBusInterfaceInfo *) &boo_interface_info,
237 : : &boo_vtable,
238 : : (gpointer) &on_register_object_freed_called,
239 : : a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop,
240 : : &error);
241 : 1 : g_assert_no_error (error);
242 : 1 : g_assert_cmpuint (registration_id, >, 0);
243 : : /* ok, finalize the connection and check that all the GDestroyNotify functions are invoked as expected */
244 : 1 : g_object_unref (c2);
245 : 1 : g_atomic_int_set (&quit_mainloop_fired, FALSE);
246 : 1 : quit_mainloop_id = g_timeout_add (30000, test_connection_quit_mainloop, (gpointer) &quit_mainloop_fired);
247 : : _log ("destroynotifies for\n"
248 : : " register_object %p\n"
249 : : " filter %p\n"
250 : : " signal %p",
251 : : &on_register_object_freed_called,
252 : : &on_filter_freed_called,
253 : : &on_signal_registration_freed_called);
254 : : while (TRUE)
255 : : {
256 [ + + ]: 3 : if (g_atomic_int_get (&on_signal_registration_freed_called) &&
257 [ + + ]: 2 : g_atomic_int_get (&on_filter_freed_called) &&
258 [ + - ]: 1 : g_atomic_int_get (&on_register_object_freed_called))
259 : 1 : break;
260 [ - + ]: 2 : if (g_atomic_int_get (&quit_mainloop_fired))
261 : 0 : break;
262 : : _log ("entering loop");
263 : 2 : g_main_loop_run (loop);
264 : : _log ("exiting loop");
265 : : }
266 : 1 : g_source_remove (quit_mainloop_id);
267 : 1 : g_assert_true (g_atomic_int_get (&on_signal_registration_freed_called));
268 : 1 : g_assert_true (g_atomic_int_get (&on_filter_freed_called));
269 : 1 : g_assert_true (g_atomic_int_get (&on_register_object_freed_called));
270 : 1 : g_assert_false (g_atomic_int_get (&quit_mainloop_fired));
271 : :
272 : : /*
273 : : * Check for correct behavior when the bus goes away
274 : : *
275 : : */
276 : 1 : g_assert_false (g_dbus_connection_is_closed (c));
277 : 1 : g_dbus_connection_set_exit_on_close (c, FALSE);
278 : 1 : session_bus_stop ();
279 : 1 : _g_assert_signal_received (c, "closed");
280 : 1 : g_assert_true (g_dbus_connection_is_closed (c));
281 : 1 : g_object_unref (c);
282 : :
283 : 1 : session_bus_down ();
284 : 1 : }
285 : :
286 : : /* ---------------------------------------------------------------------------------------------------- */
287 : : /* Test that sending and receiving messages work as expected */
288 : : /* ---------------------------------------------------------------------------------------------------- */
289 : :
290 : : static void
291 : 1 : msg_cb_expect_error_disconnected (GDBusConnection *connection,
292 : : GAsyncResult *res,
293 : : gpointer user_data)
294 : : {
295 : : GError *error;
296 : : GVariant *result;
297 : :
298 : : /* Make sure gdbusconnection isn't holding @connection's lock. (#747349) */
299 : 1 : g_dbus_connection_get_last_serial (connection);
300 : :
301 : 1 : error = NULL;
302 : 1 : result = g_dbus_connection_call_finish (connection,
303 : : res,
304 : : &error);
305 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
306 : 1 : g_assert_false (g_dbus_error_is_remote_error (error));
307 : 1 : g_error_free (error);
308 : 1 : g_assert_null (result);
309 : :
310 : 1 : g_main_loop_quit (loop);
311 : 1 : }
312 : :
313 : : static void
314 : 1 : msg_cb_expect_error_unknown_method (GDBusConnection *connection,
315 : : GAsyncResult *res,
316 : : gpointer user_data)
317 : : {
318 : : GError *error;
319 : : GVariant *result;
320 : :
321 : : /* Make sure gdbusconnection isn't holding @connection's lock. (#747349) */
322 : 1 : g_dbus_connection_get_last_serial (connection);
323 : :
324 : 1 : error = NULL;
325 : 1 : result = g_dbus_connection_call_finish (connection,
326 : : res,
327 : : &error);
328 : 1 : g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
329 : 1 : g_assert_true (g_dbus_error_is_remote_error (error));
330 : 1 : g_error_free (error);
331 : 1 : g_assert_null (result);
332 : :
333 : 1 : g_main_loop_quit (loop);
334 : 1 : }
335 : :
336 : : static void
337 : 1 : msg_cb_expect_success (GDBusConnection *connection,
338 : : GAsyncResult *res,
339 : : gpointer user_data)
340 : : {
341 : : GError *error;
342 : : GVariant *result;
343 : :
344 : : /* Make sure gdbusconnection isn't holding @connection's lock. (#747349) */
345 : 1 : g_dbus_connection_get_last_serial (connection);
346 : :
347 : 1 : error = NULL;
348 : 1 : result = g_dbus_connection_call_finish (connection,
349 : : res,
350 : : &error);
351 : 1 : g_assert_no_error (error);
352 : 1 : g_assert_nonnull (result);
353 : 1 : g_variant_unref (result);
354 : :
355 : 1 : g_main_loop_quit (loop);
356 : 1 : }
357 : :
358 : : static void
359 : 1 : msg_cb_expect_error_cancelled (GDBusConnection *connection,
360 : : GAsyncResult *res,
361 : : gpointer user_data)
362 : : {
363 : : GError *error;
364 : : GVariant *result;
365 : :
366 : : /* Make sure gdbusconnection isn't holding @connection's lock. (#747349) */
367 : 1 : g_dbus_connection_get_last_serial (connection);
368 : :
369 : 1 : error = NULL;
370 : 1 : result = g_dbus_connection_call_finish (connection,
371 : : res,
372 : : &error);
373 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
374 : 1 : g_assert_false (g_dbus_error_is_remote_error (error));
375 : 1 : g_error_free (error);
376 : 1 : g_assert_null (result);
377 : :
378 : 1 : g_main_loop_quit (loop);
379 : 1 : }
380 : :
381 : : static void
382 : 1 : msg_cb_expect_error_cancelled_2 (GDBusConnection *connection,
383 : : GAsyncResult *res,
384 : : gpointer user_data)
385 : : {
386 : : GError *error;
387 : : GVariant *result;
388 : :
389 : : /* Make sure gdbusconnection isn't holding @connection's lock. (#747349) */
390 : 1 : g_dbus_connection_get_last_serial (connection);
391 : :
392 : 1 : error = NULL;
393 : 1 : result = g_dbus_connection_call_finish (connection,
394 : : res,
395 : : &error);
396 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
397 : 1 : g_assert_false (g_dbus_error_is_remote_error (error));
398 : 1 : g_error_free (error);
399 : 1 : g_assert_null (result);
400 : :
401 : 1 : g_main_loop_quit (loop);
402 : 1 : }
403 : :
404 : : /* ---------------------------------------------------------------------------------------------------- */
405 : :
406 : : static void
407 : 1 : test_connection_send (void)
408 : : {
409 : : GDBusConnection *c;
410 : : GCancellable *ca;
411 : :
412 : 1 : session_bus_up ();
413 : :
414 : : /* First, get an unopened connection */
415 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
416 : 1 : g_assert_nonnull (c);
417 : 1 : g_assert_false (g_dbus_connection_is_closed (c));
418 : :
419 : : /*
420 : : * Check that we never actually send a message if the GCancellable
421 : : * is already cancelled - i.e. we should get G_IO_ERROR_CANCELLED
422 : : * when the actual connection is not up.
423 : : */
424 : 1 : ca = g_cancellable_new ();
425 : 1 : g_cancellable_cancel (ca);
426 : 1 : g_dbus_connection_call (c,
427 : : "org.freedesktop.DBus", /* bus_name */
428 : : "/org/freedesktop/DBus", /* object path */
429 : : "org.freedesktop.DBus", /* interface name */
430 : : "GetId", /* method name */
431 : : NULL, NULL,
432 : : G_DBUS_CALL_FLAGS_NONE,
433 : : -1,
434 : : ca,
435 : : (GAsyncReadyCallback) msg_cb_expect_error_cancelled,
436 : : NULL);
437 : 1 : g_main_loop_run (loop);
438 : 1 : g_object_unref (ca);
439 : :
440 : : /*
441 : : * Check that we get a reply to the GetId() method call.
442 : : */
443 : 1 : g_dbus_connection_call (c,
444 : : "org.freedesktop.DBus", /* bus_name */
445 : : "/org/freedesktop/DBus", /* object path */
446 : : "org.freedesktop.DBus", /* interface name */
447 : : "GetId", /* method name */
448 : : NULL, NULL,
449 : : G_DBUS_CALL_FLAGS_NONE,
450 : : -1,
451 : : NULL,
452 : : (GAsyncReadyCallback) msg_cb_expect_success,
453 : : NULL);
454 : 1 : g_main_loop_run (loop);
455 : :
456 : : /*
457 : : * Check that we get an error reply to the NonExistantMethod() method call.
458 : : */
459 : 1 : g_dbus_connection_call (c,
460 : : "org.freedesktop.DBus", /* bus_name */
461 : : "/org/freedesktop/DBus", /* object path */
462 : : "org.freedesktop.DBus", /* interface name */
463 : : "NonExistantMethod", /* method name */
464 : : NULL, NULL,
465 : : G_DBUS_CALL_FLAGS_NONE,
466 : : -1,
467 : : NULL,
468 : : (GAsyncReadyCallback) msg_cb_expect_error_unknown_method,
469 : : NULL);
470 : 1 : g_main_loop_run (loop);
471 : :
472 : : /*
473 : : * Check that cancellation works when the message is already in flight.
474 : : */
475 : 1 : ca = g_cancellable_new ();
476 : 1 : g_dbus_connection_call (c,
477 : : "org.freedesktop.DBus", /* bus_name */
478 : : "/org/freedesktop/DBus", /* object path */
479 : : "org.freedesktop.DBus", /* interface name */
480 : : "GetId", /* method name */
481 : : NULL, NULL,
482 : : G_DBUS_CALL_FLAGS_NONE,
483 : : -1,
484 : : ca,
485 : : (GAsyncReadyCallback) msg_cb_expect_error_cancelled_2,
486 : : NULL);
487 : 1 : g_cancellable_cancel (ca);
488 : 1 : g_main_loop_run (loop);
489 : 1 : g_object_unref (ca);
490 : :
491 : : /*
492 : : * Check that we get an error when sending to a connection that is disconnected.
493 : : */
494 : 1 : g_dbus_connection_set_exit_on_close (c, FALSE);
495 : 1 : session_bus_stop ();
496 : 1 : _g_assert_signal_received (c, "closed");
497 : 1 : g_assert_true (g_dbus_connection_is_closed (c));
498 : :
499 : 1 : g_dbus_connection_call (c,
500 : : "org.freedesktop.DBus", /* bus_name */
501 : : "/org/freedesktop/DBus", /* object path */
502 : : "org.freedesktop.DBus", /* interface name */
503 : : "GetId", /* method name */
504 : : NULL, NULL,
505 : : G_DBUS_CALL_FLAGS_NONE,
506 : : -1,
507 : : NULL,
508 : : (GAsyncReadyCallback) msg_cb_expect_error_disconnected,
509 : : NULL);
510 : 1 : g_main_loop_run (loop);
511 : :
512 : 1 : g_object_unref (c);
513 : :
514 : 1 : session_bus_down ();
515 : 1 : }
516 : :
517 : : /* ---------------------------------------------------------------------------------------------------- */
518 : : /* Connection signal tests */
519 : : /* ---------------------------------------------------------------------------------------------------- */
520 : :
521 : : static void
522 : 35 : test_connection_signal_handler (GDBusConnection *connection,
523 : : const gchar *sender_name,
524 : : const gchar *object_path,
525 : : const gchar *interface_name,
526 : : const gchar *signal_name,
527 : : GVariant *parameters,
528 : : gpointer user_data)
529 : : {
530 : 35 : gint *counter = user_data;
531 : 35 : *counter += 1;
532 : :
533 : : /*g_debug ("in test_connection_signal_handler (sender=%s path=%s interface=%s member=%s)",
534 : : sender_name,
535 : : object_path,
536 : : interface_name,
537 : : signal_name);*/
538 : :
539 : 35 : g_main_loop_quit (loop);
540 : 35 : }
541 : :
542 : : static void
543 : 1 : test_connection_signals (void)
544 : : {
545 : : GDBusConnection *c1;
546 : : GDBusConnection *c2;
547 : : GDBusConnection *c3;
548 : : guint s1;
549 : : guint s1b;
550 : : guint s2;
551 : : guint s3;
552 : : gint count_s1;
553 : : gint count_s1b;
554 : : gint count_s2;
555 : : gint count_name_owner_changed;
556 : : GError *error;
557 : : gboolean ret;
558 : : GVariant *result;
559 : : gboolean quit_mainloop_fired;
560 : : guint quit_mainloop_id;
561 : :
562 : 1 : error = NULL;
563 : :
564 : : /*
565 : : * Bring up first separate connections
566 : : */
567 : 1 : session_bus_up ();
568 : : /* if running with dbus-monitor, it claims the name :1.0 - so if we don't run with the monitor
569 : : * emulate this
570 : : */
571 [ + - ]: 1 : if (g_getenv ("G_DBUS_MONITOR") == NULL)
572 : : {
573 : 1 : c1 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
574 : 1 : g_assert_nonnull (c1);
575 : 1 : g_assert_false (g_dbus_connection_is_closed (c1));
576 : 1 : g_object_unref (c1);
577 : : }
578 : 1 : c1 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
579 : 1 : g_assert_nonnull (c1);
580 : 1 : g_assert_false (g_dbus_connection_is_closed (c1));
581 : 1 : g_assert_cmpstr (g_dbus_connection_get_unique_name (c1), ==, ":1.1");
582 : :
583 : : /*
584 : : * Install two signal handlers for the first connection
585 : : *
586 : : * - Listen to the signal "Foo" from :1.2 (e.g. c2)
587 : : * - Listen to the signal "Foo" from anyone (e.g. both c2 and c3)
588 : : *
589 : : * and then count how many times this signal handler was invoked.
590 : : */
591 : 1 : s1 = g_dbus_connection_signal_subscribe (c1,
592 : : ":1.2",
593 : : "org.gtk.GDBus.ExampleInterface",
594 : : "Foo",
595 : : "/org/gtk/GDBus/ExampleInterface",
596 : : NULL,
597 : : G_DBUS_SIGNAL_FLAGS_NONE,
598 : : test_connection_signal_handler,
599 : : &count_s1,
600 : : NULL);
601 : 1 : s2 = g_dbus_connection_signal_subscribe (c1,
602 : : NULL, /* match any sender */
603 : : "org.gtk.GDBus.ExampleInterface",
604 : : "Foo",
605 : : "/org/gtk/GDBus/ExampleInterface",
606 : : NULL,
607 : : G_DBUS_SIGNAL_FLAGS_NONE,
608 : : test_connection_signal_handler,
609 : : &count_s2,
610 : : NULL);
611 : 1 : s3 = g_dbus_connection_signal_subscribe (c1,
612 : : "org.freedesktop.DBus", /* sender */
613 : : "org.freedesktop.DBus", /* interface */
614 : : "NameOwnerChanged", /* member */
615 : : "/org/freedesktop/DBus", /* path */
616 : : NULL,
617 : : G_DBUS_SIGNAL_FLAGS_NONE,
618 : : test_connection_signal_handler,
619 : : &count_name_owner_changed,
620 : : NULL);
621 : : /* Note that s1b is *just like* s1 - this is to catch a bug where N
622 : : * subscriptions of the same rule causes N calls to each of the N
623 : : * subscriptions instead of just 1 call to each of the N subscriptions.
624 : : */
625 : 1 : s1b = g_dbus_connection_signal_subscribe (c1,
626 : : ":1.2",
627 : : "org.gtk.GDBus.ExampleInterface",
628 : : "Foo",
629 : : "/org/gtk/GDBus/ExampleInterface",
630 : : NULL,
631 : : G_DBUS_SIGNAL_FLAGS_NONE,
632 : : test_connection_signal_handler,
633 : : &count_s1b,
634 : : NULL);
635 : 1 : g_assert_cmpuint (s1, !=, 0);
636 : 1 : g_assert_cmpuint (s1b, !=, 0);
637 : 1 : g_assert_cmpuint (s2, !=, 0);
638 : 1 : g_assert_cmpuint (s3, !=, 0);
639 : :
640 : 1 : count_s1 = 0;
641 : 1 : count_s1b = 0;
642 : 1 : count_s2 = 0;
643 : 1 : count_name_owner_changed = 0;
644 : :
645 : : /*
646 : : * Make c2 emit "Foo" - we should catch it twice
647 : : *
648 : : * Note that there is no way to be sure that the signal subscriptions
649 : : * on c1 are effective yet - for all we know, the AddMatch() messages
650 : : * could sit waiting in a buffer somewhere between this process and
651 : : * the message bus. And emitting signals on c2 (a completely other
652 : : * socket!) will not necessarily change this.
653 : : *
654 : : * To ensure this is not the case, do a synchronous call on c1.
655 : : */
656 : 1 : result = g_dbus_connection_call_sync (c1,
657 : : "org.freedesktop.DBus", /* bus name */
658 : : "/org/freedesktop/DBus", /* object path */
659 : : "org.freedesktop.DBus", /* interface name */
660 : : "GetId", /* method name */
661 : : NULL, /* parameters */
662 : : NULL, /* return type */
663 : : G_DBUS_CALL_FLAGS_NONE,
664 : : -1,
665 : : NULL,
666 : : &error);
667 : 1 : g_assert_no_error (error);
668 : 1 : g_assert_nonnull (result);
669 : 1 : g_variant_unref (result);
670 : :
671 : : /*
672 : : * Bring up two other connections
673 : : */
674 : 1 : c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
675 : 1 : g_assert_nonnull (c2);
676 : 1 : g_assert_false (g_dbus_connection_is_closed (c2));
677 : 1 : g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
678 : 1 : c3 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
679 : 1 : g_assert_nonnull (c3);
680 : 1 : g_assert_false (g_dbus_connection_is_closed (c3));
681 : 1 : g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
682 : :
683 : : /* now, emit the signal on c2 */
684 : 1 : ret = g_dbus_connection_emit_signal (c2,
685 : : NULL, /* destination bus name */
686 : : "/org/gtk/GDBus/ExampleInterface",
687 : : "org.gtk.GDBus.ExampleInterface",
688 : : "Foo",
689 : : NULL,
690 : : &error);
691 : 1 : g_assert_no_error (error);
692 : 1 : g_assert_true (ret);
693 [ + + + + ]: 4 : while (!(count_s1 >= 1 && count_s2 >= 1))
694 : 3 : g_main_loop_run (loop);
695 : 1 : g_assert_cmpint (count_s1, ==, 1);
696 : 1 : g_assert_cmpint (count_s2, ==, 1);
697 : :
698 : : /*
699 : : * Make c3 emit "Foo" - we should catch it only once
700 : : */
701 : 1 : ret = g_dbus_connection_emit_signal (c3,
702 : : NULL, /* destination bus name */
703 : : "/org/gtk/GDBus/ExampleInterface",
704 : : "org.gtk.GDBus.ExampleInterface",
705 : : "Foo",
706 : : NULL,
707 : : &error);
708 : 1 : g_assert_no_error (error);
709 : 1 : g_assert_true (ret);
710 [ - + + + ]: 2 : while (!(count_s1 == 1 && count_s2 == 2))
711 : 1 : g_main_loop_run (loop);
712 : 1 : g_assert_cmpint (count_s1, ==, 1);
713 : 1 : g_assert_cmpint (count_s2, ==, 2);
714 : :
715 : : /*
716 : : * Also to check the total amount of NameOwnerChanged signals - use a 5 second ceiling
717 : : * to avoid spinning forever
718 : : */
719 : 1 : quit_mainloop_fired = FALSE;
720 : 1 : quit_mainloop_id = g_timeout_add (30000, test_connection_quit_mainloop, &quit_mainloop_fired);
721 [ - + - - ]: 1 : while (count_name_owner_changed < 2 && !quit_mainloop_fired)
722 : 0 : g_main_loop_run (loop);
723 : 1 : g_source_remove (quit_mainloop_id);
724 : 1 : g_assert_cmpint (count_s1, ==, 1);
725 : 1 : g_assert_cmpint (count_s2, ==, 2);
726 : 1 : g_assert_cmpint (count_name_owner_changed, ==, 2);
727 : :
728 : 1 : g_dbus_connection_signal_unsubscribe (c1, s1);
729 : 1 : g_dbus_connection_signal_unsubscribe (c1, s2);
730 : 1 : g_dbus_connection_signal_unsubscribe (c1, s3);
731 : 1 : g_dbus_connection_signal_unsubscribe (c1, s1b);
732 : :
733 : 1 : g_object_unref (c1);
734 : 1 : g_object_unref (c2);
735 : 1 : g_object_unref (c3);
736 : :
737 : 1 : session_bus_down ();
738 : 1 : }
739 : :
740 : : static void
741 : 19 : test_match_rule (GDBusConnection *connection,
742 : : GDBusSignalFlags flags,
743 : : gchar *arg0_rule,
744 : : gchar *arg0,
745 : : const gchar *signal_type,
746 : : gboolean should_match)
747 : : {
748 : : guint subscription_ids[2];
749 : 19 : gint emissions = 0;
750 : 19 : gint matches = 0;
751 : 19 : GError *error = NULL;
752 : :
753 : 19 : subscription_ids[0] = g_dbus_connection_signal_subscribe (connection,
754 : : NULL, "org.gtk.ExampleInterface", "Foo", "/",
755 : : NULL,
756 : : G_DBUS_SIGNAL_FLAGS_NONE,
757 : : test_connection_signal_handler,
758 : : &emissions, NULL);
759 : 19 : subscription_ids[1] = g_dbus_connection_signal_subscribe (connection,
760 : : NULL, "org.gtk.ExampleInterface", "Foo", "/",
761 : : arg0_rule,
762 : : flags,
763 : : test_connection_signal_handler,
764 : : &matches, NULL);
765 : 19 : g_assert_cmpint (subscription_ids[0], !=, 0);
766 : 19 : g_assert_cmpint (subscription_ids[1], !=, 0);
767 : :
768 : 19 : g_dbus_connection_emit_signal (connection,
769 : : NULL, "/", "org.gtk.ExampleInterface",
770 : : "Foo", g_variant_new (signal_type, arg0),
771 : : &error);
772 : 19 : g_assert_no_error (error);
773 : :
774 : : /* synchronously ping a non-existent method to make sure the signals are dispatched */
775 : 19 : g_dbus_connection_call_sync (connection, "org.gtk.ExampleInterface", "/", "org.gtk.ExampleInterface",
776 : : "Bar", g_variant_new ("()"), G_VARIANT_TYPE_UNIT, G_DBUS_CALL_FLAGS_NONE,
777 : : -1, NULL, NULL);
778 : :
779 [ + + ]: 38 : while (g_main_context_iteration (NULL, FALSE))
780 : : ;
781 : :
782 : 19 : g_assert_cmpint (emissions, ==, 1);
783 : 19 : g_assert_cmpint (matches, ==, should_match ? 1 : 0);
784 : :
785 : 19 : g_dbus_connection_signal_unsubscribe (connection, subscription_ids[0]);
786 : 19 : g_dbus_connection_signal_unsubscribe (connection, subscription_ids[1]);
787 : 19 : }
788 : :
789 : : static void
790 : 1 : test_connection_signal_match_rules (void)
791 : : {
792 : : GDBusConnection *con;
793 : :
794 : 1 : session_bus_up ();
795 : 1 : con = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
796 : :
797 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "foo", "(s)", TRUE);
798 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "bar", "(s)", FALSE);
799 : :
800 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "", "(s)", FALSE);
801 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org", "(s)", FALSE);
802 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk", "(s)", TRUE);
803 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk.Example", "(s)", TRUE);
804 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk+", "(s)", FALSE);
805 : :
806 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(s)", TRUE);
807 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "", "(s)", FALSE);
808 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(s)", TRUE);
809 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(s)", TRUE);
810 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/", "(s)", TRUE);
811 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(s)", FALSE);
812 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(s)", FALSE);
813 : :
814 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(o)", TRUE);
815 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(o)", TRUE);
816 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(o)", TRUE);
817 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(o)", FALSE);
818 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(o)", FALSE);
819 : :
820 : 1 : g_object_unref (con);
821 : 1 : session_bus_down ();
822 : 1 : }
823 : :
824 : : /* ---------------------------------------------------------------------------------------------------- */
825 : :
826 : : /* Accessed both from the test code and the filter function (in a worker thread)
827 : : * so all accesses must be atomic. */
828 : : typedef struct
829 : : {
830 : : GAsyncQueue *incoming_queue; /* (element-type GDBusMessage) */
831 : : guint num_outgoing; /* (atomic) */
832 : : } FilterData;
833 : :
834 : : /* Runs in a worker thread. */
835 : : static GDBusMessage *
836 : 9 : filter_func (GDBusConnection *connection,
837 : : GDBusMessage *message,
838 : : gboolean incoming,
839 : : gpointer user_data)
840 : : {
841 : 9 : FilterData *data = user_data;
842 : :
843 [ + + ]: 9 : if (incoming)
844 : 5 : g_async_queue_push (data->incoming_queue, g_object_ref (message));
845 : : else
846 : 4 : g_atomic_int_inc (&data->num_outgoing);
847 : :
848 : 9 : return message;
849 : : }
850 : :
851 : : static void
852 : 4 : wait_for_filtered_reply (GAsyncQueue *incoming_queue,
853 : : guint32 expected_serial)
854 : : {
855 : 4 : GDBusMessage *popped_message = NULL;
856 : :
857 [ + - ]: 5 : while ((popped_message = g_async_queue_pop (incoming_queue)) != NULL)
858 : : {
859 : 5 : guint32 reply_serial = g_dbus_message_get_reply_serial (popped_message);
860 : 5 : g_object_unref (popped_message);
861 [ + + ]: 5 : if (reply_serial == expected_serial)
862 : 4 : return;
863 : : }
864 : :
865 : : g_assert_not_reached ();
866 : : }
867 : :
868 : : typedef struct
869 : : {
870 : : gboolean alter_incoming;
871 : : gboolean alter_outgoing;
872 : : } FilterEffects;
873 : :
874 : : /* Runs in a worker thread. */
875 : : static GDBusMessage *
876 : 6 : other_filter_func (GDBusConnection *connection,
877 : : GDBusMessage *message,
878 : : gboolean incoming,
879 : : gpointer user_data)
880 : : {
881 : 6 : const FilterEffects *effects = user_data;
882 : : GDBusMessage *ret;
883 : : gboolean alter;
884 : :
885 [ + + ]: 6 : if (incoming)
886 : 3 : alter = effects->alter_incoming;
887 : : else
888 : 3 : alter = effects->alter_outgoing;
889 : :
890 [ + + ]: 6 : if (alter)
891 : : {
892 : : GDBusMessage *copy;
893 : : GVariant *body;
894 : : gchar *s;
895 : : gchar *s2;
896 : :
897 : 2 : copy = g_dbus_message_copy (message, NULL);
898 : 2 : g_object_unref (message);
899 : :
900 : 2 : body = g_dbus_message_get_body (copy);
901 : 2 : g_variant_get (body, "(s)", &s);
902 : 2 : s2 = g_strdup_printf ("MOD: %s", s);
903 : 2 : g_dbus_message_set_body (copy, g_variant_new ("(s)", s2));
904 : 2 : g_free (s2);
905 : 2 : g_free (s);
906 : :
907 : 2 : ret = copy;
908 : : }
909 : : else
910 : : {
911 : 4 : ret = message;
912 : : }
913 : :
914 : 6 : return ret;
915 : : }
916 : :
917 : : static void
918 : 2 : test_connection_filter_name_owner_changed_signal_handler (GDBusConnection *connection,
919 : : const gchar *sender_name,
920 : : const gchar *object_path,
921 : : const gchar *interface_name,
922 : : const gchar *signal_name,
923 : : GVariant *parameters,
924 : : gpointer user_data)
925 : : {
926 : : const gchar *name;
927 : : const gchar *old_owner;
928 : : const gchar *new_owner;
929 : :
930 : 2 : g_variant_get (parameters,
931 : : "(&s&s&s)",
932 : : &name,
933 : : &old_owner,
934 : : &new_owner);
935 : :
936 [ + + + - ]: 2 : if (g_strcmp0 (name, "com.example.TestService") == 0 && strlen (new_owner) > 0)
937 : : {
938 : 1 : g_main_loop_quit (loop);
939 : : }
940 : 2 : }
941 : :
942 : : static gboolean
943 : 0 : test_connection_filter_on_timeout (gpointer user_data)
944 : : {
945 : 0 : g_printerr ("Timeout waiting 30 sec on service\n");
946 : : g_assert_not_reached ();
947 : : return G_SOURCE_REMOVE;
948 : : }
949 : :
950 : : static void
951 : 1 : test_connection_filter (void)
952 : : {
953 : : GDBusConnection *c;
954 : 1 : FilterData data = { NULL, 0 };
955 : : GDBusMessage *m;
956 : : GDBusMessage *m2;
957 : : GDBusMessage *r;
958 : : GError *error;
959 : : guint filter_id;
960 : : guint timeout_mainloop_id;
961 : : guint signal_handler_id;
962 : : FilterEffects effects;
963 : : GVariant *result;
964 : : const gchar *s;
965 : : guint32 serial_temp;
966 : :
967 : 1 : session_bus_up ();
968 : :
969 : 1 : error = NULL;
970 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
971 : 1 : g_assert_no_error (error);
972 : 1 : g_assert_nonnull (c);
973 : :
974 : 1 : data.incoming_queue = g_async_queue_new_full (g_object_unref);
975 : 1 : data.num_outgoing = 0;
976 : 1 : filter_id = g_dbus_connection_add_filter (c,
977 : : filter_func,
978 : : &data,
979 : : NULL);
980 : :
981 : 1 : m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
982 : : "/org/freedesktop/DBus", /* path */
983 : : "org.freedesktop.DBus", /* interface */
984 : : "GetNameOwner");
985 : 1 : g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
986 : 1 : error = NULL;
987 : 1 : g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &serial_temp, &error);
988 : 1 : g_assert_no_error (error);
989 : :
990 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
991 : :
992 : 1 : m2 = g_dbus_message_copy (m, &error);
993 : 1 : g_assert_no_error (error);
994 : 1 : g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &serial_temp, &error);
995 : 1 : g_object_unref (m2);
996 : 1 : g_assert_no_error (error);
997 : :
998 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
999 : :
1000 : 1 : m2 = g_dbus_message_copy (m, &error);
1001 : 1 : g_assert_no_error (error);
1002 : 1 : g_dbus_message_set_serial (m2, serial_temp);
1003 : : /* lock the message to test PRESERVE_SERIAL flag. */
1004 : 1 : g_dbus_message_lock (m2);
1005 : 1 : g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL, &serial_temp, &error);
1006 : 1 : g_object_unref (m2);
1007 : 1 : g_assert_no_error (error);
1008 : :
1009 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
1010 : :
1011 : 1 : m2 = g_dbus_message_copy (m, &error);
1012 : 1 : g_assert_no_error (error);
1013 : 1 : r = g_dbus_connection_send_message_with_reply_sync (c,
1014 : : m2,
1015 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1016 : : -1,
1017 : : &serial_temp,
1018 : : NULL, /* GCancellable */
1019 : : &error);
1020 : 1 : g_object_unref (m2);
1021 : 1 : g_assert_no_error (error);
1022 : 1 : g_assert_nonnull (r);
1023 : 1 : g_object_unref (r);
1024 : :
1025 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
1026 : 1 : g_assert_cmpint (g_async_queue_length (data.incoming_queue), ==, 0);
1027 : :
1028 : 1 : g_dbus_connection_remove_filter (c, filter_id);
1029 : :
1030 : 1 : m2 = g_dbus_message_copy (m, &error);
1031 : 1 : g_assert_no_error (error);
1032 : 1 : r = g_dbus_connection_send_message_with_reply_sync (c,
1033 : : m2,
1034 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1035 : : -1,
1036 : : &serial_temp,
1037 : : NULL, /* GCancellable */
1038 : : &error);
1039 : 1 : g_object_unref (m2);
1040 : 1 : g_assert_no_error (error);
1041 : 1 : g_assert_nonnull (r);
1042 : 1 : g_object_unref (r);
1043 : 1 : g_assert_cmpint (g_async_queue_length (data.incoming_queue), ==, 0);
1044 : 1 : g_assert_cmpint (g_atomic_int_get (&data.num_outgoing), ==, 4);
1045 : :
1046 : : /* wait for service to be available */
1047 : 1 : signal_handler_id = g_dbus_connection_signal_subscribe (c,
1048 : : "org.freedesktop.DBus", /* sender */
1049 : : "org.freedesktop.DBus",
1050 : : "NameOwnerChanged",
1051 : : "/org/freedesktop/DBus",
1052 : : NULL, /* arg0 */
1053 : : G_DBUS_SIGNAL_FLAGS_NONE,
1054 : : test_connection_filter_name_owner_changed_signal_handler,
1055 : : NULL,
1056 : : NULL);
1057 : 1 : g_assert_cmpint (signal_handler_id, !=, 0);
1058 : :
1059 : : /* this is safe; testserver will exit once the bus goes away */
1060 : 1 : g_assert_true (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver", NULL), NULL));
1061 : :
1062 : 1 : timeout_mainloop_id = g_timeout_add (30000, test_connection_filter_on_timeout, NULL);
1063 : 1 : g_main_loop_run (loop);
1064 : 1 : g_source_remove (timeout_mainloop_id);
1065 : 1 : g_dbus_connection_signal_unsubscribe (c, signal_handler_id);
1066 : :
1067 : : /* now test some combinations... */
1068 : 1 : filter_id = g_dbus_connection_add_filter (c,
1069 : : other_filter_func,
1070 : : &effects,
1071 : : NULL);
1072 : : /* -- */
1073 : 1 : effects.alter_incoming = FALSE;
1074 : 1 : effects.alter_outgoing = FALSE;
1075 : 1 : error = NULL;
1076 : 1 : result = g_dbus_connection_call_sync (c,
1077 : : "com.example.TestService", /* bus name */
1078 : : "/com/example/TestObject", /* object path */
1079 : : "com.example.Frob", /* interface name */
1080 : : "HelloWorld", /* method name */
1081 : : g_variant_new ("(s)", "Cat"), /* parameters */
1082 : : G_VARIANT_TYPE ("(s)"), /* return type */
1083 : : G_DBUS_CALL_FLAGS_NONE,
1084 : : -1,
1085 : : NULL,
1086 : : &error);
1087 : 1 : g_assert_no_error (error);
1088 : 1 : g_variant_get (result, "(&s)", &s);
1089 : 1 : g_assert_cmpstr (s, ==, "You greeted me with 'Cat'. Thanks!");
1090 : 1 : g_variant_unref (result);
1091 : : /* -- */
1092 : 1 : effects.alter_incoming = TRUE;
1093 : 1 : effects.alter_outgoing = TRUE;
1094 : 1 : error = NULL;
1095 : 1 : result = g_dbus_connection_call_sync (c,
1096 : : "com.example.TestService", /* bus name */
1097 : : "/com/example/TestObject", /* object path */
1098 : : "com.example.Frob", /* interface name */
1099 : : "HelloWorld", /* method name */
1100 : : g_variant_new ("(s)", "Cat"), /* parameters */
1101 : : G_VARIANT_TYPE ("(s)"), /* return type */
1102 : : G_DBUS_CALL_FLAGS_NONE,
1103 : : -1,
1104 : : NULL,
1105 : : &error);
1106 : 1 : g_assert_no_error (error);
1107 : 1 : g_variant_get (result, "(&s)", &s);
1108 : 1 : g_assert_cmpstr (s, ==, "MOD: You greeted me with 'MOD: Cat'. Thanks!");
1109 : 1 : g_variant_unref (result);
1110 : :
1111 : :
1112 : 1 : g_dbus_connection_remove_filter (c, filter_id);
1113 : :
1114 : 1 : g_object_unref (c);
1115 : 1 : g_object_unref (m);
1116 : 1 : g_async_queue_unref (data.incoming_queue);
1117 : :
1118 : 1 : session_bus_down ();
1119 : 1 : }
1120 : :
1121 : : /* ---------------------------------------------------------------------------------------------------- */
1122 : :
1123 : : #define NUM_THREADS 50
1124 : :
1125 : : static void
1126 : 52 : send_bogus_message (GDBusConnection *c, guint32 *out_serial)
1127 : : {
1128 : : GDBusMessage *m;
1129 : : GError *error;
1130 : :
1131 : 52 : m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
1132 : : "/org/freedesktop/DBus", /* path */
1133 : : "org.freedesktop.DBus", /* interface */
1134 : : "GetNameOwner");
1135 : 52 : g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
1136 : 52 : error = NULL;
1137 : 52 : g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, out_serial, &error);
1138 : 52 : g_assert_no_error (error);
1139 : 52 : g_object_unref (m);
1140 : 52 : }
1141 : :
1142 : : #define SLEEP_USEC (100 * 1000)
1143 : :
1144 : : static gpointer
1145 : 50 : serials_thread_func (GDBusConnection *c)
1146 : : {
1147 : : guint32 message_serial;
1148 : : guint i;
1149 : :
1150 : : /* No calls on this thread yet */
1151 : 50 : g_assert_cmpint (g_dbus_connection_get_last_serial(c), ==, 0);
1152 : :
1153 : : /* Send a bogus message and store its serial */
1154 : 50 : message_serial = 0;
1155 : 50 : send_bogus_message (c, &message_serial);
1156 : :
1157 : : /* Give it some time to actually send the message out. 10 seconds
1158 : : * should be plenty, even on slow machines. */
1159 [ + - ]: 50 : for (i = 0; i < 10 * G_USEC_PER_SEC / SLEEP_USEC; i++)
1160 : : {
1161 [ + - ]: 50 : if (g_dbus_connection_get_last_serial(c) != 0)
1162 : 50 : break;
1163 : :
1164 : 0 : g_usleep (SLEEP_USEC);
1165 : : }
1166 : :
1167 : 50 : g_assert_cmpint (g_dbus_connection_get_last_serial(c), !=, 0);
1168 : 50 : g_assert_cmpint (g_dbus_connection_get_last_serial(c), ==, message_serial);
1169 : :
1170 : 50 : return NULL;
1171 : : }
1172 : :
1173 : : static void
1174 : 1 : test_connection_serials (void)
1175 : : {
1176 : : GDBusConnection *c;
1177 : : GError *error;
1178 : : GThread *pool[NUM_THREADS];
1179 : : int i;
1180 : :
1181 : 1 : session_bus_up ();
1182 : :
1183 : 1 : error = NULL;
1184 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1185 : 1 : g_assert_no_error (error);
1186 : 1 : g_assert_nonnull (c);
1187 : :
1188 : : /* Status after initialization */
1189 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 1);
1190 : :
1191 : : /* Send a bogus message */
1192 : 1 : send_bogus_message (c, NULL);
1193 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 2);
1194 : :
1195 : : /* Start the threads */
1196 [ + + ]: 51 : for (i = 0; i < NUM_THREADS; i++)
1197 : 50 : pool[i] = g_thread_new (NULL, (GThreadFunc) serials_thread_func, c);
1198 : :
1199 : : /* Wait until threads are finished */
1200 [ + + ]: 51 : for (i = 0; i < NUM_THREADS; i++)
1201 : 50 : g_thread_join (pool[i]);
1202 : :
1203 : : /* No calls in between on this thread, should be the last value */
1204 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 2);
1205 : :
1206 : 1 : send_bogus_message (c, NULL);
1207 : :
1208 : : /* All above calls + calls in threads */
1209 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 3 + NUM_THREADS);
1210 : :
1211 : 1 : g_object_unref (c);
1212 : :
1213 : 1 : session_bus_down ();
1214 : 1 : }
1215 : :
1216 : : /* ---------------------------------------------------------------------------------------------------- */
1217 : :
1218 : : static void
1219 : 1 : get_connection_cb_expect_cancel (GObject *source_object,
1220 : : GAsyncResult *res,
1221 : : gpointer user_data)
1222 : : {
1223 : : GDBusConnection *c;
1224 : : GError *error;
1225 : :
1226 : 1 : error = NULL;
1227 : 1 : c = g_bus_get_finish (res, &error);
1228 : :
1229 : : /* unref here to avoid timeouts when the test fails */
1230 [ - + ]: 1 : if (c)
1231 : 0 : g_object_unref (c);
1232 : :
1233 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1234 : 1 : g_assert_null (c);
1235 : :
1236 : 1 : g_error_free (error);
1237 : 1 : }
1238 : :
1239 : : static void
1240 : 1 : get_connection_cb_expect_success (GObject *source_object,
1241 : : GAsyncResult *res,
1242 : : gpointer user_data)
1243 : : {
1244 : : GDBusConnection *c;
1245 : : GError *error;
1246 : :
1247 : 1 : error = NULL;
1248 : 1 : c = g_bus_get_finish (res, &error);
1249 : 1 : g_assert_no_error (error);
1250 : 1 : g_assert_nonnull (c);
1251 : :
1252 : 1 : g_main_loop_quit (loop);
1253 : :
1254 : 1 : g_object_unref (c);
1255 : 1 : }
1256 : :
1257 : : static void
1258 : 1 : test_connection_cancel (void)
1259 : : {
1260 : : GCancellable *cancellable, *cancellable2;
1261 : :
1262 : 1 : g_test_summary ("Test that cancelling one of two racing g_bus_get() calls does not cancel the other one");
1263 : :
1264 : 1 : session_bus_up ();
1265 : :
1266 : 1 : cancellable = g_cancellable_new ();
1267 : 1 : cancellable2 = g_cancellable_new ();
1268 : :
1269 : 1 : g_bus_get (G_BUS_TYPE_SESSION, cancellable, get_connection_cb_expect_cancel, NULL);
1270 : 1 : g_bus_get (G_BUS_TYPE_SESSION, cancellable2, get_connection_cb_expect_success, NULL);
1271 : 1 : g_cancellable_cancel (cancellable);
1272 : 1 : g_main_loop_run (loop);
1273 : :
1274 : 1 : g_object_unref (cancellable);
1275 : 1 : g_object_unref (cancellable2);
1276 : :
1277 : 1 : session_bus_down ();
1278 : 1 : }
1279 : :
1280 : : /* ---------------------------------------------------------------------------------------------------- */
1281 : :
1282 : : static void
1283 : 1 : test_connection_basic (void)
1284 : : {
1285 : : GDBusConnection *connection;
1286 : : GError *error;
1287 : : GDBusCapabilityFlags flags;
1288 : : GDBusConnectionFlags connection_flags;
1289 : : gchar *guid;
1290 : : gchar *name;
1291 : : gboolean closed;
1292 : : gboolean exit_on_close;
1293 : : GIOStream *stream;
1294 : : GCredentials *credentials;
1295 : :
1296 : 1 : session_bus_up ();
1297 : :
1298 : 1 : error = NULL;
1299 : 1 : connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1300 : 1 : g_assert_no_error (error);
1301 : 1 : g_assert_nonnull (connection);
1302 : :
1303 : 1 : flags = g_dbus_connection_get_capabilities (connection);
1304 : 1 : g_assert_true (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
1305 : : flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1306 : :
1307 : 1 : connection_flags = g_dbus_connection_get_flags (connection);
1308 : : /* Ignore G_DBUS_CONNECTION_FLAGS_CROSS_NAMESPACE, it's an
1309 : : * implementation detail whether we set it */
1310 : 1 : connection_flags &= ~G_DBUS_CONNECTION_FLAGS_CROSS_NAMESPACE;
1311 : 1 : g_assert_cmpint (connection_flags, ==,
1312 : : G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
1313 : : G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION);
1314 : :
1315 : 1 : credentials = g_dbus_connection_get_peer_credentials (connection);
1316 : 1 : g_assert_null (credentials);
1317 : :
1318 : 1 : g_object_get (connection,
1319 : : "stream", &stream,
1320 : : "guid", &guid,
1321 : : "unique-name", &name,
1322 : : "closed", &closed,
1323 : : "exit-on-close", &exit_on_close,
1324 : : "capabilities", &flags,
1325 : : NULL);
1326 : :
1327 : 1 : g_assert_true (G_IS_IO_STREAM (stream));
1328 : 1 : g_assert_true (g_dbus_is_guid (guid));
1329 : 1 : g_assert_true (g_dbus_is_unique_name (name));
1330 : 1 : g_assert_false (closed);
1331 : 1 : g_assert_true (exit_on_close);
1332 : 1 : g_assert_true (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
1333 : : flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1334 : 1 : g_object_unref (stream);
1335 : 1 : g_free (name);
1336 : 1 : g_free (guid);
1337 : :
1338 : 1 : g_object_unref (connection);
1339 : :
1340 : 1 : session_bus_down ();
1341 : 1 : }
1342 : :
1343 : : /* ---------------------------------------------------------------------------------------------------- */
1344 : :
1345 : : int
1346 : 1 : main (int argc,
1347 : : char *argv[])
1348 : : {
1349 : : int ret;
1350 : :
1351 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1352 : :
1353 : : /* all the tests rely on a shared main loop */
1354 : 1 : loop = g_main_loop_new (NULL, FALSE);
1355 : :
1356 : 1 : g_test_dbus_unset ();
1357 : :
1358 : : /* gdbus cleanup is pretty racy due to worker threads, so always do this test first */
1359 : 1 : g_test_add_func ("/gdbus/connection/bus-failure", test_connection_bus_failure);
1360 : :
1361 : 1 : g_test_add_func ("/gdbus/connection/basic", test_connection_basic);
1362 : 1 : g_test_add_func ("/gdbus/connection/life-cycle", test_connection_life_cycle);
1363 : 1 : g_test_add_func ("/gdbus/connection/send", test_connection_send);
1364 : 1 : g_test_add_func ("/gdbus/connection/signals", test_connection_signals);
1365 : 1 : g_test_add_func ("/gdbus/connection/signal-match-rules", test_connection_signal_match_rules);
1366 : 1 : g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
1367 : 1 : g_test_add_func ("/gdbus/connection/serials", test_connection_serials);
1368 : 1 : g_test_add_func ("/gdbus/connection/cancel", test_connection_cancel);
1369 : 1 : ret = g_test_run();
1370 : :
1371 : 1 : g_main_loop_unref (loop);
1372 : 1 : return ret;
1373 : : }
|