c99e50c8438a7406b99ba5701c431402aad6eb68
[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 gboolean
66 some_filter_func (GDBusConnection *connection,
67                   GDBusMessage    *message,
68                   gboolean         incoming,
69                   gpointer         user_data)
70 {
71   return FALSE;
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_assert (result == NULL);
278
279   g_main_loop_quit (loop);
280 }
281
282 static void
283 msg_cb_expect_success (GDBusConnection *connection,
284                        GAsyncResult    *res,
285                        gpointer         user_data)
286 {
287   GError *error;
288   GVariant *result;
289
290   error = NULL;
291   result = g_dbus_connection_call_finish (connection,
292                                           res,
293                                           &error);
294   g_assert_no_error (error);
295   g_assert (result != NULL);
296   g_variant_unref (result);
297
298   g_main_loop_quit (loop);
299 }
300
301 static void
302 msg_cb_expect_error_cancelled (GDBusConnection *connection,
303                                GAsyncResult    *res,
304                                gpointer         user_data)
305 {
306   GError *error;
307   GVariant *result;
308
309   error = NULL;
310   result = g_dbus_connection_call_finish (connection,
311                                           res,
312                                           &error);
313   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
314   g_assert (!g_dbus_error_is_remote_error (error));
315   g_error_free (error);
316   g_assert (result == NULL);
317
318   g_main_loop_quit (loop);
319 }
320
321 static void
322 msg_cb_expect_error_cancelled_2 (GDBusConnection *connection,
323                                  GAsyncResult    *res,
324                                  gpointer         user_data)
325 {
326   GError *error;
327   GVariant *result;
328
329   error = NULL;
330   result = g_dbus_connection_call_finish (connection,
331                                           res,
332                                           &error);
333   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
334   g_assert (!g_dbus_error_is_remote_error (error));
335   g_error_free (error);
336   g_assert (result == NULL);
337
338   g_main_loop_quit (loop);
339 }
340
341 /* ---------------------------------------------------------------------------------------------------- */
342
343 static void
344 test_connection_send (void)
345 {
346   GDBusConnection *c;
347   GCancellable *ca;
348
349   session_bus_up ();
350
351   /* First, get an unopened connection */
352   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
353   g_assert (c != NULL);
354   g_assert (!g_dbus_connection_is_closed (c));
355
356   /*
357    * Check that we never actually send a message if the GCancellable
358    * is already cancelled - i.e.  we should get #G_IO_ERROR_CANCELLED
359    * when the actual connection is not up.
360    */
361   ca = g_cancellable_new ();
362   g_cancellable_cancel (ca);
363   g_dbus_connection_call (c,
364                           "org.freedesktop.DBus",  /* bus_name */
365                           "/org/freedesktop/DBus", /* object path */
366                           "org.freedesktop.DBus",  /* interface name */
367                           "GetId",                 /* method name */
368                           NULL, NULL,
369                           G_DBUS_CALL_FLAGS_NONE,
370                           -1,
371                           ca,
372                           (GAsyncReadyCallback) msg_cb_expect_error_cancelled,
373                           NULL);
374   g_main_loop_run (loop);
375   g_object_unref (ca);
376
377   /*
378    * Check that we get a reply to the GetId() method call.
379    */
380   g_dbus_connection_call (c,
381                           "org.freedesktop.DBus",  /* bus_name */
382                           "/org/freedesktop/DBus", /* object path */
383                           "org.freedesktop.DBus",  /* interface name */
384                           "GetId",                 /* method name */
385                           NULL, NULL,
386                           G_DBUS_CALL_FLAGS_NONE,
387                           -1,
388                           NULL,
389                           (GAsyncReadyCallback) msg_cb_expect_success,
390                           NULL);
391   g_main_loop_run (loop);
392
393   /*
394    * Check that we get an error reply to the NonExistantMethod() method call.
395    */
396   g_dbus_connection_call (c,
397                           "org.freedesktop.DBus",  /* bus_name */
398                           "/org/freedesktop/DBus", /* object path */
399                           "org.freedesktop.DBus",  /* interface name */
400                           "NonExistantMethod",     /* method name */
401                           NULL, NULL,
402                           G_DBUS_CALL_FLAGS_NONE,
403                           -1,
404                           NULL,
405                           (GAsyncReadyCallback) msg_cb_expect_error_unknown_method,
406                           NULL);
407   g_main_loop_run (loop);
408
409   /*
410    * Check that cancellation works when the message is already in flight.
411    */
412   ca = g_cancellable_new ();
413   g_dbus_connection_call (c,
414                           "org.freedesktop.DBus",  /* bus_name */
415                           "/org/freedesktop/DBus", /* object path */
416                           "org.freedesktop.DBus",  /* interface name */
417                           "GetId",                 /* method name */
418                           NULL, NULL,
419                           G_DBUS_CALL_FLAGS_NONE,
420                           -1,
421                           ca,
422                           (GAsyncReadyCallback) msg_cb_expect_error_cancelled_2,
423                           NULL);
424   g_cancellable_cancel (ca);
425   g_main_loop_run (loop);
426   g_object_unref (ca);
427
428   /*
429    * Check that we get an error when sending to a connection that is disconnected.
430    */
431   g_dbus_connection_set_exit_on_close (c, FALSE);
432   session_bus_down ();
433   _g_assert_signal_received (c, "closed");
434   g_assert (g_dbus_connection_is_closed (c));
435
436   g_dbus_connection_call (c,
437                           "org.freedesktop.DBus",  /* bus_name */
438                           "/org/freedesktop/DBus", /* object path */
439                           "org.freedesktop.DBus",  /* interface name */
440                           "GetId",                 /* method name */
441                           NULL, NULL,
442                           G_DBUS_CALL_FLAGS_NONE,
443                           -1,
444                           NULL,
445                           (GAsyncReadyCallback) msg_cb_expect_error_disconnected,
446                           NULL);
447   g_main_loop_run (loop);
448
449   _g_object_wait_for_single_ref (c);
450   g_object_unref (c);
451 }
452
453 /* ---------------------------------------------------------------------------------------------------- */
454 /* Connection signal tests */
455 /* ---------------------------------------------------------------------------------------------------- */
456
457 static void
458 test_connection_signal_handler (GDBusConnection  *connection,
459                                 const gchar      *sender_name,
460                                 const gchar      *object_path,
461                                 const gchar      *interface_name,
462                                 const gchar      *signal_name,
463                                 GVariant         *parameters,
464                                 gpointer         user_data)
465 {
466   gint *counter = user_data;
467   *counter += 1;
468
469   /*g_debug ("in test_connection_signal_handler (sender=%s path=%s interface=%s member=%s)",
470            sender_name,
471            object_path,
472            interface_name,
473            signal_name);*/
474
475   g_main_loop_quit (loop);
476 }
477
478 static void
479 test_connection_signals (void)
480 {
481   GDBusConnection *c1;
482   GDBusConnection *c2;
483   GDBusConnection *c3;
484   guint s1;
485   guint s1b;
486   guint s2;
487   guint s3;
488   gint count_s1;
489   gint count_s1b;
490   gint count_s2;
491   gint count_name_owner_changed;
492   GError *error;
493   gboolean ret;
494   GVariant *result;
495
496   error = NULL;
497
498   /*
499    * Bring up first separate connections
500    */
501   session_bus_up ();
502   /* if running with dbus-monitor, it claims the name :1.0 - so if we don't run with the monitor
503    * emulate this
504    */
505   if (g_getenv ("G_DBUS_MONITOR") == NULL)
506     {
507       c1 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
508       g_assert (c1 != NULL);
509       g_assert (!g_dbus_connection_is_closed (c1));
510       g_object_unref (c1);
511     }
512   c1 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
513   g_assert (c1 != NULL);
514   g_assert (!g_dbus_connection_is_closed (c1));
515   g_assert_cmpstr (g_dbus_connection_get_unique_name (c1), ==, ":1.1");
516
517   /*
518    * Install two signal handlers for the first connection
519    *
520    *  - Listen to the signal "Foo" from :1.2 (e.g. c2)
521    *  - Listen to the signal "Foo" from anyone (e.g. both c2 and c3)
522    *
523    * and then count how many times this signal handler was invoked.
524    */
525   s1 = g_dbus_connection_signal_subscribe (c1,
526                                            ":1.2",
527                                            "org.gtk.GDBus.ExampleInterface",
528                                            "Foo",
529                                            "/org/gtk/GDBus/ExampleInterface",
530                                            NULL,
531                                            G_DBUS_SIGNAL_FLAGS_NONE,
532                                            test_connection_signal_handler,
533                                            &count_s1,
534                                            NULL);
535   s2 = g_dbus_connection_signal_subscribe (c1,
536                                            NULL, /* match any sender */
537                                            "org.gtk.GDBus.ExampleInterface",
538                                            "Foo",
539                                            "/org/gtk/GDBus/ExampleInterface",
540                                            NULL,
541                                            G_DBUS_SIGNAL_FLAGS_NONE,
542                                            test_connection_signal_handler,
543                                            &count_s2,
544                                            NULL);
545   s3 = g_dbus_connection_signal_subscribe (c1,
546                                            "org.freedesktop.DBus",  /* sender */
547                                            "org.freedesktop.DBus",  /* interface */
548                                            "NameOwnerChanged",      /* member */
549                                            "/org/freedesktop/DBus", /* path */
550                                            NULL,
551                                            G_DBUS_SIGNAL_FLAGS_NONE,
552                                            test_connection_signal_handler,
553                                            &count_name_owner_changed,
554                                            NULL);
555   /* Note that s1b is *just like* s1 - this is to catch a bug where N
556    * subscriptions of the same rule causes N calls to each of the N
557    * subscriptions instead of just 1 call to each of the N subscriptions.
558    */
559   s1b = g_dbus_connection_signal_subscribe (c1,
560                                             ":1.2",
561                                             "org.gtk.GDBus.ExampleInterface",
562                                             "Foo",
563                                             "/org/gtk/GDBus/ExampleInterface",
564                                             NULL,
565                                             G_DBUS_SIGNAL_FLAGS_NONE,
566                                             test_connection_signal_handler,
567                                             &count_s1b,
568                                             NULL);
569   g_assert (s1 != 0);
570   g_assert (s1b != 0);
571   g_assert (s2 != 0);
572   g_assert (s3 != 0);
573
574   count_s1 = 0;
575   count_s1b = 0;
576   count_s2 = 0;
577   count_name_owner_changed = 0;
578
579   /*
580    * Bring up two other connections
581    */
582   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
583   g_assert (c2 != NULL);
584   g_assert (!g_dbus_connection_is_closed (c2));
585   g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
586   c3 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
587   g_assert (c3 != NULL);
588   g_assert (!g_dbus_connection_is_closed (c3));
589   g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
590
591   /*
592    * Make c2 emit "Foo" - we should catch it twice
593    *
594    * Note that there is no way to be sure that the signal subscriptions
595    * on c1 are effective yet - for all we know, the AddMatch() messages
596    * could sit waiting in a buffer somewhere between this process and
597    * the message bus. And emitting signals on c2 (a completely other
598    * socket!) will not necessarily change this.
599    *
600    * To ensure this is not the case, do a synchronous call on c1.
601    */
602   result = g_dbus_connection_call_sync (c1,
603                                         "org.freedesktop.DBus",  /* bus name */
604                                         "/org/freedesktop/DBus", /* object path */
605                                         "org.freedesktop.DBus",  /* interface name */
606                                         "GetId",                 /* method name */
607                                         NULL,                    /* parameters */
608                                         NULL,                    /* return type */
609                                         G_DBUS_CALL_FLAGS_NONE,
610                                         -1,
611                                         NULL,
612                                         &error);
613   g_assert_no_error (error);
614   g_assert (result != NULL);
615   g_variant_unref (result);
616   /* now, emit the signal on c2 */
617   ret = g_dbus_connection_emit_signal (c2,
618                                        NULL, /* destination bus name */
619                                        "/org/gtk/GDBus/ExampleInterface",
620                                        "org.gtk.GDBus.ExampleInterface",
621                                        "Foo",
622                                        NULL,
623                                        &error);
624   g_assert_no_error (error);
625   g_assert (ret);
626   while (!(count_s1 >= 1 && count_s2 >= 1))
627     g_main_loop_run (loop);
628   g_assert_cmpint (count_s1, ==, 1);
629   g_assert_cmpint (count_s2, ==, 1);
630
631   /*
632    * Make c3 emit "Foo" - we should catch it only once
633    */
634   ret = g_dbus_connection_emit_signal (c3,
635                                        NULL, /* destination bus name */
636                                        "/org/gtk/GDBus/ExampleInterface",
637                                        "org.gtk.GDBus.ExampleInterface",
638                                        "Foo",
639                                        NULL,
640                                        &error);
641   g_assert_no_error (error);
642   g_assert (ret);
643   while (!(count_s1 == 1 && count_s2 == 2))
644     g_main_loop_run (loop);
645   g_assert_cmpint (count_s1, ==, 1);
646   g_assert_cmpint (count_s2, ==, 2);
647
648   /*
649    * Also to check the total amount of NameOwnerChanged signals - use a 5 second ceiling
650    * to avoid spinning forever
651    */
652   gboolean quit_mainloop_fired;
653   guint quit_mainloop_id;
654   quit_mainloop_fired = FALSE;
655   quit_mainloop_id = g_timeout_add (5000, test_connection_quit_mainloop, &quit_mainloop_fired);
656   while (count_name_owner_changed < 2 && !quit_mainloop_fired)
657     g_main_loop_run (loop);
658   g_source_remove (quit_mainloop_id);
659   g_assert_cmpint (count_s1, ==, 1);
660   g_assert_cmpint (count_s2, ==, 2);
661   g_assert_cmpint (count_name_owner_changed, ==, 2);
662
663   g_dbus_connection_signal_unsubscribe (c1, s1);
664   g_dbus_connection_signal_unsubscribe (c1, s2);
665   g_dbus_connection_signal_unsubscribe (c1, s3);
666   g_dbus_connection_signal_unsubscribe (c1, s1b);
667
668   _g_object_wait_for_single_ref (c1);
669   _g_object_wait_for_single_ref (c2);
670   _g_object_wait_for_single_ref (c3);
671
672   g_object_unref (c1);
673   g_object_unref (c2);
674   g_object_unref (c3);
675
676   session_bus_down ();
677 }
678
679 /* ---------------------------------------------------------------------------------------------------- */
680
681 typedef struct
682 {
683   guint num_handled;
684   guint num_outgoing;
685   guint32 serial;
686 } FilterData;
687
688 static gboolean
689 filter_func (GDBusConnection *connection,
690              GDBusMessage    *message,
691              gboolean         incoming,
692              gpointer         user_data)
693 {
694   FilterData *data = user_data;
695   guint32 reply_serial;
696
697   if (incoming)
698     {
699       reply_serial = g_dbus_message_get_reply_serial (message);
700       if (reply_serial == data->serial)
701         data->num_handled += 1;
702     }
703   else
704     {
705       data->num_outgoing += 1;
706     }
707
708   return FALSE;
709 }
710
711 static void
712 test_connection_filter (void)
713 {
714   GDBusConnection *c;
715   FilterData data;
716   GDBusMessage *m;
717   GDBusMessage *r;
718   GError *error;
719   guint filter_id;
720
721   memset (&data, '\0', sizeof (FilterData));
722
723   session_bus_up ();
724
725   error = NULL;
726   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
727   g_assert_no_error (error);
728   g_assert (c != NULL);
729
730   filter_id = g_dbus_connection_add_filter (c,
731                                             filter_func,
732                                             &data,
733                                             NULL);
734
735   m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
736                                       "/org/freedesktop/DBus", /* path */
737                                       "org.freedesktop.DBus", /* interface */
738                                       "GetNameOwner");
739   g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
740   error = NULL;
741   g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
742   g_assert_no_error (error);
743
744   while (data.num_handled == 0)
745     g_thread_yield ();
746
747   g_dbus_message_set_serial (m, 0);
748   g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
749   g_assert_no_error (error);
750
751   while (data.num_handled == 1)
752     g_thread_yield ();
753
754   g_dbus_message_set_serial (m, 0);
755   r = g_dbus_connection_send_message_with_reply_sync (c,
756                                                       m,
757                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
758                                                       -1,
759                                                       &data.serial,
760                                                       NULL, /* GCancellable */
761                                                       &error);
762   g_assert_no_error (error);
763   g_assert (r != NULL);
764   g_object_unref (r);
765   g_assert_cmpint (data.num_handled, ==, 3);
766
767   g_dbus_connection_remove_filter (c, filter_id);
768
769   g_dbus_message_set_serial (m, 0);
770   r = g_dbus_connection_send_message_with_reply_sync (c,
771                                                       m,
772                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
773                                                       -1,
774                                                       &data.serial,
775                                                       NULL, /* GCancellable */
776                                                       &error);
777   g_assert_no_error (error);
778   g_assert (r != NULL);
779   g_object_unref (r);
780   g_assert_cmpint (data.num_handled, ==, 3);
781   g_assert_cmpint (data.num_outgoing, ==, 3);
782
783   _g_object_wait_for_single_ref (c);
784   g_object_unref (c);
785   g_object_unref (m);
786
787   session_bus_down ();
788 }
789
790 /* ---------------------------------------------------------------------------------------------------- */
791
792 static void
793 test_connection_flush_signal_handler (GDBusConnection  *connection,
794                                       const gchar      *sender_name,
795                                       const gchar      *object_path,
796                                       const gchar      *interface_name,
797                                       const gchar      *signal_name,
798                                       GVariant         *parameters,
799                                       gpointer         user_data)
800 {
801   g_main_loop_quit (loop);
802 }
803
804 static gboolean
805 test_connection_flush_on_timeout (gpointer user_data)
806 {
807   guint iteration = GPOINTER_TO_UINT (user_data);
808   g_printerr ("Timeout waiting 1000 msec on iteration %d\n", iteration);
809   g_assert_not_reached ();
810   return FALSE;
811 }
812
813 static void
814 test_connection_flush (void)
815 {
816   GDBusConnection *connection;
817   GError *error;
818   guint n;
819   guint signal_handler_id;
820
821   session_bus_up ();
822
823   error = NULL;
824   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
825   g_assert_no_error (error);
826   g_assert (connection != NULL);
827
828   signal_handler_id = g_dbus_connection_signal_subscribe (connection,
829                                                           NULL, /* sender */
830                                                           "org.gtk.GDBus.FlushInterface",
831                                                           "SomeSignal",
832                                                           "/org/gtk/GDBus/FlushObject",
833                                                           NULL,
834                                                           G_DBUS_SIGNAL_FLAGS_NONE,
835                                                           test_connection_flush_signal_handler,
836                                                           NULL,
837                                                           NULL);
838   g_assert_cmpint (signal_handler_id, !=, 0);
839
840   for (n = 0; n < 50; n++)
841     {
842       gboolean ret;
843       gint exit_status;
844       guint timeout_mainloop_id;
845
846       error = NULL;
847       ret = g_spawn_command_line_sync ("./gdbus-connection-flush-helper",
848                                        NULL, /* stdout */
849                                        NULL, /* stderr */
850                                        &exit_status,
851                                        &error);
852       g_assert_no_error (error);
853       g_assert (WIFEXITED (exit_status));
854       g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
855       g_assert (ret);
856
857       timeout_mainloop_id = g_timeout_add (1000, test_connection_flush_on_timeout, GUINT_TO_POINTER (n));
858       g_main_loop_run (loop);
859       g_source_remove (timeout_mainloop_id);
860     }
861
862   g_dbus_connection_signal_unsubscribe (connection, signal_handler_id);
863   _g_object_wait_for_single_ref (connection);
864   g_object_unref (connection);
865
866   session_bus_down ();
867 }
868
869 static void
870 test_connection_basic (void)
871 {
872   GDBusConnection *connection;
873   GError *error;
874   GDBusCapabilityFlags flags;
875   gchar *guid;
876   gchar *name;
877   gboolean closed;
878   gboolean exit_on_close;
879   GIOStream *stream;
880   GCredentials *credentials;
881
882   session_bus_up ();
883
884   error = NULL;
885   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
886   g_assert_no_error (error);
887   g_assert (connection != NULL);
888
889   flags = g_dbus_connection_get_capabilities (connection);
890   g_assert (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
891             flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
892
893   credentials = g_dbus_connection_get_peer_credentials (connection);
894   g_assert (credentials == NULL);
895
896   g_object_get (connection,
897                 "stream", &stream,
898                 "guid", &guid,
899                 "unique-name", &name,
900                 "closed", &closed,
901                 "exit-on-close", &exit_on_close,
902                 "capabilities", &flags,
903                 NULL);
904
905   g_assert (G_IS_IO_STREAM (stream));
906   g_assert (g_dbus_is_guid (guid));
907   g_assert (g_dbus_is_unique_name (name));
908   g_assert (!closed);
909   g_assert (exit_on_close);
910   g_assert (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
911             flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
912
913   g_object_unref (stream);
914   g_object_unref (connection);
915   g_free (name);
916   g_free (guid);
917
918   session_bus_down ();
919 }
920
921 /* ---------------------------------------------------------------------------------------------------- */
922
923 /* Message size > 20MiB ... should be enough to make sure the message
924  * is fragmented when shoved across any transport
925  */
926 #define LARGE_MESSAGE_STRING_LENGTH (20*1024*1024)
927
928 static void
929 large_message_on_name_appeared (GDBusConnection *connection,
930                                 const gchar *name,
931                                 const gchar *name_owner,
932                                 gpointer user_data)
933 {
934   GError *error;
935   gchar *request;
936   const gchar *reply;
937   GVariant *result;
938   guint n;
939
940   request = g_new (gchar, LARGE_MESSAGE_STRING_LENGTH + 1);
941   for (n = 0; n < LARGE_MESSAGE_STRING_LENGTH; n++)
942     request[n] = '0' + (n%10);
943   request[n] = '\0';
944
945   error = NULL;
946   result = g_dbus_connection_call_sync (connection,
947                                         "com.example.TestService",      /* bus name */
948                                         "/com/example/TestObject",      /* object path */
949                                         "com.example.Frob",             /* interface name */
950                                         "HelloWorld",                   /* method name */
951                                         g_variant_new ("(s)", request), /* parameters */
952                                         G_VARIANT_TYPE ("(s)"),         /* return type */
953                                         G_DBUS_CALL_FLAGS_NONE,
954                                         -1,
955                                         NULL,
956                                         &error);
957   g_assert_no_error (error);
958   g_assert (result != NULL);
959   g_variant_get (result, "(&s)", &reply);
960   g_assert_cmpint (strlen (reply), >, LARGE_MESSAGE_STRING_LENGTH);
961   g_assert (g_str_has_prefix (reply, "You greeted me with '01234567890123456789012"));
962   g_assert (g_str_has_suffix (reply, "6789'. Thanks!"));
963   g_variant_unref (result);
964
965   g_free (request);
966
967   g_main_loop_quit (loop);
968 }
969
970 static void
971 large_message_on_name_vanished (GDBusConnection *connection,
972                                 const gchar *name,
973                                 gpointer user_data)
974 {
975 }
976
977 static void
978 test_connection_large_message (void)
979 {
980   guint watcher_id;
981
982   session_bus_up ();
983
984   /* this is safe; testserver will exit once the bus goes away */
985   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
986
987   watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
988                                  "com.example.TestService",
989                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
990                                  large_message_on_name_appeared,
991                                  large_message_on_name_vanished,
992                                  NULL,  /* user_data */
993                                  NULL); /* GDestroyNotify */
994   g_main_loop_run (loop);
995   g_bus_unwatch_name (watcher_id);
996
997   session_bus_down ();
998 }
999
1000 /* ---------------------------------------------------------------------------------------------------- */
1001
1002 int
1003 main (int   argc,
1004       char *argv[])
1005 {
1006   g_type_init ();
1007   g_test_init (&argc, &argv, NULL);
1008
1009   /* all the tests rely on a shared main loop */
1010   loop = g_main_loop_new (NULL, FALSE);
1011
1012   /* all the tests use a session bus with a well-known address that we can bring up and down
1013    * using session_bus_up() and session_bus_down().
1014    */
1015   g_unsetenv ("DISPLAY");
1016   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
1017
1018   g_test_add_func ("/gdbus/connection/basic", test_connection_basic);
1019   g_test_add_func ("/gdbus/connection/life-cycle", test_connection_life_cycle);
1020   g_test_add_func ("/gdbus/connection/send", test_connection_send);
1021   g_test_add_func ("/gdbus/connection/signals", test_connection_signals);
1022   g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
1023   g_test_add_func ("/gdbus/connection/flush", test_connection_flush);
1024   g_test_add_func ("/gdbus/connection/large_message", test_connection_large_message);
1025   return g_test_run();
1026 }