GDBus: Add GDBusSignalFlags and use it in g_dbus_connection_signal_subscribe()
[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 /* ---------------------------------------------------------------------------------------------------- */
36 /* Connection life-cycle testing */
37 /* ---------------------------------------------------------------------------------------------------- */
38
39 static void
40 test_connection_life_cycle (void)
41 {
42   gboolean ret;
43   GDBusConnection *c;
44   GDBusConnection *c2;
45   GError *error;
46
47   error = NULL;
48
49   /*
50    * Check for correct behavior when no bus is present
51    *
52    */
53   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
54   _g_assert_error_domain (error, G_IO_ERROR);
55   g_assert (!g_dbus_error_is_remote_error (error));
56   g_assert (c == NULL);
57   g_error_free (error);
58   error = NULL;
59
60   /*
61    *  Check for correct behavior when a bus is present
62    */
63   session_bus_up ();
64   /* case 1 */
65   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
66   g_assert_no_error (error);
67   g_assert (c != NULL);
68   g_assert (!g_dbus_connection_is_closed (c));
69
70   /*
71    * Check that singleton handling work
72    */
73   c2 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
74   g_assert_no_error (error);
75   g_assert (c2 != NULL);
76   g_assert (c == c2);
77   g_object_unref (c2);
78
79   /*
80    * Check that private connections work
81    */
82   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
83   g_assert_no_error (error);
84   g_assert (c2 != NULL);
85   g_assert (c != c2);
86   g_object_unref (c2);
87
88   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &error);
89   g_assert_no_error (error);
90   g_assert (c2 != NULL);
91   g_assert (!g_dbus_connection_is_closed (c2));
92   ret = g_dbus_connection_close_sync (c2, NULL, &error);
93   g_assert_no_error (error);
94   g_assert (ret);
95   _g_assert_signal_received (c2, "closed");
96   g_assert (g_dbus_connection_is_closed (c2));
97   ret = g_dbus_connection_close_sync (c2, NULL, &error);
98   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
99   g_assert (!ret);
100   g_object_unref (c2);
101
102   /*
103    *  Check for correct behavior when the bus goes away
104    *
105    */
106   g_assert (!g_dbus_connection_is_closed (c));
107   g_dbus_connection_set_exit_on_close (c, FALSE);
108   session_bus_down ();
109   if (!g_dbus_connection_is_closed (c))
110     _g_assert_signal_received (c, "closed");
111   g_assert (g_dbus_connection_is_closed (c));
112
113   _g_object_wait_for_single_ref (c);
114   g_object_unref (c);
115 }
116
117 /* ---------------------------------------------------------------------------------------------------- */
118 /* Test that sending and receiving messages work as expected */
119 /* ---------------------------------------------------------------------------------------------------- */
120
121 static void
122 msg_cb_expect_error_disconnected (GDBusConnection *connection,
123                                   GAsyncResult    *res,
124                                   gpointer         user_data)
125 {
126   GError *error;
127   GVariant *result;
128
129   error = NULL;
130   result = g_dbus_connection_call_finish (connection,
131                                           res,
132                                           &error);
133   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
134   g_assert (!g_dbus_error_is_remote_error (error));
135   g_error_free (error);
136   g_assert (result == NULL);
137
138   g_main_loop_quit (loop);
139 }
140
141 static void
142 msg_cb_expect_error_unknown_method (GDBusConnection *connection,
143                                     GAsyncResult    *res,
144                                     gpointer         user_data)
145 {
146   GError *error;
147   GVariant *result;
148
149   error = NULL;
150   result = g_dbus_connection_call_finish (connection,
151                                           res,
152                                           &error);
153   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
154   g_assert (g_dbus_error_is_remote_error (error));
155   g_assert (result == NULL);
156
157   g_main_loop_quit (loop);
158 }
159
160 static void
161 msg_cb_expect_success (GDBusConnection *connection,
162                        GAsyncResult    *res,
163                        gpointer         user_data)
164 {
165   GError *error;
166   GVariant *result;
167
168   error = NULL;
169   result = g_dbus_connection_call_finish (connection,
170                                           res,
171                                           &error);
172   g_assert_no_error (error);
173   g_assert (result != NULL);
174   g_variant_unref (result);
175
176   g_main_loop_quit (loop);
177 }
178
179 static void
180 msg_cb_expect_error_cancelled (GDBusConnection *connection,
181                                GAsyncResult    *res,
182                                gpointer         user_data)
183 {
184   GError *error;
185   GVariant *result;
186
187   error = NULL;
188   result = g_dbus_connection_call_finish (connection,
189                                           res,
190                                           &error);
191   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
192   g_assert (!g_dbus_error_is_remote_error (error));
193   g_error_free (error);
194   g_assert (result == NULL);
195
196   g_main_loop_quit (loop);
197 }
198
199 static void
200 msg_cb_expect_error_cancelled_2 (GDBusConnection *connection,
201                                  GAsyncResult    *res,
202                                  gpointer         user_data)
203 {
204   GError *error;
205   GVariant *result;
206
207   error = NULL;
208   result = g_dbus_connection_call_finish (connection,
209                                           res,
210                                           &error);
211   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
212   g_assert (!g_dbus_error_is_remote_error (error));
213   g_error_free (error);
214   g_assert (result == NULL);
215
216   g_main_loop_quit (loop);
217 }
218
219 /* ---------------------------------------------------------------------------------------------------- */
220
221 static void
222 test_connection_send (void)
223 {
224   GDBusConnection *c;
225   GCancellable *ca;
226
227   session_bus_up ();
228
229   /* First, get an unopened connection */
230   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
231   g_assert (c != NULL);
232   g_assert (!g_dbus_connection_is_closed (c));
233
234   /*
235    * Check that we never actually send a message if the GCancellable
236    * is already cancelled - i.e.  we should get #G_IO_ERROR_CANCELLED
237    * when the actual connection is not up.
238    */
239   ca = g_cancellable_new ();
240   g_cancellable_cancel (ca);
241   g_dbus_connection_call (c,
242                           "org.freedesktop.DBus",  /* bus_name */
243                           "/org/freedesktop/DBus", /* object path */
244                           "org.freedesktop.DBus",  /* interface name */
245                           "GetId",                 /* method name */
246                           NULL, NULL,
247                           G_DBUS_CALL_FLAGS_NONE,
248                           -1,
249                           ca,
250                           (GAsyncReadyCallback) msg_cb_expect_error_cancelled,
251                           NULL);
252   g_main_loop_run (loop);
253   g_object_unref (ca);
254
255   /*
256    * Check that we get a reply to the GetId() method call.
257    */
258   g_dbus_connection_call (c,
259                           "org.freedesktop.DBus",  /* bus_name */
260                           "/org/freedesktop/DBus", /* object path */
261                           "org.freedesktop.DBus",  /* interface name */
262                           "GetId",                 /* method name */
263                           NULL, NULL,
264                           G_DBUS_CALL_FLAGS_NONE,
265                           -1,
266                           NULL,
267                           (GAsyncReadyCallback) msg_cb_expect_success,
268                           NULL);
269   g_main_loop_run (loop);
270
271   /*
272    * Check that we get an error reply to the NonExistantMethod() method call.
273    */
274   g_dbus_connection_call (c,
275                           "org.freedesktop.DBus",  /* bus_name */
276                           "/org/freedesktop/DBus", /* object path */
277                           "org.freedesktop.DBus",  /* interface name */
278                           "NonExistantMethod",     /* method name */
279                           NULL, NULL,
280                           G_DBUS_CALL_FLAGS_NONE,
281                           -1,
282                           NULL,
283                           (GAsyncReadyCallback) msg_cb_expect_error_unknown_method,
284                           NULL);
285   g_main_loop_run (loop);
286
287   /*
288    * Check that cancellation works when the message is already in flight.
289    */
290   ca = g_cancellable_new ();
291   g_dbus_connection_call (c,
292                           "org.freedesktop.DBus",  /* bus_name */
293                           "/org/freedesktop/DBus", /* object path */
294                           "org.freedesktop.DBus",  /* interface name */
295                           "GetId",                 /* method name */
296                           NULL, NULL,
297                           G_DBUS_CALL_FLAGS_NONE,
298                           -1,
299                           ca,
300                           (GAsyncReadyCallback) msg_cb_expect_error_cancelled_2,
301                           NULL);
302   g_cancellable_cancel (ca);
303   g_main_loop_run (loop);
304   g_object_unref (ca);
305
306   /*
307    * Check that we get an error when sending to a connection that is disconnected.
308    */
309   g_dbus_connection_set_exit_on_close (c, FALSE);
310   session_bus_down ();
311   _g_assert_signal_received (c, "closed");
312   g_assert (g_dbus_connection_is_closed (c));
313
314   g_dbus_connection_call (c,
315                           "org.freedesktop.DBus",  /* bus_name */
316                           "/org/freedesktop/DBus", /* object path */
317                           "org.freedesktop.DBus",  /* interface name */
318                           "GetId",                 /* method name */
319                           NULL, NULL,
320                           G_DBUS_CALL_FLAGS_NONE,
321                           -1,
322                           NULL,
323                           (GAsyncReadyCallback) msg_cb_expect_error_disconnected,
324                           NULL);
325   g_main_loop_run (loop);
326
327   _g_object_wait_for_single_ref (c);
328   g_object_unref (c);
329 }
330
331 /* ---------------------------------------------------------------------------------------------------- */
332 /* Connection signal tests */
333 /* ---------------------------------------------------------------------------------------------------- */
334
335 static void
336 test_connection_signal_handler (GDBusConnection  *connection,
337                                 const gchar      *sender_name,
338                                 const gchar      *object_path,
339                                 const gchar      *interface_name,
340                                 const gchar      *signal_name,
341                                 GVariant         *parameters,
342                                 gpointer         user_data)
343 {
344   gint *counter = user_data;
345   *counter += 1;
346
347   /*g_debug ("in test_connection_signal_handler (sender=%s path=%s interface=%s member=%s)",
348            sender_name,
349            object_path,
350            interface_name,
351            signal_name);*/
352
353   g_main_loop_quit (loop);
354 }
355
356 static gboolean
357 test_connection_signal_quit_mainloop (gpointer user_data)
358 {
359   gboolean *quit_mainloop_fired = user_data;
360   *quit_mainloop_fired = TRUE;
361   g_main_loop_quit (loop);
362   return TRUE;
363 }
364
365 static void
366 test_connection_signals (void)
367 {
368   GDBusConnection *c1;
369   GDBusConnection *c2;
370   GDBusConnection *c3;
371   guint s1;
372   guint s1b;
373   guint s2;
374   guint s3;
375   gint count_s1;
376   gint count_s1b;
377   gint count_s2;
378   gint count_name_owner_changed;
379   GError *error;
380   gboolean ret;
381   GVariant *result;
382
383   error = NULL;
384
385   /*
386    * Bring up first separate connections
387    */
388   session_bus_up ();
389   /* if running with dbus-monitor, it claims the name :1.0 - so if we don't run with the monitor
390    * emulate this
391    */
392   if (g_getenv ("G_DBUS_MONITOR") == NULL)
393     {
394       c1 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
395       g_assert (c1 != NULL);
396       g_assert (!g_dbus_connection_is_closed (c1));
397       g_object_unref (c1);
398     }
399   c1 = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
400   g_assert (c1 != NULL);
401   g_assert (!g_dbus_connection_is_closed (c1));
402   g_assert_cmpstr (g_dbus_connection_get_unique_name (c1), ==, ":1.1");
403
404   /*
405    * Install two signal handlers for the first connection
406    *
407    *  - Listen to the signal "Foo" from :1.2 (e.g. c2)
408    *  - Listen to the signal "Foo" from anyone (e.g. both c2 and c3)
409    *
410    * and then count how many times this signal handler was invoked.
411    */
412   s1 = g_dbus_connection_signal_subscribe (c1,
413                                            ":1.2",
414                                            "org.gtk.GDBus.ExampleInterface",
415                                            "Foo",
416                                            "/org/gtk/GDBus/ExampleInterface",
417                                            NULL,
418                                            G_DBUS_SIGNAL_FLAGS_NONE,
419                                            test_connection_signal_handler,
420                                            &count_s1,
421                                            NULL);
422   s2 = g_dbus_connection_signal_subscribe (c1,
423                                            NULL, /* match any sender */
424                                            "org.gtk.GDBus.ExampleInterface",
425                                            "Foo",
426                                            "/org/gtk/GDBus/ExampleInterface",
427                                            NULL,
428                                            G_DBUS_SIGNAL_FLAGS_NONE,
429                                            test_connection_signal_handler,
430                                            &count_s2,
431                                            NULL);
432   s3 = g_dbus_connection_signal_subscribe (c1,
433                                            "org.freedesktop.DBus",  /* sender */
434                                            "org.freedesktop.DBus",  /* interface */
435                                            "NameOwnerChanged",      /* member */
436                                            "/org/freedesktop/DBus", /* path */
437                                            NULL,
438                                            G_DBUS_SIGNAL_FLAGS_NONE,
439                                            test_connection_signal_handler,
440                                            &count_name_owner_changed,
441                                            NULL);
442   /* Note that s1b is *just like* s1 - this is to catch a bug where N
443    * subscriptions of the same rule causes N calls to each of the N
444    * subscriptions instead of just 1 call to each of the N subscriptions.
445    */
446   s1b = g_dbus_connection_signal_subscribe (c1,
447                                             ":1.2",
448                                             "org.gtk.GDBus.ExampleInterface",
449                                             "Foo",
450                                             "/org/gtk/GDBus/ExampleInterface",
451                                             NULL,
452                                             G_DBUS_SIGNAL_FLAGS_NONE,
453                                             test_connection_signal_handler,
454                                             &count_s1b,
455                                             NULL);
456   g_assert (s1 != 0);
457   g_assert (s1b != 0);
458   g_assert (s2 != 0);
459   g_assert (s3 != 0);
460
461   count_s1 = 0;
462   count_s1b = 0;
463   count_s2 = 0;
464   count_name_owner_changed = 0;
465
466   /*
467    * Bring up two other connections
468    */
469   c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
470   g_assert (c2 != NULL);
471   g_assert (!g_dbus_connection_is_closed (c2));
472   g_assert_cmpstr (g_dbus_connection_get_unique_name (c2), ==, ":1.2");
473   c3 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
474   g_assert (c3 != NULL);
475   g_assert (!g_dbus_connection_is_closed (c3));
476   g_assert_cmpstr (g_dbus_connection_get_unique_name (c3), ==, ":1.3");
477
478   /*
479    * Make c2 emit "Foo" - we should catch it twice
480    *
481    * Note that there is no way to be sure that the signal subscriptions
482    * on c1 are effective yet - for all we know, the AddMatch() messages
483    * could sit waiting in a buffer somewhere between this process and
484    * the message bus. And emitting signals on c2 (a completely other
485    * socket!) will not necessarily change this.
486    *
487    * To ensure this is not the case, do a synchronous call on c1.
488    */
489   result = g_dbus_connection_call_sync (c1,
490                                         "org.freedesktop.DBus",  /* bus name */
491                                         "/org/freedesktop/DBus", /* object path */
492                                         "org.freedesktop.DBus",  /* interface name */
493                                         "GetId",                 /* method name */
494                                         NULL,                    /* parameters */
495                                         NULL,                    /* return type */
496                                         G_DBUS_CALL_FLAGS_NONE,
497                                         -1,
498                                         NULL,
499                                         &error);
500   g_assert_no_error (error);
501   g_assert (result != NULL);
502   g_variant_unref (result);
503   /* now, emit the signal on c2 */
504   ret = g_dbus_connection_emit_signal (c2,
505                                        NULL, /* destination bus name */
506                                        "/org/gtk/GDBus/ExampleInterface",
507                                        "org.gtk.GDBus.ExampleInterface",
508                                        "Foo",
509                                        NULL,
510                                        &error);
511   g_assert_no_error (error);
512   g_assert (ret);
513   while (!(count_s1 >= 1 && count_s2 >= 1))
514     g_main_loop_run (loop);
515   g_assert_cmpint (count_s1, ==, 1);
516   g_assert_cmpint (count_s2, ==, 1);
517
518   /*
519    * Make c3 emit "Foo" - we should catch it only once
520    */
521   ret = g_dbus_connection_emit_signal (c3,
522                                        NULL, /* destination bus name */
523                                        "/org/gtk/GDBus/ExampleInterface",
524                                        "org.gtk.GDBus.ExampleInterface",
525                                        "Foo",
526                                        NULL,
527                                        &error);
528   g_assert_no_error (error);
529   g_assert (ret);
530   while (!(count_s1 == 1 && count_s2 == 2))
531     g_main_loop_run (loop);
532   g_assert_cmpint (count_s1, ==, 1);
533   g_assert_cmpint (count_s2, ==, 2);
534
535   /*
536    * Also to check the total amount of NameOwnerChanged signals - use a 5 second ceiling
537    * to avoid spinning forever
538    */
539   gboolean quit_mainloop_fired;
540   guint quit_mainloop_id;
541   quit_mainloop_fired = FALSE;
542   quit_mainloop_id = g_timeout_add (5000, test_connection_signal_quit_mainloop, &quit_mainloop_fired);
543   while (count_name_owner_changed < 2 && !quit_mainloop_fired)
544     g_main_loop_run (loop);
545   g_source_remove (quit_mainloop_id);
546   g_assert_cmpint (count_s1, ==, 1);
547   g_assert_cmpint (count_s2, ==, 2);
548   g_assert_cmpint (count_name_owner_changed, ==, 2);
549
550   g_dbus_connection_signal_unsubscribe (c1, s1);
551   g_dbus_connection_signal_unsubscribe (c1, s2);
552   g_dbus_connection_signal_unsubscribe (c1, s3);
553   g_dbus_connection_signal_unsubscribe (c1, s1b);
554
555   _g_object_wait_for_single_ref (c1);
556   _g_object_wait_for_single_ref (c2);
557   _g_object_wait_for_single_ref (c3);
558
559   g_object_unref (c1);
560   g_object_unref (c2);
561   g_object_unref (c3);
562
563   session_bus_down ();
564 }
565
566 /* ---------------------------------------------------------------------------------------------------- */
567
568 typedef struct
569 {
570   guint num_handled;
571   guint num_outgoing;
572   guint32 serial;
573 } FilterData;
574
575 static gboolean
576 filter_func (GDBusConnection *connection,
577              GDBusMessage    *message,
578              gboolean         incoming,
579              gpointer         user_data)
580 {
581   FilterData *data = user_data;
582   guint32 reply_serial;
583
584   if (incoming)
585     {
586       reply_serial = g_dbus_message_get_reply_serial (message);
587       if (reply_serial == data->serial)
588         data->num_handled += 1;
589     }
590   else
591     {
592       data->num_outgoing += 1;
593     }
594
595   return FALSE;
596 }
597
598 static void
599 test_connection_filter (void)
600 {
601   GDBusConnection *c;
602   FilterData data;
603   GDBusMessage *m;
604   GDBusMessage *r;
605   GError *error;
606   guint filter_id;
607
608   memset (&data, '\0', sizeof (FilterData));
609
610   session_bus_up ();
611
612   error = NULL;
613   c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
614   g_assert_no_error (error);
615   g_assert (c != NULL);
616
617   filter_id = g_dbus_connection_add_filter (c,
618                                             filter_func,
619                                             &data,
620                                             NULL);
621
622   m = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
623                                       "/org/freedesktop/DBus", /* path */
624                                       "org.freedesktop.DBus", /* interface */
625                                       "GetNameOwner");
626   g_dbus_message_set_body (m, g_variant_new ("(s)", "org.freedesktop.DBus"));
627   error = NULL;
628   g_dbus_connection_send_message (c, m, &data.serial, &error);
629   g_assert_no_error (error);
630
631   while (data.num_handled == 0)
632     g_thread_yield ();
633
634   g_dbus_message_set_serial (m, 0);
635   g_dbus_connection_send_message (c, m, &data.serial, &error);
636   g_assert_no_error (error);
637
638   while (data.num_handled == 1)
639     g_thread_yield ();
640
641   g_dbus_message_set_serial (m, 0);
642   r = g_dbus_connection_send_message_with_reply_sync (c,
643                                                       m,
644                                                       -1,
645                                                       &data.serial,
646                                                       NULL, /* GCancellable */
647                                                       &error);
648   g_assert_no_error (error);
649   g_assert (r != NULL);
650   g_object_unref (r);
651   g_assert_cmpint (data.num_handled, ==, 3);
652
653   g_dbus_connection_remove_filter (c, filter_id);
654
655   g_dbus_message_set_serial (m, 0);
656   r = g_dbus_connection_send_message_with_reply_sync (c,
657                                                       m,
658                                                       -1,
659                                                       &data.serial,
660                                                       NULL, /* GCancellable */
661                                                       &error);
662   g_assert_no_error (error);
663   g_assert (r != NULL);
664   g_object_unref (r);
665   g_assert_cmpint (data.num_handled, ==, 3);
666   g_assert_cmpint (data.num_outgoing, ==, 3);
667
668   _g_object_wait_for_single_ref (c);
669   g_object_unref (c);
670   g_object_unref (m);
671
672   session_bus_down ();
673 }
674
675 /* ---------------------------------------------------------------------------------------------------- */
676
677 static void
678 test_connection_flush_signal_handler (GDBusConnection  *connection,
679                                       const gchar      *sender_name,
680                                       const gchar      *object_path,
681                                       const gchar      *interface_name,
682                                       const gchar      *signal_name,
683                                       GVariant         *parameters,
684                                       gpointer         user_data)
685 {
686   g_main_loop_quit (loop);
687 }
688
689 static gboolean
690 test_connection_flush_on_timeout (gpointer user_data)
691 {
692   guint iteration = GPOINTER_TO_UINT (user_data);
693   g_printerr ("Timeout waiting 1000 msec on iteration %d\n", iteration);
694   g_assert_not_reached ();
695   return FALSE;
696 }
697
698 static void
699 test_connection_flush (void)
700 {
701   GDBusConnection *connection;
702   GError *error;
703   guint n;
704   guint signal_handler_id;
705
706   session_bus_up ();
707
708   error = NULL;
709   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
710   g_assert_no_error (error);
711   g_assert (connection != NULL);
712
713   signal_handler_id = g_dbus_connection_signal_subscribe (connection,
714                                                           NULL, /* sender */
715                                                           "org.gtk.GDBus.FlushInterface",
716                                                           "SomeSignal",
717                                                           "/org/gtk/GDBus/FlushObject",
718                                                           NULL,
719                                                           G_DBUS_SIGNAL_FLAGS_NONE,
720                                                           test_connection_flush_signal_handler,
721                                                           NULL,
722                                                           NULL);
723   g_assert_cmpint (signal_handler_id, !=, 0);
724
725   for (n = 0; n < 50; n++)
726     {
727       gboolean ret;
728       gint exit_status;
729       guint timeout_mainloop_id;
730
731       error = NULL;
732       ret = g_spawn_command_line_sync ("./gdbus-connection-flush-helper",
733                                        NULL, /* stdout */
734                                        NULL, /* stderr */
735                                        &exit_status,
736                                        &error);
737       g_assert_no_error (error);
738       g_assert (WIFEXITED (exit_status));
739       g_assert_cmpint (WEXITSTATUS (exit_status), ==, 0);
740       g_assert (ret);
741
742       timeout_mainloop_id = g_timeout_add (1000, test_connection_flush_on_timeout, GUINT_TO_POINTER (n));
743       g_main_loop_run (loop);
744       g_source_remove (timeout_mainloop_id);
745     }
746
747   g_dbus_connection_signal_unsubscribe (connection, signal_handler_id);
748   _g_object_wait_for_single_ref (connection);
749   g_object_unref (connection);
750
751   session_bus_down ();
752 }
753
754 /* ---------------------------------------------------------------------------------------------------- */
755
756 int
757 main (int   argc,
758       char *argv[])
759 {
760   g_type_init ();
761   g_test_init (&argc, &argv, NULL);
762
763   /* all the tests rely on a shared main loop */
764   loop = g_main_loop_new (NULL, FALSE);
765
766   /* all the tests use a session bus with a well-known address that we can bring up and down
767    * using session_bus_up() and session_bus_down().
768    */
769   g_unsetenv ("DISPLAY");
770   g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
771
772   g_test_add_func ("/gdbus/connection-life-cycle", test_connection_life_cycle);
773   g_test_add_func ("/gdbus/connection-send", test_connection_send);
774   g_test_add_func ("/gdbus/connection-signals", test_connection_signals);
775   g_test_add_func ("/gdbus/connection-filter", test_connection_filter);
776   g_test_add_func ("/gdbus/connection-flush", test_connection_flush);
777   return g_test_run();
778 }