GDBusConnection: Fix race in /gdbus/connection/life-cycle
[platform/upstream/glib.git] / gio / tests / gdbus-connection.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
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 #include <sys/wait.h>
29
30 #include "gdbus-tests.h"
31
32 /* all tests rely on a shared mainloop */
33 static GMainLoop *loop = NULL;
34
35 G_GNUC_UNUSED static void
36 _log (const gchar *format, ...)
37 {
38   GTimeVal now;
39   time_t now_time;
40   struct tm *now_tm;
41   gchar time_buf[128];
42   gchar *str;
43   va_list var_args;
44
45   va_start (var_args, format);
46   str = g_strdup_vprintf (format, var_args);
47   va_end (var_args);
48
49   g_get_current_time (&now);
50   now_time = (time_t) now.tv_sec;
51   now_tm = localtime (&now_time);
52   strftime (time_buf, sizeof time_buf, "%H:%M:%S", now_tm);
53
54   g_print ("%s.%06d: %s\n",
55            time_buf, (gint) now.tv_usec / 1000,
56            str);
57   g_free (str);
58 }
59
60 static gboolean
61 test_connection_quit_mainloop (gpointer user_data)
62 {
63   volatile gboolean *quit_mainloop_fired = user_data;
64   //_log ("quit_mainloop_fired");
65   *quit_mainloop_fired = TRUE;
66   g_main_loop_quit (loop);
67   return TRUE;
68 }
69
70 /* ---------------------------------------------------------------------------------------------------- */
71 /* Connection life-cycle testing */
72 /* ---------------------------------------------------------------------------------------------------- */
73
74 static const GDBusInterfaceInfo boo_interface_info =
75 {
76   -1,
77   "org.example.Boo",
78   (GDBusMethodInfo **) NULL,
79   (GDBusSignalInfo **) NULL,
80   (GDBusPropertyInfo **) NULL,
81   NULL,
82 };
83
84 static const GDBusInterfaceVTable boo_vtable =
85 {
86   NULL, /* _method_call */
87   NULL, /* _get_property */
88   NULL  /* _set_property */
89 };
90
91 static GDBusMessage *
92 some_filter_func (GDBusConnection *connection,
93                   GDBusMessage    *message,
94                   gboolean         incoming,
95                   gpointer         user_data)
96 {
97   return message;
98 }
99
100 static void
101 on_name_owner_changed (GDBusConnection *connection,
102                        const gchar     *sender_name,
103                        const gchar     *object_path,
104                        const gchar     *interface_name,
105                        const gchar     *signal_name,
106                        GVariant        *parameters,
107                        gpointer         user_data)
108 {
109 }
110
111 static void
112 a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop (gpointer user_data)
113 {
114   volatile gboolean *val = user_data;
115   *val = TRUE;
116   //_log ("destroynotify fired for %p", val);
117   g_main_loop_quit (loop);
118 }
119
120 static void
121 test_connection_life_cycle (void)
122 {
123   gboolean ret;
124   GDBusConnection *c;
125   GDBusConnection *c2;
126   GError *error;
127   volatile gboolean on_signal_registration_freed_called;
128   volatile gboolean on_filter_freed_called;
129   volatile gboolean on_register_object_freed_called;
130   volatile gboolean quit_mainloop_fired;
131   guint quit_mainloop_id;
132   guint registration_id;
133
134   error = NULL;
135
136   /*
137    * Check for correct behavior when no bus is present
138    *
139    */
140   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
141   _g_assert_error_domain (error, G_IO_ERROR);
142   g_assert (!g_dbus_error_is_remote_error (error));
143   g_assert (c == NULL);
144   g_error_free (error);
145
146   /*
147    *  Check for correct behavior when a bus is present
148    */
149   session_bus_up ();
150   /* case 1 */
151   error = NULL;
152   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
153   g_assert_no_error (error);
154   g_assert (c != NULL);
155   g_assert (!g_dbus_connection_is_closed (c));
156
157   /*
158    * Check that singleton handling work
159    */
160   error = NULL;
161   c2 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
162   g_assert_no_error (error);
163   g_assert (c2 != NULL);
164   g_assert (c == c2);
165   g_object_unref (c2);
166
167   /*
168    * Check that private connections work
169    */
170   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
171   g_assert_no_error (error);
172   g_assert (c2 != NULL);
173   g_assert (c != c2);
174   g_object_unref (c2);
175
176   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
177   g_assert_no_error (error);
178   g_assert (c2 != NULL);
179   g_assert (!g_dbus_connection_is_closed (c2));
180   ret = g_dbus_connection_close_sync (c2, NULL, &error);
181   g_assert_no_error (error);
182   g_assert (ret);
183   _g_assert_signal_received (c2, "closed");
184   g_assert (g_dbus_connection_is_closed (c2));
185   ret = g_dbus_connection_close_sync (c2, NULL, &error);
186   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
187   g_error_free (error);
188   g_assert (!ret);
189   g_object_unref (c2);
190
191   /*
192    * Check that the finalization code works
193    *
194    * (and that the GDestroyNotify for filters and objects and signal
195    * registrations are run as expected)
196    */
197   error = NULL;
198   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
199   g_assert_no_error (error);
200   g_assert (c2 != NULL);
201   /* signal registration */
202   on_signal_registration_freed_called = FALSE;
203   g_dbus_connection_signal_subscribe (c2,
204                                       "org.freedesktop.DBus", /* bus name */
205                                       "org.freedesktop.DBus", /* interface */
206                                       "NameOwnerChanged",     /* member */
207                                       "/org/freesktop/DBus",  /* path */
208                                       NULL,                   /* arg0 */
209                                       G_DBUS_SIGNAL_FLAGS_NONE,
210                                       on_name_owner_changed,
211                                       (gpointer) &on_signal_registration_freed_called,
212                                       a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop);
213   /* filter func */
214   on_filter_freed_called = FALSE;
215   g_dbus_connection_add_filter (c2,
216                                 some_filter_func,
217                                 (gpointer) &on_filter_freed_called,
218                                 a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop);
219   /* object registration */
220   on_register_object_freed_called = FALSE;
221   error = NULL;
222   registration_id = g_dbus_connection_register_object (c2,
223                                                        "/foo",
224                                                        (GDBusInterfaceInfo *) &boo_interface_info,
225                                                        &boo_vtable,
226                                                        (gpointer) &on_register_object_freed_called,
227                                                        a_gdestroynotify_that_sets_a_gboolean_to_true_and_quits_loop,
228                                                        &error);
229   g_assert_no_error (error);
230   g_assert (registration_id > 0);
231   /* ok, finalize the connection and check that all the GDestroyNotify functions are invoked as expected */
232   g_object_unref (c2);
233   quit_mainloop_fired = FALSE;
234   quit_mainloop_id = g_timeout_add (30000, test_connection_quit_mainloop, (gpointer) &quit_mainloop_fired);
235   //_log ("destroynotifies for\n"
236   //      " register_object %p\n"
237   //      " filter          %p\n"
238   //      " signal          %p",
239   //      &on_register_object_freed_called,
240   //      &on_filter_freed_called,
241   //      &on_signal_registration_freed_called);
242   while (TRUE)
243     {
244       if (on_signal_registration_freed_called &&
245           on_filter_freed_called &&
246           on_register_object_freed_called)
247         break;
248       if (quit_mainloop_fired)
249         break;
250       //_log ("entering loop");
251       g_main_loop_run (loop);
252       //_log ("exiting loop");
253     }
254   g_source_remove (quit_mainloop_id);
255   g_assert (on_signal_registration_freed_called);
256   g_assert (on_filter_freed_called);
257   g_assert (on_register_object_freed_called);
258   g_assert (!quit_mainloop_fired);
259
260   /*
261    *  Check for correct behavior when the bus goes away
262    *
263    */
264   g_assert (!g_dbus_connection_is_closed (c));
265   g_dbus_connection_set_exit_on_close (c, FALSE);
266   session_bus_down ();
267   _g_assert_signal_received (c, "closed");
268   g_assert (g_dbus_connection_is_closed (c));
269
270   _g_object_wait_for_single_ref (c);
271   g_object_unref (c);
272 }
273
274 /* ---------------------------------------------------------------------------------------------------- */
275 /* Test that sending and receiving messages work as expected */
276 /* ---------------------------------------------------------------------------------------------------- */
277
278 static void
279 msg_cb_expect_error_disconnected (GDBusConnection *connection,
280                                   GAsyncResult    *res,
281                                   gpointer         user_data)
282 {
283   GError *error;
284   GVariant *result;
285
286   error = NULL;
287   result = g_dbus_connection_call_finish (connection,
288                                           res,
289                                           &error);
290   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
291   g_assert (!g_dbus_error_is_remote_error (error));
292   g_error_free (error);
293   g_assert (result == NULL);
294
295   g_main_loop_quit (loop);
296 }
297
298 static void
299 msg_cb_expect_error_unknown_method (GDBusConnection *connection,
300                                     GAsyncResult    *res,
301                                     gpointer         user_data)
302 {
303   GError *error;
304   GVariant *result;
305
306   error = NULL;
307   result = g_dbus_connection_call_finish (connection,
308                                           res,
309                                           &error);
310   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
311   g_assert (g_dbus_error_is_remote_error (error));
312   g_error_free (error);
313   g_assert (result == NULL);
314
315   g_main_loop_quit (loop);
316 }
317
318 static void
319 msg_cb_expect_success (GDBusConnection *connection,
320                        GAsyncResult    *res,
321                        gpointer         user_data)
322 {
323   GError *error;
324   GVariant *result;
325
326   error = NULL;
327   result = g_dbus_connection_call_finish (connection,
328                                           res,
329                                           &error);
330   g_assert_no_error (error);
331   g_assert (result != NULL);
332   g_variant_unref (result);
333
334   g_main_loop_quit (loop);
335 }
336
337 static void
338 msg_cb_expect_error_cancelled (GDBusConnection *connection,
339                                GAsyncResult    *res,
340                                gpointer         user_data)
341 {
342   GError *error;
343   GVariant *result;
344
345   error = NULL;
346   result = g_dbus_connection_call_finish (connection,
347                                           res,
348                                           &error);
349   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
350   g_assert (!g_dbus_error_is_remote_error (error));
351   g_error_free (error);
352   g_assert (result == NULL);
353
354   g_main_loop_quit (loop);
355 }
356
357 static void
358 msg_cb_expect_error_cancelled_2 (GDBusConnection *connection,
359                                  GAsyncResult    *res,
360                                  gpointer         user_data)
361 {
362   GError *error;
363   GVariant *result;
364
365   error = NULL;
366   result = g_dbus_connection_call_finish (connection,
367                                           res,
368                                           &error);
369   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
370   g_assert (!g_dbus_error_is_remote_error (error));
371   g_error_free (error);
372   g_assert (result == NULL);
373
374   g_main_loop_quit (loop);
375 }
376
377 /* ---------------------------------------------------------------------------------------------------- */
378
379 static void
380 test_connection_send (void)
381 {
382   GDBusConnection *c;
383   GCancellable *ca;
384
385   session_bus_up ();
386
387   /* First, get an unopened connection */
388   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
389   g_assert (c != NULL);
390   g_assert (!g_dbus_connection_is_closed (c));
391
392   /*
393    * Check that we never actually send a message if the GCancellable
394    * is already cancelled - i.e.  we should get #G_IO_ERROR_CANCELLED
395    * when the actual connection is not up.
396    */
397   ca = g_cancellable_new ();
398   g_cancellable_cancel (ca);
399   g_dbus_connection_call (c,
400                           "org.freedesktop.DBus",  /* bus_name */
401                           "/org/freedesktop/DBus", /* object path */
402                           "org.freedesktop.DBus",  /* interface name */
403                           "GetId",                 /* method name */
404                           NULL, NULL,
405                           G_DBUS_CALL_FLAGS_NONE,
406                           -1,
407                           ca,
408                           (GAsyncReadyCallback) msg_cb_expect_error_cancelled,
409                           NULL);
410   g_main_loop_run (loop);
411   g_object_unref (ca);
412
413   /*
414    * Check that we get a reply to the GetId() method call.
415    */
416   g_dbus_connection_call (c,
417                           "org.freedesktop.DBus",  /* bus_name */
418                           "/org/freedesktop/DBus", /* object path */
419                           "org.freedesktop.DBus",  /* interface name */
420                           "GetId",                 /* method name */
421                           NULL, NULL,
422                           G_DBUS_CALL_FLAGS_NONE,
423                           -1,
424                           NULL,
425                           (GAsyncReadyCallback) msg_cb_expect_success,
426                           NULL);
427   g_main_loop_run (loop);
428
429   /*
430    * Check that we get an error reply to the NonExistantMethod() method call.
431    */
432   g_dbus_connection_call (c,
433                           "org.freedesktop.DBus",  /* bus_name */
434                           "/org/freedesktop/DBus", /* object path */
435                           "org.freedesktop.DBus",  /* interface name */
436                           "NonExistantMethod",     /* method name */
437                           NULL, NULL,
438                           G_DBUS_CALL_FLAGS_NONE,
439                           -1,
440                           NULL,
441                           (GAsyncReadyCallback) msg_cb_expect_error_unknown_method,
442                           NULL);
443   g_main_loop_run (loop);
444
445   /*
446    * Check that cancellation works when the message is already in flight.
447    */
448   ca = g_cancellable_new ();
449   g_dbus_connection_call (c,
450                           "org.freedesktop.DBus",  /* bus_name */
451                           "/org/freedesktop/DBus", /* object path */
452                           "org.freedesktop.DBus",  /* interface name */
453                           "GetId",                 /* method name */
454                           NULL, NULL,
455                           G_DBUS_CALL_FLAGS_NONE,
456                           -1,
457                           ca,
458                           (GAsyncReadyCallback) msg_cb_expect_error_cancelled_2,
459                           NULL);
460   g_cancellable_cancel (ca);
461   g_main_loop_run (loop);
462   g_object_unref (ca);
463
464   /*
465    * Check that we get an error when sending to a connection that is disconnected.
466    */
467   g_dbus_connection_set_exit_on_close (c, FALSE);
468   session_bus_down ();
469   _g_assert_signal_received (c, "closed");
470   g_assert (g_dbus_connection_is_closed (c));
471
472   g_dbus_connection_call (c,
473                           "org.freedesktop.DBus",  /* bus_name */
474                           "/org/freedesktop/DBus", /* object path */
475                           "org.freedesktop.DBus",  /* interface name */
476                           "GetId",                 /* method name */
477                           NULL, NULL,
478                           G_DBUS_CALL_FLAGS_NONE,
479                           -1,
480                           NULL,
481                           (GAsyncReadyCallback) msg_cb_expect_error_disconnected,
482                           NULL);
483   g_main_loop_run (loop);
484
485   _g_object_wait_for_single_ref (c);
486   g_object_unref (c);
487 }
488
489 /* ---------------------------------------------------------------------------------------------------- */
490 /* Connection signal tests */
491 /* ---------------------------------------------------------------------------------------------------- */
492
493 static void
494 test_connection_signal_handler (GDBusConnection  *connection,
495                                 const gchar      *sender_name,
496                                 const gchar      *object_path,
497                                 const gchar      *interface_name,
498                                 const gchar      *signal_name,
499                                 GVariant         *parameters,
500                                 gpointer         user_data)
501 {
502   gint *counter = user_data;
503   *counter += 1;
504
505   /*g_debug ("in test_connection_signal_handler (sender=%s path=%s interface=%s member=%s)",
506            sender_name,
507            object_path,
508            interface_name,
509            signal_name);*/
510
511   g_main_loop_quit (loop);
512 }
513
514 static void
515 test_connection_signals (void)
516 {
517   GDBusConnection *c1;
518   GDBusConnection *c2;
519   GDBusConnection *c3;
520   guint s1;
521   guint s1b;
522   guint s2;
523   guint s3;
524   gint count_s1;
525   gint count_s1b;
526   gint count_s2;
527   gint count_name_owner_changed;
528   GError *error;
529   gboolean ret;
530   GVariant *result;
531   gboolean quit_mainloop_fired;
532   guint quit_mainloop_id;
533
534   error = NULL;
535
536   /*
537    * Bring up first separate connections
538    */
539   session_bus_up ();
540   /* if running with dbus-monitor, it claims the name :1.0 - so if we don't run with the monitor
541    * emulate this
542    */
543   if (g_getenv ("G_DBUS_MONITOR") == NULL)
544     {
545       c1 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
546       g_assert (c1 != NULL);
547       g_assert (!g_dbus_connection_is_closed (c1));
548       g_object_unref (c1);
549     }
550   c1 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
551   g_assert (c1 != NULL);
552   g_assert (!g_dbus_connection_is_closed (c1));
553   g_assert_cmpstr (g_dbus_connection_get_unique_name (c1), ==, ":1.1");
554
555   /*
556    * Install two signal handlers for the first connection
557    *
558    *  - Listen to the signal "Foo" from :1.2 (e.g. c2)
559    *  - Listen to the signal "Foo" from anyone (e.g. both c2 and c3)
560    *
561    * and then count how many times this signal handler was invoked.
562    */
563   s1 = g_dbus_connection_signal_subscribe (c1,
564                                            ":1.2",
565                                            "org.gtk.GDBus.ExampleInterface",
566                                            "Foo",
567                                            "/org/gtk/GDBus/ExampleInterface",
568                                            NULL,
569                                            G_DBUS_SIGNAL_FLAGS_NONE,
570                                            test_connection_signal_handler,
571                                            &count_s1,
572                                            NULL);
573   s2 = g_dbus_connection_signal_subscribe (c1,
574                                            NULL, /* match any sender */
575                                            "org.gtk.GDBus.ExampleInterface",
576                                            "Foo",
577                                            "/org/gtk/GDBus/ExampleInterface",
578                                            NULL,
579                                            G_DBUS_SIGNAL_FLAGS_NONE,
580                                            test_connection_signal_handler,
581                                            &count_s2,
582                                            NULL);
583   s3 = g_dbus_connection_signal_subscribe (c1,
584                                            "org.freedesktop.DBus",  /* sender */
585                                            "org.freedesktop.DBus",  /* interface */
586                                            "NameOwnerChanged",      /* member */
587                                            "/org/freedesktop/DBus", /* path */
588                                            NULL,
589                                            G_DBUS_SIGNAL_FLAGS_NONE,
590                                            test_connection_signal_handler,
591                                            &count_name_owner_changed,
592                                            NULL);
593   /* Note that s1b is *just like* s1 - this is to catch a bug where N
594    * subscriptions of the same rule causes N calls to each of the N
595    * subscriptions instead of just 1 call to each of the N subscriptions.
596    */
597   s1b = g_dbus_connection_signal_subscribe (c1,
598                                             ":1.2",
599                                             "org.gtk.GDBus.ExampleInterface",
600                                             "Foo",
601                                             "/org/gtk/GDBus/ExampleInterface",
602                                             NULL,
603                                             G_DBUS_SIGNAL_FLAGS_NONE,
604                                             test_connection_signal_handler,
605                                             &count_s1b,
606                                             NULL);
607   g_assert (s1 != 0);
608   g_assert (s1b != 0);
609   g_assert (s2 != 0);
610   g_assert (s3 != 0);
611
612   count_s1 = 0;
613   count_s1b = 0;
614   count_s2 = 0;
615   count_name_owner_changed = 0;
616
617   /*
618    * Bring up two other connections
619    */
620   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
621   g_assert (c2 != NULL);
622   g_assert (!g_dbus_connection_is_closed (c2));
623   g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
624   c3 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
625   g_assert (c3 != NULL);
626   g_assert (!g_dbus_connection_is_closed (c3));
627   g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
628
629   /*
630    * Make c2 emit "Foo" - we should catch it twice
631    *
632    * Note that there is no way to be sure that the signal subscriptions
633    * on c1 are effective yet - for all we know, the AddMatch() messages
634    * could sit waiting in a buffer somewhere between this process and
635    * the message bus. And emitting signals on c2 (a completely other
636    * socket!) will not necessarily change this.
637    *
638    * To ensure this is not the case, do a synchronous call on c1.
639    */
640   result = g_dbus_connection_call_sync (c1,
641                                         "org.freedesktop.DBus",  /* bus name */
642                                         "/org/freedesktop/DBus", /* object path */
643                                         "org.freedesktop.DBus",  /* interface name */
644                                         "GetId",                 /* method name */
645                                         NULL,                    /* parameters */
646                                         NULL,                    /* return type */
647                                         G_DBUS_CALL_FLAGS_NONE,
648                                         -1,
649                                         NULL,
650                                         &error);
651   g_assert_no_error (error);
652   g_assert (result != NULL);
653   g_variant_unref (result);
654   /* now, emit the signal on c2 */
655   ret = g_dbus_connection_emit_signal (c2,
656                                        NULL, /* destination bus name */
657                                        "/org/gtk/GDBus/ExampleInterface",
658                                        "org.gtk.GDBus.ExampleInterface",
659                                        "Foo",
660                                        NULL,
661                                        &error);
662   g_assert_no_error (error);
663   g_assert (ret);
664   while (!(count_s1 >= 1 && count_s2 >= 1))
665     g_main_loop_run (loop);
666   g_assert_cmpint (count_s1, ==, 1);
667   g_assert_cmpint (count_s2, ==, 1);
668
669   /*
670    * Make c3 emit "Foo" - we should catch it only once
671    */
672   ret = g_dbus_connection_emit_signal (c3,
673                                        NULL, /* destination bus name */
674                                        "/org/gtk/GDBus/ExampleInterface",
675                                        "org.gtk.GDBus.ExampleInterface",
676                                        "Foo",
677                                        NULL,
678                                        &error);
679   g_assert_no_error (error);
680   g_assert (ret);
681   while (!(count_s1 == 1 && count_s2 == 2))
682     g_main_loop_run (loop);
683   g_assert_cmpint (count_s1, ==, 1);
684   g_assert_cmpint (count_s2, ==, 2);
685
686   /*
687    * Also to check the total amount of NameOwnerChanged signals - use a 5 second ceiling
688    * to avoid spinning forever
689    */
690   quit_mainloop_fired = FALSE;
691   quit_mainloop_id = g_timeout_add (30000, test_connection_quit_mainloop, &quit_mainloop_fired);
692   while (count_name_owner_changed < 2 && !quit_mainloop_fired)
693     g_main_loop_run (loop);
694   g_source_remove (quit_mainloop_id);
695   g_assert_cmpint (count_s1, ==, 1);
696   g_assert_cmpint (count_s2, ==, 2);
697   g_assert_cmpint (count_name_owner_changed, ==, 2);
698
699   g_dbus_connection_signal_unsubscribe (c1, s1);
700   g_dbus_connection_signal_unsubscribe (c1, s2);
701   g_dbus_connection_signal_unsubscribe (c1, s3);
702   g_dbus_connection_signal_unsubscribe (c1, s1b);
703
704   _g_object_wait_for_single_ref (c1);
705   _g_object_wait_for_single_ref (c2);
706   _g_object_wait_for_single_ref (c3);
707
708   g_object_unref (c1);
709   g_object_unref (c2);
710   g_object_unref (c3);
711
712   session_bus_down ();
713 }
714
715 /* ---------------------------------------------------------------------------------------------------- */
716
717 typedef struct
718 {
719   guint num_handled;
720   guint num_outgoing;
721   guint32 serial;
722 } FilterData;
723
724 static GDBusMessage *
725 filter_func (GDBusConnection *connection,
726              GDBusMessage    *message,
727              gboolean         incoming,
728              gpointer         user_data)
729 {
730   FilterData *data = user_data;
731   guint32 reply_serial;
732
733   if (incoming)
734     {
735       reply_serial = g_dbus_message_get_reply_serial (message);
736       if (reply_serial == data->serial)
737         data->num_handled += 1;
738     }
739   else
740     {
741       data->num_outgoing += 1;
742     }
743
744   return message;
745 }
746
747
748 typedef struct
749 {
750   gboolean alter_incoming;
751   gboolean alter_outgoing;
752 } FilterEffects;
753
754 static GDBusMessage *
755 other_filter_func (GDBusConnection *connection,
756                    GDBusMessage    *message,
757                    gboolean         incoming,
758                    gpointer         user_data)
759 {
760   FilterEffects *effects = user_data;
761   GDBusMessage *ret;
762   gboolean alter;
763
764   if (incoming)
765     alter = effects->alter_incoming;
766   else
767     alter = effects->alter_outgoing;
768
769   if (alter)
770     {
771       GDBusMessage *copy;
772       GVariant *body;
773       gchar *s;
774       gchar *s2;
775
776       copy = g_dbus_message_copy (message, NULL);
777       g_object_unref (message);
778
779       body = g_dbus_message_get_body (copy);
780       g_variant_get (body, "(s)", &s);
781       s2 = g_strdup_printf ("MOD: %s", s);
782       g_dbus_message_set_body (copy, g_variant_new ("(s)", s2));
783       g_free (s2);
784       g_free (s);
785
786       ret = copy;
787     }
788   else
789     {
790       ret = message;
791     }
792
793   return ret;
794 }
795
796 static void
797 test_connection_filter_name_owner_changed_signal_handler (GDBusConnection  *connection,
798                                                           const gchar      *sender_name,
799                                                           const gchar      *object_path,
800                                                           const gchar      *interface_name,
801                                                           const gchar      *signal_name,
802                                                           GVariant         *parameters,
803                                                           gpointer         user_data)
804 {
805   const gchar *name;
806   const gchar *old_owner;
807   const gchar *new_owner;
808
809   g_variant_get (parameters,
810                  "(&s&s&s)",
811                  &name,
812                  &old_owner,
813                  &new_owner);
814
815   if (g_strcmp0 (name, "com.example.TestService") == 0 && strlen (new_owner) > 0)
816     {
817       g_main_loop_quit (loop);
818     }
819 }
820
821 static gboolean
822 test_connection_filter_on_timeout (gpointer user_data)
823 {
824   g_printerr ("Timeout waiting 30 sec on service\n");
825   g_assert_not_reached ();
826   return FALSE;
827 }
828
829 static void
830 test_connection_filter (void)
831 {
832   GDBusConnection *c;
833   FilterData data;
834   GDBusMessage *m;
835   GDBusMessage *m2;
836   GDBusMessage *r;
837   GError *error;
838   guint filter_id;
839   guint timeout_mainloop_id;
840   guint signal_handler_id;
841   FilterEffects effects;
842   GVariant *result;
843   const gchar *s;
844
845   memset (&data, '\0', sizeof (FilterData));
846
847   session_bus_up ();
848
849   error = NULL;
850   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
851   g_assert_no_error (error);
852   g_assert (c != NULL);
853
854   filter_id = g_dbus_connection_add_filter (c,
855                                             filter_func,
856                                             &data,
857                                             NULL);
858
859   m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
860                                       "/org/freedesktop/DBus", /* path */
861                                       "org.freedesktop.DBus", /* interface */
862                                       "GetNameOwner");
863   g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
864   error = NULL;
865   g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
866   g_assert_no_error (error);
867
868   while (data.num_handled == 0)
869     g_thread_yield ();
870
871   m2 = g_dbus_message_copy (m, &error);
872   g_assert_no_error (error);
873   g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
874   g_object_unref (m2);
875   g_assert_no_error (error);
876
877   while (data.num_handled == 1)
878     g_thread_yield ();
879
880   m2 = g_dbus_message_copy (m, &error);
881   g_assert_no_error (error);
882   g_dbus_message_set_serial (m2, data.serial);
883   /* lock the message to test PRESERVE_SERIAL flag. */
884   g_dbus_message_lock (m2);
885   g_dbus_connection_send_message (c, m2, G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL, &data.serial, &error);
886   g_object_unref (m2);
887   g_assert_no_error (error);
888
889   while (data.num_handled == 2)
890     g_thread_yield ();
891
892   m2 = g_dbus_message_copy (m, &error);
893   g_assert_no_error (error);
894   r = g_dbus_connection_send_message_with_reply_sync (c,
895                                                       m2,
896                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
897                                                       -1,
898                                                       &data.serial,
899                                                       NULL, /* GCancellable */
900                                                       &error);
901   g_object_unref (m2);
902   g_assert_no_error (error);
903   g_assert (r != NULL);
904   g_object_unref (r);
905   g_assert_cmpint (data.num_handled, ==, 4);
906
907   g_dbus_connection_remove_filter (c, filter_id);
908
909   m2 = g_dbus_message_copy (m, &error);
910   g_assert_no_error (error);
911   r = g_dbus_connection_send_message_with_reply_sync (c,
912                                                       m2,
913                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
914                                                       -1,
915                                                       &data.serial,
916                                                       NULL, /* GCancellable */
917                                                       &error);
918   g_object_unref (m2);
919   g_assert_no_error (error);
920   g_assert (r != NULL);
921   g_object_unref (r);
922   g_assert_cmpint (data.num_handled, ==, 4);
923   g_assert_cmpint (data.num_outgoing, ==, 4);
924
925   /* this is safe; testserver will exit once the bus goes away */
926   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
927   /* wait for service to be available */
928   signal_handler_id = g_dbus_connection_signal_subscribe (c,
929                                                           "org.freedesktop.DBus", /* sender */
930                                                           "org.freedesktop.DBus",
931                                                           "NameOwnerChanged",
932                                                           "/org/freedesktop/DBus",
933                                                           NULL, /* arg0 */
934                                                           G_DBUS_SIGNAL_FLAGS_NONE,
935                                                           test_connection_filter_name_owner_changed_signal_handler,
936                                                           NULL,
937                                                           NULL);
938   g_assert_cmpint (signal_handler_id, !=, 0);
939   timeout_mainloop_id = g_timeout_add (30000, test_connection_filter_on_timeout, NULL);
940   g_main_loop_run (loop);
941   g_source_remove (timeout_mainloop_id);
942   g_dbus_connection_signal_unsubscribe (c, signal_handler_id);
943
944   /* now test some combinations... */
945   filter_id = g_dbus_connection_add_filter (c,
946                                             other_filter_func,
947                                             &effects,
948                                             NULL);
949   /* -- */
950   effects.alter_incoming = FALSE;
951   effects.alter_outgoing = FALSE;
952   error = NULL;
953   result = g_dbus_connection_call_sync (c,
954                                         "com.example.TestService",      /* bus name */
955                                         "/com/example/TestObject",      /* object path */
956                                         "com.example.Frob",             /* interface name */
957                                         "HelloWorld",                   /* method name */
958                                         g_variant_new ("(s)", "Cat"),   /* parameters */
959                                         G_VARIANT_TYPE ("(s)"),         /* return type */
960                                         G_DBUS_CALL_FLAGS_NONE,
961                                         -1,
962                                         NULL,
963                                         &error);
964   g_assert_no_error (error);
965   g_variant_get (result, "(&s)", &s);
966   g_assert_cmpstr (s, ==, "You greeted me with 'Cat'. Thanks!");
967   g_variant_unref (result);
968   /* -- */
969   effects.alter_incoming = TRUE;
970   effects.alter_outgoing = TRUE;
971   error = NULL;
972   result = g_dbus_connection_call_sync (c,
973                                         "com.example.TestService",      /* bus name */
974                                         "/com/example/TestObject",      /* object path */
975                                         "com.example.Frob",             /* interface name */
976                                         "HelloWorld",                   /* method name */
977                                         g_variant_new ("(s)", "Cat"),   /* parameters */
978                                         G_VARIANT_TYPE ("(s)"),         /* return type */
979                                         G_DBUS_CALL_FLAGS_NONE,
980                                         -1,
981                                         NULL,
982                                         &error);
983   g_assert_no_error (error);
984   g_variant_get (result, "(&s)", &s);
985   g_assert_cmpstr (s, ==, "MOD: You greeted me with 'MOD: Cat'. Thanks!");
986   g_variant_unref (result);
987
988
989   g_dbus_connection_remove_filter (c, filter_id);
990
991   _g_object_wait_for_single_ref (c);
992   g_object_unref (c);
993   g_object_unref (m);
994
995   session_bus_down ();
996 }
997
998 static void
999 test_connection_basic (void)
1000 {
1001   GDBusConnection *connection;
1002   GError *error;
1003   GDBusCapabilityFlags flags;
1004   gchar *guid;
1005   gchar *name;
1006   gboolean closed;
1007   gboolean exit_on_close;
1008   GIOStream *stream;
1009   GCredentials *credentials;
1010
1011   session_bus_up ();
1012
1013   error = NULL;
1014   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
1015   g_assert_no_error (error);
1016   g_assert (connection != NULL);
1017
1018   flags = g_dbus_connection_get_capabilities (connection);
1019   g_assert (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
1020             flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1021
1022   credentials = g_dbus_connection_get_peer_credentials (connection);
1023   g_assert (credentials == NULL);
1024
1025   g_object_get (connection,
1026                 "stream", &stream,
1027                 "guid", &guid,
1028                 "unique-name", &name,
1029                 "closed", &closed,
1030                 "exit-on-close", &exit_on_close,
1031                 "capabilities", &flags,
1032                 NULL);
1033
1034   g_assert (G_IS_IO_STREAM (stream));
1035   g_assert (g_dbus_is_guid (guid));
1036   g_assert (g_dbus_is_unique_name (name));
1037   g_assert (!closed);
1038   g_assert (exit_on_close);
1039   g_assert (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
1040             flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1041   g_object_unref (stream);
1042   g_free (name);
1043   g_free (guid);
1044
1045   _g_object_wait_for_single_ref (connection);
1046   g_object_unref (connection);
1047
1048   session_bus_down ();
1049 }
1050
1051 /* ---------------------------------------------------------------------------------------------------- */
1052
1053 int
1054 main (int   argc,
1055       char *argv[])
1056 {
1057   g_type_init ();
1058   g_test_init (&argc, &argv, NULL);
1059
1060   /* all the tests rely on a shared main loop */
1061   loop = g_main_loop_new (NULL, FALSE);
1062
1063   /* all the tests use a session bus with a well-known address that we can bring up and down
1064    * using session_bus_up() and session_bus_down().
1065    */
1066   g_unsetenv ("DISPLAY");
1067   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
1068
1069   g_test_add_func ("/gdbus/connection/basic", test_connection_basic);
1070   g_test_add_func ("/gdbus/connection/life-cycle", test_connection_life_cycle);
1071   g_test_add_func ("/gdbus/connection/send", test_connection_send);
1072   g_test_add_func ("/gdbus/connection/signals", test_connection_signals);
1073   g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
1074   return g_test_run();
1075 }