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