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