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