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