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