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