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