Plug a mem leak in gdbus-connection test
[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_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 gboolean
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 FALSE;
710 }
711
712 static void
713 test_connection_filter (void)
714 {
715   GDBusConnection *c;
716   FilterData data;
717   GDBusMessage *m;
718   GDBusMessage *r;
719   GError *error;
720   guint filter_id;
721
722   memset (&data, '\0', sizeof (FilterData));
723
724   session_bus_up ();
725
726   error = NULL;
727   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
728   g_assert_no_error (error);
729   g_assert (c != NULL);
730
731   filter_id = g_dbus_connection_add_filter (c,
732                                             filter_func,
733                                             &data,
734                                             NULL);
735
736   m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
737                                       "/org/freedesktop/DBus", /* path */
738                                       "org.freedesktop.DBus", /* interface */
739                                       "GetNameOwner");
740   g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
741   error = NULL;
742   g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
743   g_assert_no_error (error);
744
745   while (data.num_handled == 0)
746     g_thread_yield ();
747
748   g_dbus_message_set_serial (m, 0);
749   g_dbus_connection_send_message (c, m, G_DBUS_SEND_MESSAGE_FLAGS_NONE, &data.serial, &error);
750   g_assert_no_error (error);
751
752   while (data.num_handled == 1)
753     g_thread_yield ();
754
755   g_dbus_message_set_serial (m, 0);
756   r = g_dbus_connection_send_message_with_reply_sync (c,
757                                                       m,
758                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
759                                                       -1,
760                                                       &data.serial,
761                                                       NULL, /* GCancellable */
762                                                       &error);
763   g_assert_no_error (error);
764   g_assert (r != NULL);
765   g_object_unref (r);
766   g_assert_cmpint (data.num_handled, ==, 3);
767
768   g_dbus_connection_remove_filter (c, filter_id);
769
770   g_dbus_message_set_serial (m, 0);
771   r = g_dbus_connection_send_message_with_reply_sync (c,
772                                                       m,
773                                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
774                                                       -1,
775                                                       &data.serial,
776                                                       NULL, /* GCancellable */
777                                                       &error);
778   g_assert_no_error (error);
779   g_assert (r != NULL);
780   g_object_unref (r);
781   g_assert_cmpint (data.num_handled, ==, 3);
782   g_assert_cmpint (data.num_outgoing, ==, 3);
783
784   _g_object_wait_for_single_ref (c);
785   g_object_unref (c);
786   g_object_unref (m);
787
788   session_bus_down ();
789 }
790
791 /* ---------------------------------------------------------------------------------------------------- */
792
793 static void
794 test_connection_flush_signal_handler (GDBusConnection  *connection,
795                                       const gchar      *sender_name,
796                                       const gchar      *object_path,
797                                       const gchar      *interface_name,
798                                       const gchar      *signal_name,
799                                       GVariant         *parameters,
800                                       gpointer         user_data)
801 {
802   g_main_loop_quit (loop);
803 }
804
805 static gboolean
806 test_connection_flush_on_timeout (gpointer user_data)
807 {
808   guint iteration = GPOINTER_TO_UINT (user_data);
809   g_printerr ("Timeout waiting 1000 msec on iteration %d\n", iteration);
810   g_assert_not_reached ();
811   return FALSE;
812 }
813
814 static void
815 test_connection_flush (void)
816 {
817   GDBusConnection *connection;
818   GError *error;
819   guint n;
820   guint signal_handler_id;
821
822   session_bus_up ();
823
824   error = NULL;
825   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
826   g_assert_no_error (error);
827   g_assert (connection != NULL);
828
829   signal_handler_id = g_dbus_connection_signal_subscribe (connection,
830                                                           NULL, /* sender */
831                                                           "org.gtk.GDBus.FlushInterface",
832                                                           "SomeSignal",
833                                                           "/org/gtk/GDBus/FlushObject",
834                                                           NULL,
835                                                           G_DBUS_SIGNAL_FLAGS_NONE,
836                                                           test_connection_flush_signal_handler,
837                                                           NULL,
838                                                           NULL);
839   g_assert_cmpint (signal_handler_id, !=, 0);
840
841   for (n = 0; n < 50; n++)
842     {
843       gboolean ret;
844       gint exit_status;
845       guint timeout_mainloop_id;
846
847       error = NULL;
848       ret = g_spawn_command_line_sync ("./gdbus-connection-flush-helper",
849                                        NULL, /* stdout */
850                                        NULL, /* stderr */
851                                        &exit_status,
852                                        &error);
853       g_assert_no_error (error);
854       g_assert (WIFEXITED (exit_status));
855       g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
856       g_assert (ret);
857
858       timeout_mainloop_id = g_timeout_add (1000, test_connection_flush_on_timeout, GUINT_TO_POINTER (n));
859       g_main_loop_run (loop);
860       g_source_remove (timeout_mainloop_id);
861     }
862
863   g_dbus_connection_signal_unsubscribe (connection, signal_handler_id);
864   _g_object_wait_for_single_ref (connection);
865   g_object_unref (connection);
866
867   session_bus_down ();
868 }
869
870 static void
871 test_connection_basic (void)
872 {
873   GDBusConnection *connection;
874   GError *error;
875   GDBusCapabilityFlags flags;
876   gchar *guid;
877   gchar *name;
878   gboolean closed;
879   gboolean exit_on_close;
880   GIOStream *stream;
881   GCredentials *credentials;
882
883   session_bus_up ();
884
885   error = NULL;
886   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
887   g_assert_no_error (error);
888   g_assert (connection != NULL);
889
890   flags = g_dbus_connection_get_capabilities (connection);
891   g_assert (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
892             flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
893
894   credentials = g_dbus_connection_get_peer_credentials (connection);
895   g_assert (credentials == NULL);
896
897   g_object_get (connection,
898                 "stream", &stream,
899                 "guid", &guid,
900                 "unique-name", &name,
901                 "closed", &closed,
902                 "exit-on-close", &exit_on_close,
903                 "capabilities", &flags,
904                 NULL);
905
906   g_assert (G_IS_IO_STREAM (stream));
907   g_assert (g_dbus_is_guid (guid));
908   g_assert (g_dbus_is_unique_name (name));
909   g_assert (!closed);
910   g_assert (exit_on_close);
911   g_assert (flags == G_DBUS_CAPABILITY_FLAGS_NONE ||
912             flags == G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
913
914   g_object_unref (stream);
915   g_object_unref (connection);
916   g_free (name);
917   g_free (guid);
918
919   session_bus_down ();
920 }
921
922 /* ---------------------------------------------------------------------------------------------------- */
923
924 /* Message size > 20MiB ... should be enough to make sure the message
925  * is fragmented when shoved across any transport
926  */
927 #define LARGE_MESSAGE_STRING_LENGTH (20*1024*1024)
928
929 static void
930 large_message_on_name_appeared (GDBusConnection *connection,
931                                 const gchar *name,
932                                 const gchar *name_owner,
933                                 gpointer user_data)
934 {
935   GError *error;
936   gchar *request;
937   const gchar *reply;
938   GVariant *result;
939   guint n;
940
941   request = g_new (gchar, LARGE_MESSAGE_STRING_LENGTH + 1);
942   for (n = 0; n < LARGE_MESSAGE_STRING_LENGTH; n++)
943     request[n] = '0' + (n%10);
944   request[n] = '\0';
945
946   error = NULL;
947   result = g_dbus_connection_call_sync (connection,
948                                         "com.example.TestService",      /* bus name */
949                                         "/com/example/TestObject",      /* object path */
950                                         "com.example.Frob",             /* interface name */
951                                         "HelloWorld",                   /* method name */
952                                         g_variant_new ("(s)", request), /* parameters */
953                                         G_VARIANT_TYPE ("(s)"),         /* return type */
954                                         G_DBUS_CALL_FLAGS_NONE,
955                                         -1,
956                                         NULL,
957                                         &error);
958   g_assert_no_error (error);
959   g_assert (result != NULL);
960   g_variant_get (result, "(&s)", &reply);
961   g_assert_cmpint (strlen (reply), >, LARGE_MESSAGE_STRING_LENGTH);
962   g_assert (g_str_has_prefix (reply, "You greeted me with '01234567890123456789012"));
963   g_assert (g_str_has_suffix (reply, "6789'. Thanks!"));
964   g_variant_unref (result);
965
966   g_free (request);
967
968   g_main_loop_quit (loop);
969 }
970
971 static void
972 large_message_on_name_vanished (GDBusConnection *connection,
973                                 const gchar *name,
974                                 gpointer user_data)
975 {
976 }
977
978 static void
979 test_connection_large_message (void)
980 {
981   guint watcher_id;
982
983   session_bus_up ();
984
985   /* this is safe; testserver will exit once the bus goes away */
986   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
987
988   watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
989                                  "com.example.TestService",
990                                  G_BUS_NAME_WATCHER_FLAGS_NONE,
991                                  large_message_on_name_appeared,
992                                  large_message_on_name_vanished,
993                                  NULL,  /* user_data */
994                                  NULL); /* GDestroyNotify */
995   g_main_loop_run (loop);
996   g_bus_unwatch_name (watcher_id);
997
998   session_bus_down ();
999 }
1000
1001 /* ---------------------------------------------------------------------------------------------------- */
1002
1003 int
1004 main (int   argc,
1005       char *argv[])
1006 {
1007   g_type_init ();
1008   g_test_init (&argc, &argv, NULL);
1009
1010   /* all the tests rely on a shared main loop */
1011   loop = g_main_loop_new (NULL, FALSE);
1012
1013   /* all the tests use a session bus with a well-known address that we can bring up and down
1014    * using session_bus_up() and session_bus_down().
1015    */
1016   g_unsetenv ("DISPLAY");
1017   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
1018
1019   g_test_add_func ("/gdbus/connection/basic", test_connection_basic);
1020   g_test_add_func ("/gdbus/connection/life-cycle", test_connection_life_cycle);
1021   g_test_add_func ("/gdbus/connection/send", test_connection_send);
1022   g_test_add_func ("/gdbus/connection/signals", test_connection_signals);
1023   g_test_add_func ("/gdbus/connection/filter", test_connection_filter);
1024   g_test_add_func ("/gdbus/connection/flush", test_connection_flush);
1025   g_test_add_func ("/gdbus/connection/large_message", test_connection_large_message);
1026   return g_test_run();
1027 }