GDBus: Rename ::deny-authentication-peer to ::authorize-authenticated-peer
[platform/upstream/glib.git] / gio / tests / gdbus-peer.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 /* for open(2) */
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31
32 #include <gio/gunixsocketaddress.h>
33
34 #include "gdbus-tests.h"
35
36
37 #ifdef G_OS_UNIX
38 static gboolean is_unix = TRUE;
39 #else
40 static gboolean is_unix = FALSE;
41 #endif
42
43 static gchar *test_guid = NULL;
44 static GMainLoop *service_loop = NULL;
45 static GDBusServer *server = NULL;
46 static GMainLoop *loop = NULL;
47
48 /* ---------------------------------------------------------------------------------------------------- */
49 /* Test that peer-to-peer connections work */
50 /* ---------------------------------------------------------------------------------------------------- */
51
52
53 typedef struct
54 {
55   gboolean accept_connection;
56   gint num_connection_attempts;
57   GPtrArray *current_connections;
58   guint num_method_calls;
59   gboolean signal_received;
60 } PeerData;
61
62 static const gchar *test_interface_introspection_xml =
63   "<node>"
64   "  <interface name='org.gtk.GDBus.PeerTestInterface'>"
65   "    <method name='HelloPeer'>"
66   "      <arg type='s' name='greeting' direction='in'/>"
67   "      <arg type='s' name='response' direction='out'/>"
68   "    </method>"
69   "    <method name='EmitSignal'/>"
70   "    <method name='OpenFile'>"
71   "      <arg type='s' name='path' direction='in'/>"
72   "    </method>"
73   "    <signal name='PeerSignal'>"
74   "      <arg type='s' name='a_string'/>"
75   "    </signal>"
76   "    <property type='s' name='PeerProperty' access='read'/>"
77   "  </interface>"
78   "</node>";
79 static const GDBusInterfaceInfo *test_interface_introspection_data = NULL;
80
81 static void
82 test_interface_method_call (GDBusConnection       *connection,
83                             const gchar           *sender,
84                             const gchar           *object_path,
85                             const gchar           *interface_name,
86                             const gchar           *method_name,
87                             GVariant              *parameters,
88                             GDBusMethodInvocation *invocation,
89                             gpointer               user_data)
90 {
91   PeerData *data = user_data;
92
93   data->num_method_calls++;
94
95   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
96   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
97
98   if (g_strcmp0 (method_name, "HelloPeer") == 0)
99     {
100       const gchar *greeting;
101       gchar *response;
102
103       g_variant_get (parameters, "(s)", &greeting);
104
105       response = g_strdup_printf ("You greeted me with '%s'.",
106                                   greeting);
107       g_dbus_method_invocation_return_value (invocation,
108                                              g_variant_new ("(s)", response));
109       g_free (response);
110     }
111   else if (g_strcmp0 (method_name, "EmitSignal") == 0)
112     {
113       GError *error;
114
115       error = NULL;
116       g_dbus_connection_emit_signal (connection,
117                                      NULL,
118                                      "/org/gtk/GDBus/PeerTestObject",
119                                      "org.gtk.GDBus.PeerTestInterface",
120                                      "PeerSignal",
121                                      NULL,
122                                      &error);
123       g_assert_no_error (error);
124       g_dbus_method_invocation_return_value (invocation, NULL);
125     }
126   else if (g_strcmp0 (method_name, "OpenFile") == 0)
127     {
128       const gchar *path;
129       GDBusMessage *reply;
130       GError *error;
131       gint fd;
132       GUnixFDList *fd_list;
133
134       g_variant_get (parameters, "(s)", &path);
135
136       fd_list = g_unix_fd_list_new ();
137
138       error = NULL;
139
140       fd = open (path, O_RDONLY);
141       g_unix_fd_list_append (fd_list, fd, &error);
142       g_assert_no_error (error);
143       close (fd);
144
145       reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
146       g_dbus_message_set_unix_fd_list (reply, fd_list);
147       g_object_unref (invocation);
148
149       error = NULL;
150       g_dbus_connection_send_message (connection,
151                                       reply,
152                                       NULL, /* out_serial */
153                                       &error);
154       g_assert_no_error (error);
155       g_object_unref (reply);
156     }
157   else
158     {
159       g_assert_not_reached ();
160     }
161 }
162
163 static GVariant *
164 test_interface_get_property (GDBusConnection  *connection,
165                              const gchar      *sender,
166                              const gchar      *object_path,
167                              const gchar      *interface_name,
168                              const gchar      *property_name,
169                              GError          **error,
170                              gpointer          user_data)
171 {
172   g_assert_cmpstr (object_path, ==, "/org/gtk/GDBus/PeerTestObject");
173   g_assert_cmpstr (interface_name, ==, "org.gtk.GDBus.PeerTestInterface");
174   g_assert_cmpstr (property_name, ==, "PeerProperty");
175
176   return g_variant_new_string ("ThePropertyValue");
177 }
178
179
180 static const GDBusInterfaceVTable test_interface_vtable =
181 {
182   test_interface_method_call,
183   test_interface_get_property,
184   NULL  /* set_property */
185 };
186
187 static void
188 on_proxy_signal_received (GDBusProxy *proxy,
189                           gchar      *sender_name,
190                           gchar      *signal_name,
191                           GVariant   *parameters,
192                           gpointer    user_data)
193 {
194   PeerData *data = user_data;
195
196   data->signal_received = TRUE;
197
198   g_assert (sender_name == NULL);
199   g_assert_cmpstr (signal_name, ==, "PeerSignal");
200   g_main_loop_quit (loop);
201 }
202
203 /* ---------------------------------------------------------------------------------------------------- */
204
205 static gboolean
206 on_authorize_authenticated_peer (GDBusAuthObserver *observer,
207                                  GIOStream         *stream,
208                                  GCredentials      *credentials,
209                                  gpointer           user_data)
210 {
211   PeerData *data = user_data;
212   gboolean authorized;
213
214   data->num_connection_attempts++;
215
216   authorized = TRUE;
217   if (!data->accept_connection)
218     {
219       authorized = FALSE;
220       g_main_loop_quit (loop);
221     }
222
223   return authorized;
224 }
225
226 /* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
227 static void
228 on_new_connection (GDBusServer *server,
229                    GDBusConnection *connection,
230                    gpointer user_data)
231 {
232   PeerData *data = user_data;
233   GError *error;
234   guint reg_id;
235
236   //g_print ("Client connected.\n"
237   //         "Negotiated capabilities: unix-fd-passing=%d\n",
238   //         g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
239
240   g_ptr_array_add (data->current_connections, g_object_ref (connection));
241
242   /* export object on the newly established connection */
243   error = NULL;
244   reg_id = g_dbus_connection_register_object (connection,
245                                               "/org/gtk/GDBus/PeerTestObject",
246                                               test_interface_introspection_data,
247                                               &test_interface_vtable,
248                                               data,
249                                               NULL, /* GDestroyNotify for data */
250                                               &error);
251   g_assert_no_error (error);
252   g_assert (reg_id > 0);
253
254   g_main_loop_quit (loop);
255 }
256
257 static gpointer
258 service_thread_func (gpointer user_data)
259 {
260   PeerData *data = user_data;
261   GMainContext *service_context;
262   GDBusAuthObserver *observer;
263   GError *error;
264
265   service_context = g_main_context_new ();
266   g_main_context_push_thread_default (service_context);
267
268   error = NULL;
269   observer = g_dbus_auth_observer_new ();
270   server = g_dbus_server_new_sync (is_unix ? "unix:tmpdir=/tmp/gdbus-test-" : "nonce-tcp:",
271                                    G_DBUS_SERVER_FLAGS_NONE,
272                                    test_guid,
273                                    observer,
274                                    NULL, /* cancellable */
275                                    &error);
276   g_assert_no_error (error);
277
278   g_signal_connect (server,
279                     "new-connection",
280                     G_CALLBACK (on_new_connection),
281                     data);
282   g_signal_connect (observer,
283                     "authorize-authenticated-peer",
284                     G_CALLBACK (on_authorize_authenticated_peer),
285                     data);
286   g_object_unref (observer);
287
288   g_dbus_server_start (server);
289
290   service_loop = g_main_loop_new (service_context, FALSE);
291   g_main_loop_run (service_loop);
292
293   g_main_context_pop_thread_default (service_context);
294
295   g_main_loop_unref (service_loop);
296   g_main_context_unref (service_context);
297
298   /* test code specifically unrefs the server - see below */
299   g_assert (server == NULL);
300
301   return NULL;
302 }
303
304 #if 0
305 static gboolean
306 on_incoming_connection (GSocketService     *service,
307                         GSocketConnection  *socket_connection,
308                         GObject            *source_object,
309                         gpointer           user_data)
310 {
311   PeerData *data = user_data;
312
313   if (data->accept_connection)
314     {
315       GError *error;
316       guint reg_id;
317       GDBusConnection *connection;
318
319       error = NULL;
320       connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
321                                                test_guid,
322                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
323                                                NULL, /* cancellable */
324                                                &error);
325       g_assert_no_error (error);
326
327       g_ptr_array_add (data->current_connections, connection);
328
329       /* export object on the newly established connection */
330       error = NULL;
331       reg_id = g_dbus_connection_register_object (connection,
332                                                   "/org/gtk/GDBus/PeerTestObject",
333                                                   &test_interface_introspection_data,
334                                                   &test_interface_vtable,
335                                                   data,
336                                                   NULL, /* GDestroyNotify for data */
337                                                   &error);
338       g_assert_no_error (error);
339       g_assert (reg_id > 0);
340
341     }
342   else
343     {
344       /* don't do anything */
345     }
346
347   data->num_connection_attempts++;
348
349   g_main_loop_quit (loop);
350
351   /* stops other signal handlers from being invoked */
352   return TRUE;
353 }
354
355 static gpointer
356 service_thread_func (gpointer data)
357 {
358   GMainContext *service_context;
359   gchar *socket_path;
360   GSocketAddress *address;
361   GError *error;
362
363   service_context = g_main_context_new ();
364   g_main_context_push_thread_default (service_context);
365
366   socket_path = g_strdup_printf ("/tmp/gdbus-test-pid-%d", getpid ());
367   address = g_unix_socket_address_new (socket_path);
368
369   service = g_socket_service_new ();
370   error = NULL;
371   g_socket_listener_add_address (G_SOCKET_LISTENER (service),
372                                  address,
373                                  G_SOCKET_TYPE_STREAM,
374                                  G_SOCKET_PROTOCOL_DEFAULT,
375                                  NULL, /* source_object */
376                                  NULL, /* effective_address */
377                                  &error);
378   g_assert_no_error (error);
379   g_signal_connect (service,
380                     "incoming",
381                     G_CALLBACK (on_incoming_connection),
382                     data);
383   g_socket_service_start (service);
384
385   service_loop = g_main_loop_new (service_context, FALSE);
386   g_main_loop_run (service_loop);
387
388   g_main_context_pop_thread_default (service_context);
389
390   g_main_loop_unref (service_loop);
391   g_main_context_unref (service_context);
392
393   g_object_unref (address);
394   g_free (socket_path);
395   return NULL;
396 }
397 #endif
398
399 /* ---------------------------------------------------------------------------------------------------- */
400
401 #if 0
402 static gboolean
403 check_connection (gpointer user_data)
404 {
405   PeerData *data = user_data;
406   guint n;
407
408   for (n = 0; n < data->current_connections->len; n++)
409     {
410       GDBusConnection *c;
411       GIOStream *stream;
412
413       c = G_DBUS_CONNECTION (data->current_connections->pdata[n]);
414       stream = g_dbus_connection_get_stream (c);
415
416       g_debug ("In check_connection for %d: connection %p, stream %p", n, c, stream);
417       g_debug ("closed = %d", g_io_stream_is_closed (stream));
418
419       GSocket *socket;
420       socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (stream));
421       g_debug ("socket_closed = %d", g_socket_is_closed (socket));
422       g_debug ("socket_condition_check = %d", g_socket_condition_check (socket, G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP));
423
424       gchar buf[128];
425       GError *error;
426       gssize num_read;
427       error = NULL;
428       num_read = g_input_stream_read (g_io_stream_get_input_stream (stream),
429                                       buf,
430                                       128,
431                                       NULL,
432                                       &error);
433       if (num_read < 0)
434         {
435           g_debug ("error: %s", error->message);
436           g_error_free (error);
437         }
438       else
439         {
440           g_debug ("no error, read %d bytes", (gint) num_read);
441         }
442     }
443
444   return FALSE;
445 }
446
447 static gboolean
448 on_do_disconnect_in_idle (gpointer data)
449 {
450   GDBusConnection *c = G_DBUS_CONNECTION (data);
451   g_debug ("GDC %p has ref_count %d", c, G_OBJECT (c)->ref_count);
452   g_dbus_connection_disconnect (c);
453   g_object_unref (c);
454   return FALSE;
455 }
456 #endif
457
458 static void
459 test_peer (void)
460 {
461   GDBusConnection *c;
462   GDBusConnection *c2;
463   GDBusProxy *proxy;
464   GError *error;
465   PeerData data;
466   GVariant *value;
467   GVariant *result;
468   const gchar *s;
469   GThread *service_thread;
470
471   memset (&data, '\0', sizeof (PeerData));
472   data.current_connections = g_ptr_array_new_with_free_func (g_object_unref);
473
474   /* first try to connect when there is no server */
475   error = NULL;
476   c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" :
477                                               /* NOTE: Even if something is listening on port 12345 the connection
478                                                * will fail because the nonce file doesn't exist */
479                                               "nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus",
480                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
481                                               NULL, /* cancellable */
482                                               &error);
483   _g_assert_error_domain (error, G_IO_ERROR);
484   g_assert (!g_dbus_error_is_remote_error (error));
485   g_clear_error (&error);
486   g_assert (c == NULL);
487
488   /* bring up a server - we run the server in a different thread to avoid deadlocks */
489   error = NULL;
490   service_thread = g_thread_create (service_thread_func,
491                                     &data,
492                                     TRUE,
493                                     &error);
494   while (service_loop == NULL)
495     g_thread_yield ();
496   g_assert (server != NULL);
497
498   /* bring up a connection and accept it */
499   data.accept_connection = TRUE;
500   error = NULL;
501   c = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
502                                               G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
503                                               NULL, /* cancellable */
504                                               &error);
505   g_assert_no_error (error);
506   g_assert (c != NULL);
507   while (data.current_connections->len < 1)
508     g_main_loop_run (loop);
509   g_assert_cmpint (data.current_connections->len, ==, 1);
510   g_assert_cmpint (data.num_connection_attempts, ==, 1);
511   //g_assert (g_dbus_connection_get_bus_type (c) == G_BUS_TYPE_NONE);
512   g_assert (g_dbus_connection_get_unique_name (c) == NULL);
513   g_assert_cmpstr (g_dbus_connection_get_guid (c), ==, test_guid);
514
515   /* check that we create a proxy, read properties, receive signals and invoke
516    * the HelloPeer() method. Since the server runs in another thread it's fine
517    * to use synchronous blocking API here.
518    */
519   error = NULL;
520   proxy = g_dbus_proxy_new_sync (c,
521                                  G_TYPE_DBUS_PROXY,
522                                  G_DBUS_PROXY_FLAGS_NONE,
523                                  NULL,
524                                  NULL, /* bus_name */
525                                  "/org/gtk/GDBus/PeerTestObject",
526                                  "org.gtk.GDBus.PeerTestInterface",
527                                  NULL, /* GCancellable */
528                                  &error);
529   g_assert_no_error (error);
530   g_assert (proxy != NULL);
531   error = NULL;
532   value = g_dbus_proxy_get_cached_property (proxy, "PeerProperty");
533   g_assert_cmpstr (g_variant_get_string (value, NULL), ==, "ThePropertyValue");
534
535   /* try invoking a method */
536   error = NULL;
537   result = g_dbus_proxy_call_sync (proxy,
538                                    "HelloPeer",
539                                    g_variant_new ("(s)", "Hey Peer!"),
540                                    G_DBUS_CALL_FLAGS_NONE,
541                                    -1,
542                                    NULL,  /* GCancellable */
543                                    &error);
544   g_assert_no_error (error);
545   g_variant_get (result, "(s)", &s);
546   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Peer!'.");
547   g_variant_unref (result);
548   g_assert_cmpint (data.num_method_calls, ==, 1);
549
550   /* make the other peer emit a signal - catch it */
551   g_signal_connect (proxy,
552                     "g-signal",
553                     G_CALLBACK (on_proxy_signal_received),
554                     &data);
555   g_assert (!data.signal_received);
556   g_dbus_proxy_call (proxy,
557                      "EmitSignal",
558                      NULL,  /* no arguments */
559                      G_DBUS_CALL_FLAGS_NONE,
560                      -1,
561                      NULL,  /* GCancellable */
562                      NULL,  /* GAsyncReadyCallback - we don't care about the result */
563                      NULL); /* user_data */
564   g_main_loop_run (loop);
565   g_assert (data.signal_received);
566   g_assert_cmpint (data.num_method_calls, ==, 2);
567
568   /* check for UNIX fd passing */
569 #ifdef G_OS_UNIX
570   {
571     GDBusMessage *method_call_message;
572     GDBusMessage *method_reply_message;
573     GUnixFDList *fd_list;
574     gint fd;
575     gchar buf[1024];
576     gssize len;
577     gchar *buf2;
578     gsize len2;
579
580     method_call_message = g_dbus_message_new_method_call (NULL, /* name */
581                                                           "/org/gtk/GDBus/PeerTestObject",
582                                                           "org.gtk.GDBus.PeerTestInterface",
583                                                           "OpenFile");
584     g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", "/etc/hosts"));
585     error = NULL;
586     method_reply_message = g_dbus_connection_send_message_with_reply_sync (c,
587                                                                            method_call_message,
588                                                                            -1,
589                                                                            NULL, /* out_serial */
590                                                                            NULL, /* cancellable */
591                                                                            &error);
592     g_assert_no_error (error);
593     g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN);
594     fd_list = g_dbus_message_get_unix_fd_list (method_reply_message);
595     g_assert (fd_list != NULL);
596     g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1);
597     error = NULL;
598     fd = g_unix_fd_list_get (fd_list, 0, &error);
599     g_assert_no_error (error);
600     g_object_unref (method_call_message);
601     g_object_unref (method_reply_message);
602
603     memset (buf, '\0', sizeof (buf));
604     len = read (fd, buf, sizeof (buf) - 1);
605     close (fd);
606
607     error = NULL;
608     g_file_get_contents ("/etc/hosts",
609                          &buf2,
610                          &len2,
611                          &error);
612     g_assert_no_error (error);
613     if (len2 > sizeof (buf))
614       buf2[sizeof (buf)] = '\0';
615     g_assert_cmpstr (buf, ==, buf2);
616     g_free (buf2);
617   }
618 #endif /* G_OS_UNIX */
619
620
621   /* bring up a connection - don't accept it - this should fail
622    */
623   data.accept_connection = FALSE;
624   error = NULL;
625   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
626                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
627                                                NULL, /* cancellable */
628                                                &error);
629   _g_assert_error_domain (error, G_IO_ERROR);
630   g_assert (c2 == NULL);
631
632 #if 0
633   /* TODO: THIS TEST DOESN'T WORK YET */
634
635   /* bring up a connection - accept it.. then disconnect from the client side - check
636    * that the server side gets the disconnect signal.
637    */
638   error = NULL;
639   data.accept_connection = TRUE;
640   c2 = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (server),
641                                                G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
642                                                NULL, /* cancellable */
643                                                &error);
644   g_assert_no_error (error);
645   g_assert (c2 != NULL);
646   g_assert (!g_dbus_connection_get_is_disconnected (c2));
647   while (data.num_connection_attempts < 3)
648     g_main_loop_run (loop);
649   g_assert_cmpint (data.current_connections->len, ==, 2);
650   g_assert_cmpint (data.num_connection_attempts, ==, 3);
651   g_assert (!g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
652   g_idle_add (on_do_disconnect_in_idle, c2);
653   g_debug ("==================================================");
654   g_debug ("==================================================");
655   g_debug ("==================================================");
656   g_debug ("waiting for disconnect on connection %p, stream %p",
657            data.current_connections->pdata[1],
658            g_dbus_connection_get_stream (data.current_connections->pdata[1]));
659
660   g_timeout_add (2000, check_connection, &data);
661   //_g_assert_signal_received (G_DBUS_CONNECTION (data.current_connections->pdata[1]), "closed");
662   g_main_loop_run (loop);
663   g_assert (g_dbus_connection_get_is_disconnected (G_DBUS_CONNECTION (data.current_connections->pdata[1])));
664   g_ptr_array_set_size (data.current_connections, 1); /* remove disconnected connection object */
665 #endif
666
667   /* unref the server and stop listening for new connections
668    *
669    * This won't bring down the established connections - check that c is still connected
670    * by invoking a method
671    */
672   //g_socket_service_stop (service);
673   //g_object_unref (service);
674   g_dbus_server_stop (server);
675   g_object_unref (server);
676   server = NULL;
677
678   error = NULL;
679   result = g_dbus_proxy_call_sync (proxy,
680                                    "HelloPeer",
681                                    g_variant_new ("(s)", "Hey Again Peer!"),
682                                    G_DBUS_CALL_FLAGS_NONE,
683                                    -1,
684                                    NULL,  /* GCancellable */
685                                    &error);
686   g_assert_no_error (error);
687   g_variant_get (result, "(s)", &s);
688   g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'.");
689   g_variant_unref (result);
690   g_assert_cmpint (data.num_method_calls, ==, 4);
691
692 #if 0
693   /* TODO: THIS TEST DOESN'T WORK YET */
694
695   /* now disconnect from the server side - check that the client side gets the signal */
696   g_assert_cmpint (data.current_connections->len, ==, 1);
697   g_assert (G_DBUS_CONNECTION (data.current_connections->pdata[0]) != c);
698   g_dbus_connection_disconnect (G_DBUS_CONNECTION (data.current_connections->pdata[0]));
699   if (!g_dbus_connection_get_is_disconnected (c))
700     _g_assert_signal_received (c, "closed");
701   g_assert (g_dbus_connection_get_is_disconnected (c));
702 #endif
703
704   g_object_unref (c);
705   g_ptr_array_unref (data.current_connections);
706   g_object_unref (proxy);
707
708   g_main_loop_quit (service_loop);
709   g_thread_join (service_thread);
710 }
711
712 /* ---------------------------------------------------------------------------------------------------- */
713
714 int
715 main (int   argc,
716       char *argv[])
717 {
718   gint ret;
719   GDBusNodeInfo *introspection_data = NULL;
720
721   g_type_init ();
722   g_thread_init (NULL);
723   g_test_init (&argc, &argv, NULL);
724
725   introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL);
726   g_assert (introspection_data != NULL);
727   test_interface_introspection_data = introspection_data->interfaces[0];
728
729   test_guid = g_dbus_generate_guid ();
730
731   /* all the tests rely on a shared main loop */
732   loop = g_main_loop_new (NULL, FALSE);
733
734   g_test_add_func ("/gdbus/peer-to-peer", test_peer);
735
736   ret = g_test_run();
737
738   g_main_loop_unref (loop);
739   g_free (test_guid);
740   g_dbus_node_info_unref (introspection_data);
741
742   return ret;
743 }