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 : 0 : some_filter_func (GDBusConnection *connection,
99 : : GDBusMessage *message,
100 : : gboolean incoming,
101 : : gpointer user_data)
102 : : {
103 : 0 : 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 : 2 : if (g_atomic_int_get (&on_signal_registration_freed_called) &&
258 : 1 : g_atomic_int_get (&on_filter_freed_called) &&
259 : 1 : g_atomic_int_get (&on_register_object_freed_called))
260 : 1 : break;
261 : 1 : if (g_atomic_int_get (&quit_mainloop_fired))
262 : 0 : break;
263 : : _log ("entering loop");
264 : 1 : 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_PRIORITY_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_assert_cmpuint (s1, !=, 0);
797 : 1 : g_clear_dbus_signal_subscription (&s1, c1);
798 : 1 : g_assert_cmpuint (s1, ==, 0);
799 : : /* g_clear_dbus_signal_subscription() is idempotent, with no warnings */
800 : 1 : g_clear_dbus_signal_subscription (&s1, c1);
801 : 1 : g_assert_cmpuint (s1, ==, 0);
802 : :
803 : 1 : g_clear_dbus_signal_subscription (&s2, c1);
804 : 1 : g_clear_dbus_signal_subscription (&s3, c1);
805 : 1 : g_clear_dbus_signal_subscription (&s1b, c1);
806 : 1 : g_clear_dbus_signal_subscription (&s4, c1);
807 : 1 : g_clear_dbus_signal_subscription (&s5, c1);
808 : :
809 : 1 : g_object_unref (c1);
810 : 1 : g_object_unref (c2);
811 : 1 : g_object_unref (c3);
812 : :
813 : 1 : session_bus_down ();
814 : 1 : }
815 : :
816 : : static void
817 : 19 : test_match_rule (GDBusConnection *connection,
818 : : GDBusSignalFlags flags,
819 : : gchar *arg0_rule,
820 : : gchar *arg0,
821 : : const gchar *signal_type,
822 : : gboolean should_match)
823 : : {
824 : : guint subscription_ids[2];
825 : 19 : gint emissions = 0;
826 : 19 : gint matches = 0;
827 : 19 : GError *error = NULL;
828 : :
829 : 19 : subscription_ids[0] = g_dbus_connection_signal_subscribe (connection,
830 : : NULL, "org.gtk.ExampleInterface", "Foo", "/",
831 : : NULL,
832 : : G_DBUS_SIGNAL_FLAGS_NONE,
833 : : test_connection_signal_handler,
834 : : &emissions, NULL);
835 : 19 : subscription_ids[1] = g_dbus_connection_signal_subscribe (connection,
836 : : NULL, "org.gtk.ExampleInterface", "Foo", "/",
837 : : arg0_rule,
838 : : flags,
839 : : test_connection_signal_handler,
840 : : &matches, NULL);
841 : 19 : g_assert_cmpint (subscription_ids[0], !=, 0);
842 : 19 : g_assert_cmpint (subscription_ids[1], !=, 0);
843 : :
844 : 19 : g_dbus_connection_emit_signal (connection,
845 : : NULL, "/", "org.gtk.ExampleInterface",
846 : : "Foo", g_variant_new (signal_type, arg0),
847 : : &error);
848 : 19 : g_assert_no_error (error);
849 : :
850 : : /* synchronously ping a non-existent method to make sure the signals are dispatched */
851 : 19 : g_dbus_connection_call_sync (connection, "org.gtk.ExampleInterface", "/", "org.gtk.ExampleInterface",
852 : : "Bar", g_variant_new ("()"), G_VARIANT_TYPE_UNIT, G_DBUS_CALL_FLAGS_NONE,
853 : : -1, NULL, NULL);
854 : :
855 : 57 : while (g_main_context_iteration (NULL, FALSE))
856 : : ;
857 : :
858 : 19 : g_assert_cmpint (emissions, ==, 1);
859 : 19 : g_assert_cmpint (matches, ==, should_match ? 1 : 0);
860 : :
861 : 19 : g_clear_dbus_signal_subscription (&subscription_ids[0], connection);
862 : 19 : g_clear_dbus_signal_subscription (&subscription_ids[1], connection);
863 : 19 : }
864 : :
865 : : static void
866 : 1 : test_connection_signal_match_rules (void)
867 : : {
868 : : GDBusConnection *con;
869 : :
870 : 1 : session_bus_up ();
871 : 1 : con = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
872 : :
873 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "foo", "(s)", TRUE);
874 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "bar", "(s)", FALSE);
875 : :
876 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "", "(s)", FALSE);
877 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org", "(s)", FALSE);
878 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk", "(s)", TRUE);
879 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk.Example", "(s)", TRUE);
880 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk+", "(s)", FALSE);
881 : :
882 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(s)", TRUE);
883 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "", "(s)", FALSE);
884 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(s)", TRUE);
885 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(s)", TRUE);
886 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/", "(s)", TRUE);
887 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(s)", FALSE);
888 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(s)", FALSE);
889 : :
890 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(o)", TRUE);
891 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(o)", TRUE);
892 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(o)", TRUE);
893 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(o)", FALSE);
894 : 1 : test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(o)", FALSE);
895 : :
896 : 1 : g_object_unref (con);
897 : 1 : session_bus_down ();
898 : 1 : }
899 : :
900 : : /* ---------------------------------------------------------------------------------------------------- */
901 : :
902 : : /* Accessed both from the test code and the filter function (in a worker thread)
903 : : * so all accesses must be atomic. */
904 : : typedef struct
905 : : {
906 : : GAsyncQueue *incoming_queue; /* (element-type GDBusMessage) */
907 : : guint num_outgoing; /* (atomic) */
908 : : } FilterData;
909 : :
910 : : /* Runs in a worker thread. */
911 : : static GDBusMessage *
912 : 9 : filter_func (GDBusConnection *connection,
913 : : GDBusMessage *message,
914 : : gboolean incoming,
915 : : gpointer user_data)
916 : : {
917 : 9 : FilterData *data = user_data;
918 : :
919 : 9 : if (incoming)
920 : 5 : g_async_queue_push (data->incoming_queue, g_object_ref (message));
921 : : else
922 : 4 : g_atomic_int_inc (&data->num_outgoing);
923 : :
924 : 9 : return message;
925 : : }
926 : :
927 : : static void
928 : 4 : wait_for_filtered_reply (GAsyncQueue *incoming_queue,
929 : : guint32 expected_serial)
930 : : {
931 : 4 : GDBusMessage *popped_message = NULL;
932 : :
933 : 5 : while ((popped_message = g_async_queue_pop (incoming_queue)) != NULL)
934 : : {
935 : 5 : guint32 reply_serial = g_dbus_message_get_reply_serial (popped_message);
936 : 5 : g_object_unref (popped_message);
937 : 5 : if (reply_serial == expected_serial)
938 : 4 : return;
939 : : }
940 : :
941 : : g_assert_not_reached ();
942 : : }
943 : :
944 : : typedef struct
945 : : {
946 : : gboolean alter_incoming;
947 : : gboolean alter_outgoing;
948 : : } FilterEffects;
949 : :
950 : : /* Runs in a worker thread. */
951 : : static GDBusMessage *
952 : 6 : other_filter_func (GDBusConnection *connection,
953 : : GDBusMessage *message,
954 : : gboolean incoming,
955 : : gpointer user_data)
956 : : {
957 : 6 : const FilterEffects *effects = user_data;
958 : : GDBusMessage *ret;
959 : : gboolean alter;
960 : :
961 : 6 : if (incoming)
962 : 3 : alter = effects->alter_incoming;
963 : : else
964 : 3 : alter = effects->alter_outgoing;
965 : :
966 : 6 : if (alter)
967 : : {
968 : : GDBusMessage *copy;
969 : : GVariant *body;
970 : : gchar *s;
971 : : gchar *s2;
972 : :
973 : 2 : copy = g_dbus_message_copy (message, NULL);
974 : 2 : g_object_unref (message);
975 : :
976 : 2 : body = g_dbus_message_get_body (copy);
977 : 2 : g_variant_get (body, "(s)", &s);
978 : 2 : s2 = g_strdup_printf ("MOD: %s", s);
979 : 2 : g_dbus_message_set_body (copy, g_variant_new ("(s)", s2));
980 : 2 : g_free (s2);
981 : 2 : g_free (s);
982 : :
983 : 2 : ret = copy;
984 : : }
985 : : else
986 : : {
987 : 4 : ret = message;
988 : : }
989 : :
990 : 6 : return ret;
991 : : }
992 : :
993 : : static void
994 : 2 : test_connection_filter_name_owner_changed_signal_handler (GDBusConnection *connection,
995 : : const gchar *sender_name,
996 : : const gchar *object_path,
997 : : const gchar *interface_name,
998 : : const gchar *signal_name,
999 : : GVariant *parameters,
1000 : : gpointer user_data)
1001 : : {
1002 : : const gchar *name;
1003 : : const gchar *old_owner;
1004 : : const gchar *new_owner;
1005 : :
1006 : 2 : g_variant_get (parameters,
1007 : : "(&s&s&s)",
1008 : : &name,
1009 : : &old_owner,
1010 : : &new_owner);
1011 : :
1012 : 2 : if (g_strcmp0 (name, "com.example.TestService") == 0 && strlen (new_owner) > 0)
1013 : : {
1014 : 1 : g_main_loop_quit (loop);
1015 : : }
1016 : 2 : }
1017 : :
1018 : : static gboolean
1019 : 0 : test_connection_filter_on_timeout (gpointer user_data)
1020 : : {
1021 : 0 : g_printerr ("Timeout waiting 30 sec on service\n");
1022 : : g_assert_not_reached ();
1023 : : return G_SOURCE_REMOVE;
1024 : : }
1025 : :
1026 : : static void
1027 : 1 : test_connection_filter (void)
1028 : : {
1029 : : GDBusConnection *c;
1030 : 1 : FilterData data = { NULL, 0 };
1031 : : GDBusMessage *m;
1032 : : GDBusMessage *m2;
1033 : : GDBusMessage *r;
1034 : : GError *error;
1035 : : guint filter_id;
1036 : : guint timeout_mainloop_id;
1037 : : guint signal_handler_id;
1038 : : FilterEffects effects;
1039 : : GVariant *result;
1040 : : const gchar *s;
1041 : : guint32 serial_temp;
1042 : :
1043 : 1 : session_bus_up ();
1044 : :
1045 : 1 : error = NULL;
1046 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1047 : 1 : g_assert_no_error (error);
1048 : 1 : g_assert_nonnull (c);
1049 : :
1050 : 1 : data.incoming_queue = g_async_queue_new_full (g_object_unref);
1051 : 1 : data.num_outgoing = 0;
1052 : 1 : filter_id = g_dbus_connection_add_filter (c,
1053 : : filter_func,
1054 : : &data,
1055 : : NULL);
1056 : :
1057 : 1 : m = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
1058 : : DBUS_PATH_DBUS,
1059 : : DBUS_INTERFACE_DBUS,
1060 : : "GetNameOwner");
1061 : 1 : g_dbus_message_set_body (m, g_variant_new ("(s)", DBUS_SERVICE_DBUS));
1062 : 1 : error = NULL;
1063 : 1 : g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &serial_temp, &error);
1064 : 1 : g_assert_no_error (error);
1065 : :
1066 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
1067 : :
1068 : 1 : m2 = g_dbus_message_copy (m, &error);
1069 : 1 : g_assert_no_error (error);
1070 : 1 : g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &serial_temp, &error);
1071 : 1 : g_object_unref (m2);
1072 : 1 : g_assert_no_error (error);
1073 : :
1074 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
1075 : :
1076 : 1 : m2 = g_dbus_message_copy (m, &error);
1077 : 1 : g_assert_no_error (error);
1078 : 1 : g_dbus_message_set_serial (m2, serial_temp);
1079 : : /* lock the message to test PRESERVE_SERIAL flag. */
1080 : 1 : g_dbus_message_lock (m2);
1081 : 1 : g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL, &serial_temp, &error);
1082 : 1 : g_object_unref (m2);
1083 : 1 : g_assert_no_error (error);
1084 : :
1085 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
1086 : :
1087 : 1 : m2 = g_dbus_message_copy (m, &error);
1088 : 1 : g_assert_no_error (error);
1089 : 1 : r = g_dbus_connection_send_message_with_reply_sync (c,
1090 : : m2,
1091 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1092 : : -1,
1093 : : &serial_temp,
1094 : : NULL, /* GCancellable */
1095 : : &error);
1096 : 1 : g_object_unref (m2);
1097 : 1 : g_assert_no_error (error);
1098 : 1 : g_assert_nonnull (r);
1099 : 1 : g_object_unref (r);
1100 : :
1101 : 1 : wait_for_filtered_reply (data.incoming_queue, serial_temp);
1102 : 1 : g_assert_cmpint (g_async_queue_length (data.incoming_queue), ==, 0);
1103 : :
1104 : 1 : g_dbus_connection_remove_filter (c, filter_id);
1105 : :
1106 : 1 : m2 = g_dbus_message_copy (m, &error);
1107 : 1 : g_assert_no_error (error);
1108 : 1 : r = g_dbus_connection_send_message_with_reply_sync (c,
1109 : : m2,
1110 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
1111 : : -1,
1112 : : &serial_temp,
1113 : : NULL, /* GCancellable */
1114 : : &error);
1115 : 1 : g_object_unref (m2);
1116 : 1 : g_assert_no_error (error);
1117 : 1 : g_assert_nonnull (r);
1118 : 1 : g_object_unref (r);
1119 : 1 : g_assert_cmpint (g_async_queue_length (data.incoming_queue), ==, 0);
1120 : 1 : g_assert_cmpint (g_atomic_int_get (&data.num_outgoing), ==, 4);
1121 : :
1122 : : /* wait for service to be available */
1123 : 1 : signal_handler_id = g_dbus_connection_signal_subscribe (c,
1124 : : DBUS_SERVICE_DBUS,
1125 : : DBUS_INTERFACE_DBUS,
1126 : : "NameOwnerChanged",
1127 : : DBUS_PATH_DBUS,
1128 : : NULL, /* arg0 */
1129 : : G_DBUS_SIGNAL_FLAGS_NONE,
1130 : : test_connection_filter_name_owner_changed_signal_handler,
1131 : : NULL,
1132 : : NULL);
1133 : 1 : g_assert_cmpint (signal_handler_id, !=, 0);
1134 : :
1135 : : /* this is safe; testserver will exit once the bus goes away */
1136 : 1 : g_assert_true (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver", NULL), NULL));
1137 : :
1138 : 1 : timeout_mainloop_id = g_timeout_add (30000, test_connection_filter_on_timeout, NULL);
1139 : 1 : g_main_loop_run (loop);
1140 : 1 : g_source_remove (timeout_mainloop_id);
1141 : 1 : g_clear_dbus_signal_subscription (&signal_handler_id, c);
1142 : :
1143 : : /* now test some combinations... */
1144 : 1 : filter_id = g_dbus_connection_add_filter (c,
1145 : : other_filter_func,
1146 : : &effects,
1147 : : NULL);
1148 : : /* -- */
1149 : 1 : effects.alter_incoming = FALSE;
1150 : 1 : effects.alter_outgoing = FALSE;
1151 : 1 : error = NULL;
1152 : 1 : result = g_dbus_connection_call_sync (c,
1153 : : "com.example.TestService", /* bus name */
1154 : : "/com/example/TestObject", /* object path */
1155 : : "com.example.Frob", /* interface name */
1156 : : "HelloWorld", /* method name */
1157 : : g_variant_new ("(s)", "Cat"), /* parameters */
1158 : : G_VARIANT_TYPE ("(s)"), /* return type */
1159 : : G_DBUS_CALL_FLAGS_NONE,
1160 : : -1,
1161 : : NULL,
1162 : : &error);
1163 : 1 : g_assert_no_error (error);
1164 : 1 : g_variant_get (result, "(&s)", &s);
1165 : 1 : g_assert_cmpstr (s, ==, "You greeted me with 'Cat'. Thanks!");
1166 : 1 : g_variant_unref (result);
1167 : : /* -- */
1168 : 1 : effects.alter_incoming = TRUE;
1169 : 1 : effects.alter_outgoing = TRUE;
1170 : 1 : error = NULL;
1171 : 1 : result = g_dbus_connection_call_sync (c,
1172 : : "com.example.TestService", /* bus name */
1173 : : "/com/example/TestObject", /* object path */
1174 : : "com.example.Frob", /* interface name */
1175 : : "HelloWorld", /* method name */
1176 : : g_variant_new ("(s)", "Cat"), /* parameters */
1177 : : G_VARIANT_TYPE ("(s)"), /* return type */
1178 : : G_DBUS_CALL_FLAGS_NONE,
1179 : : -1,
1180 : : NULL,
1181 : : &error);
1182 : 1 : g_assert_no_error (error);
1183 : 1 : g_variant_get (result, "(&s)", &s);
1184 : 1 : g_assert_cmpstr (s, ==, "MOD: You greeted me with 'MOD: Cat'. Thanks!");
1185 : 1 : g_variant_unref (result);
1186 : :
1187 : :
1188 : 1 : g_dbus_connection_remove_filter (c, filter_id);
1189 : :
1190 : 1 : g_object_unref (c);
1191 : 1 : g_object_unref (m);
1192 : 1 : g_async_queue_unref (data.incoming_queue);
1193 : :
1194 : 1 : session_bus_down ();
1195 : 1 : }
1196 : :
1197 : : /* ---------------------------------------------------------------------------------------------------- */
1198 : :
1199 : : #define NUM_THREADS 50
1200 : :
1201 : : static void
1202 : 52 : send_bogus_message (GDBusConnection *c, guint32 *out_serial)
1203 : : {
1204 : : GDBusMessage *m;
1205 : : GError *error;
1206 : :
1207 : 52 : m = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
1208 : : DBUS_PATH_DBUS,
1209 : : DBUS_INTERFACE_DBUS,
1210 : : "GetNameOwner");
1211 : 52 : g_dbus_message_set_body (m, g_variant_new ("(s)", DBUS_SERVICE_DBUS));
1212 : 52 : error = NULL;
1213 : 52 : g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, out_serial, &error);
1214 : 52 : g_assert_no_error (error);
1215 : 52 : g_object_unref (m);
1216 : 52 : }
1217 : :
1218 : : #define SLEEP_USEC (100 * 1000)
1219 : :
1220 : : static gpointer
1221 : 50 : serials_thread_func (GDBusConnection *c)
1222 : : {
1223 : : guint32 message_serial;
1224 : : guint i;
1225 : :
1226 : : /* No calls on this thread yet */
1227 : 50 : g_assert_cmpint (g_dbus_connection_get_last_serial(c), ==, 0);
1228 : :
1229 : : /* Send a bogus message and store its serial */
1230 : 50 : message_serial = 0;
1231 : 50 : send_bogus_message (c, &message_serial);
1232 : :
1233 : : /* Give it some time to actually send the message out. 10 seconds
1234 : : * should be plenty, even on slow machines. */
1235 : 50 : for (i = 0; i < 10 * G_USEC_PER_SEC / SLEEP_USEC; i++)
1236 : : {
1237 : 50 : if (g_dbus_connection_get_last_serial(c) != 0)
1238 : 50 : break;
1239 : :
1240 : 0 : g_usleep (SLEEP_USEC);
1241 : : }
1242 : :
1243 : 50 : g_assert_cmpint (g_dbus_connection_get_last_serial(c), !=, 0);
1244 : 50 : g_assert_cmpint (g_dbus_connection_get_last_serial(c), ==, message_serial);
1245 : :
1246 : 50 : return NULL;
1247 : : }
1248 : :
1249 : : static void
1250 : 1 : test_connection_serials (void)
1251 : : {
1252 : : GDBusConnection *c;
1253 : : GError *error;
1254 : : GThread *pool[NUM_THREADS];
1255 : : int i;
1256 : :
1257 : 1 : session_bus_up ();
1258 : :
1259 : 1 : error = NULL;
1260 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1261 : 1 : g_assert_no_error (error);
1262 : 1 : g_assert_nonnull (c);
1263 : :
1264 : : /* Status after initialization */
1265 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 1);
1266 : :
1267 : : /* Send a bogus message */
1268 : 1 : send_bogus_message (c, NULL);
1269 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 2);
1270 : :
1271 : : /* Start the threads */
1272 : 51 : for (i = 0; i < NUM_THREADS; i++)
1273 : 50 : pool[i] = g_thread_new (NULL, (GThreadFunc) serials_thread_func, c);
1274 : :
1275 : : /* Wait until threads are finished */
1276 : 51 : for (i = 0; i < NUM_THREADS; i++)
1277 : 50 : g_thread_join (pool[i]);
1278 : :
1279 : : /* No calls in between on this thread, should be the last value */
1280 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 2);
1281 : :
1282 : 1 : send_bogus_message (c, NULL);
1283 : :
1284 : : /* All above calls + calls in threads */
1285 : 1 : g_assert_cmpint (g_dbus_connection_get_last_serial (c), ==, 3 + NUM_THREADS);
1286 : :
1287 : 1 : g_object_unref (c);
1288 : :
1289 : 1 : session_bus_down ();
1290 : 1 : }
1291 : :
1292 : : /* ---------------------------------------------------------------------------------------------------- */
1293 : :
1294 : : static void
1295 : 1 : get_connection_cb_expect_cancel (GObject *source_object,
1296 : : GAsyncResult *res,
1297 : : gpointer user_data)
1298 : : {
1299 : : GDBusConnection *c;
1300 : : GError *error;
1301 : :
1302 : 1 : error = NULL;
1303 : 1 : c = g_bus_get_finish (res, &error);
1304 : :
1305 : : /* unref here to avoid timeouts when the test fails */
1306 : 1 : if (c)
1307 : 0 : g_object_unref (c);
1308 : :
1309 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
1310 : 1 : g_assert_null (c);
1311 : :
1312 : 1 : g_error_free (error);
1313 : 1 : }
1314 : :
1315 : : static void
1316 : 1 : get_connection_cb_expect_success (GObject *source_object,
1317 : : GAsyncResult *res,
1318 : : gpointer user_data)
1319 : : {
1320 : : GDBusConnection *c;
1321 : : GError *error;
1322 : :
1323 : 1 : error = NULL;
1324 : 1 : c = g_bus_get_finish (res, &error);
1325 : 1 : g_assert_no_error (error);
1326 : 1 : g_assert_nonnull (c);
1327 : :
1328 : 1 : g_main_loop_quit (loop);
1329 : :
1330 : 1 : g_object_unref (c);
1331 : 1 : }
1332 : :
1333 : : static void
1334 : 1 : test_connection_cancel (void)
1335 : : {
1336 : : GCancellable *cancellable, *cancellable2;
1337 : :
1338 : 1 : g_test_summary ("Test that cancelling one of two racing g_bus_get() calls does not cancel the other one");
1339 : :
1340 : 1 : session_bus_up ();
1341 : :
1342 : 1 : cancellable = g_cancellable_new ();
1343 : 1 : cancellable2 = g_cancellable_new ();
1344 : :
1345 : 1 : g_bus_get (G_BUS_TYPE_SESSION, cancellable, get_connection_cb_expect_cancel, NULL);
1346 : 1 : g_bus_get (G_BUS_TYPE_SESSION, cancellable2, get_connection_cb_expect_success, NULL);
1347 : 1 : g_cancellable_cancel (cancellable);
1348 : 1 : g_main_loop_run (loop);
1349 : :
1350 : 1 : g_object_unref (cancellable);
1351 : 1 : g_object_unref (cancellable2);
1352 : :
1353 : 1 : session_bus_down ();
1354 : 1 : }
1355 : :
1356 : : /* ---------------------------------------------------------------------------------------------------- */
1357 : :
1358 : : static void
1359 : 1 : test_connection_basic (void)
1360 : : {
1361 : : GDBusConnection *connection;
1362 : : GError *error;
1363 : : GDBusCapabilityFlags flags;
1364 : : GDBusConnectionFlags connection_flags;
1365 : : gchar *guid;
1366 : : gchar *name;
1367 : : gboolean closed;
1368 : : gboolean exit_on_close;
1369 : : GIOStream *stream;
1370 : : GCredentials *credentials;
1371 : :
1372 : 1 : session_bus_up ();
1373 : :
1374 : 1 : error = NULL;
1375 : 1 : connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1376 : 1 : g_assert_no_error (error);
1377 : 1 : g_assert_nonnull (connection);
1378 : :
1379 : 1 : flags = g_dbus_connection_get_capabilities (connection);
1380 : 1 : g_assert_true (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
1381 : : flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1382 : :
1383 : 1 : connection_flags = g_dbus_connection_get_flags (connection);
1384 : : /* Ignore G_DBUS_CONNECTION_FLAGS_CROSS_NAMESPACE, it's an
1385 : : * implementation detail whether we set it */
1386 : 1 : connection_flags &= ~G_DBUS_CONNECTION_FLAGS_CROSS_NAMESPACE;
1387 : 1 : g_assert_cmpint (connection_flags, ==,
1388 : : G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
1389 : : G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION);
1390 : :
1391 : 1 : credentials = g_dbus_connection_get_peer_credentials (connection);
1392 : 1 : g_assert_null (credentials);
1393 : :
1394 : 1 : g_object_get (connection,
1395 : : "stream", &stream,
1396 : : "guid", &guid,
1397 : : "unique-name", &name,
1398 : : "closed", &closed,
1399 : : "exit-on-close", &exit_on_close,
1400 : : "capabilities", &flags,
1401 : : NULL);
1402 : :
1403 : 1 : g_assert_true (G_IS_IO_STREAM (stream));
1404 : 1 : g_assert_true (g_dbus_is_guid (guid));
1405 : 1 : g_assert_true (g_dbus_is_unique_name (name));
1406 : 1 : g_assert_false (closed);
1407 : 1 : g_assert_true (exit_on_close);
1408 : 1 : g_assert_true (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
1409 : : flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1410 : 1 : g_object_unref (stream);
1411 : 1 : g_free (name);
1412 : 1 : g_free (guid);
1413 : :
1414 : 1 : g_object_unref (connection);
1415 : :
1416 : 1 : session_bus_down ();
1417 : 1 : }
1418 : :
1419 : : /* ---------------------------------------------------------------------------------------------------- */
1420 : :
1421 : : int
1422 : 1 : main (int argc,
1423 : : char *argv[])
1424 : : {
1425 : : int ret;
1426 : :
1427 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1428 : :
1429 : : /* all the tests rely on a shared main loop */
1430 : 1 : loop = g_main_loop_new (NULL, FALSE);
1431 : :
1432 : 1 : g_test_dbus_unset ();
1433 : :
1434 : : /* gdbus cleanup is pretty racy due to worker threads, so always do this test first */
1435 : 1 : g_test_add_func ("/gdbus/connection/bus-failure", test_connection_bus_failure);
1436 : :
1437 : 1 : g_test_add_func ("/gdbus/connection/basic", test_connection_basic);
1438 : 1 : g_test_add_func ("/gdbus/connection/life-cycle", test_connection_life_cycle);
1439 : 1 : g_test_add_func ("/gdbus/connection/send", test_connection_send);
1440 : 1 : g_test_add_func ("/gdbus/connection/signals", test_connection_signals);
1441 : 1 : g_test_add_func ("/gdbus/connection/signal-match-rules", test_connection_signal_match_rules);
1442 : 1 : g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
1443 : 1 : g_test_add_func ("/gdbus/connection/serials", test_connection_serials);
1444 : 1 : g_test_add_func ("/gdbus/connection/cancel", test_connection_cancel);
1445 : 1 : ret = g_test_run();
1446 : :
1447 : 1 : g_main_loop_unref (loop);
1448 : 1 : return ret;
1449 : : }
|