Add GTestDBus object
[platform/upstream/glib.git] / gio / tests / gdbus-proxy.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 /* Test that the method aspects of GDBusProxy works */
34 /* ---------------------------------------------------------------------------------------------------- */
35
36 static void
37 test_methods (GDBusProxy *proxy)
38 {
39   GVariant *result;
40   GError *error;
41   const gchar *str;
42   gchar *dbus_error_name;
43
44   /* check that we can invoke a method */
45   error = NULL;
46   result = g_dbus_proxy_call_sync (proxy,
47                                    "HelloWorld",
48                                    g_variant_new ("(s)", "Hey"),
49                                    G_DBUS_CALL_FLAGS_NONE,
50                                    -1,
51                                    NULL,
52                                    &error);
53   g_assert_no_error (error);
54   g_assert (result != NULL);
55   g_assert_cmpstr (g_variant_get_type_string (result), ==, "(s)");
56   g_variant_get (result, "(&s)", &str);
57   g_assert_cmpstr (str, ==, "You greeted me with 'Hey'. Thanks!");
58   g_variant_unref (result);
59
60   /* Check that we can completely recover the returned error */
61   result = g_dbus_proxy_call_sync (proxy,
62                                    "HelloWorld",
63                                    g_variant_new ("(s)", "Yo"),
64                                    G_DBUS_CALL_FLAGS_NONE,
65                                    -1,
66                                    NULL,
67                                    &error);
68   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR);
69   g_assert (g_dbus_error_is_remote_error (error));
70   g_assert (g_dbus_error_is_remote_error (error));
71   g_assert (result == NULL);
72   dbus_error_name = g_dbus_error_get_remote_error (error);
73   g_assert_cmpstr (dbus_error_name, ==, "com.example.TestException");
74   g_free (dbus_error_name);
75   g_assert (g_dbus_error_strip_remote_error (error));
76   g_assert_cmpstr (error->message, ==, "Yo is not a proper greeting");
77   g_clear_error (&error);
78
79   /* Check that we get a timeout if the method handling is taking longer than timeout */
80   error = NULL;
81   result = g_dbus_proxy_call_sync (proxy,
82                                    "Sleep",
83                                    g_variant_new ("(i)", 500 /* msec */),
84                                    G_DBUS_CALL_FLAGS_NONE,
85                                    100 /* msec */,
86                                    NULL,
87                                    &error);
88   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
89   g_assert (!g_dbus_error_is_remote_error (error));
90   g_assert (result == NULL);
91   g_clear_error (&error);
92
93   /* Check that proxy-default timeouts work. */
94   g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
95
96   /* the default timeout is 25000 msec so this should work */
97   result = g_dbus_proxy_call_sync (proxy,
98                                    "Sleep",
99                                    g_variant_new ("(i)", 500 /* msec */),
100                                    G_DBUS_CALL_FLAGS_NONE,
101                                    -1, /* use proxy default (e.g. -1 -> e.g. 25000 msec) */
102                                    NULL,
103                                    &error);
104   g_assert_no_error (error);
105   g_assert (result != NULL);
106   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
107   g_variant_unref (result);
108
109   /* now set the proxy-default timeout to 250 msec and try the 500 msec call - this should FAIL */
110   g_dbus_proxy_set_default_timeout (proxy, 250);
111   g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, 250);
112   result = g_dbus_proxy_call_sync (proxy,
113                                    "Sleep",
114                                    g_variant_new ("(i)", 500 /* msec */),
115                                    G_DBUS_CALL_FLAGS_NONE,
116                                    -1, /* use proxy default (e.g. 250 msec) */
117                                    NULL,
118                                    &error);
119   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
120   g_assert (!g_dbus_error_is_remote_error (error));
121   g_assert (result == NULL);
122   g_clear_error (&error);
123
124   /* clean up after ourselves */
125   g_dbus_proxy_set_default_timeout (proxy, -1);
126 }
127
128 static gboolean
129 strv_equal (gchar **strv, ...)
130 {
131   gint count;
132   va_list list;
133   const gchar *str;
134   gboolean res;
135
136   res = TRUE;
137   count = 0;
138   va_start (list, strv);
139   while (1)
140     {
141       str = va_arg (list, const gchar *);
142       if (str == NULL)
143         break;
144       if (g_strcmp0 (str, strv[count]) != 0)
145         {
146           res = FALSE;
147           break;
148         }
149       count++;
150     }
151   va_end (list);
152
153   if (res)
154     res = g_strv_length (strv) == count;
155
156   return res;
157 }
158
159 /* ---------------------------------------------------------------------------------------------------- */
160 /* Test that the property aspects of GDBusProxy works */
161 /* ---------------------------------------------------------------------------------------------------- */
162
163 static void
164 test_properties (GDBusProxy *proxy)
165 {
166   GError *error;
167   GVariant *variant;
168   GVariant *variant2;
169   GVariant *result;
170   gchar **names;
171
172   error = NULL;
173
174   if (g_dbus_proxy_get_flags (proxy) & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
175     {
176        g_assert (g_dbus_proxy_get_cached_property_names (proxy) == NULL);
177        return;
178     }
179
180   /*
181    * Check that we can list all cached properties.
182    */
183   names = g_dbus_proxy_get_cached_property_names (proxy);
184
185   g_assert (strv_equal (names,
186                         "PropertyThatWillBeInvalidated",
187                         "ab",
188                         "ad",
189                         "ai",
190                         "an",
191                         "ao",
192                         "aq",
193                         "as",
194                         "at",
195                         "au",
196                         "ax",
197                         "ay",
198                         "b",
199                         "d",
200                         "foo",
201                         "i",
202                         "n",
203                         "o",
204                         "q",
205                         "s",
206                         "t",
207                         "u",
208                         "x",
209                         "y",
210                         NULL));
211
212   g_strfreev (names);
213
214   /*
215    * Check that we can read cached properties.
216    *
217    * No need to test all properties - GVariant has already been tested
218    */
219   variant = g_dbus_proxy_get_cached_property (proxy, "y");
220   g_assert (variant != NULL);
221   g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
222   g_variant_unref (variant);
223   variant = g_dbus_proxy_get_cached_property (proxy, "o");
224   g_assert (variant != NULL);
225   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
226   g_variant_unref (variant);
227
228   /*
229    * Now ask the service to change a property and check that #GDBusProxy::g-property-changed
230    * is received. Also check that the cache is updated.
231    */
232   variant2 = g_variant_new_byte (42);
233   result = g_dbus_proxy_call_sync (proxy,
234                                    "FrobSetProperty",
235                                    g_variant_new ("(sv)",
236                                                   "y",
237                                                   variant2),
238                                    G_DBUS_CALL_FLAGS_NONE,
239                                    -1,
240                                    NULL,
241                                    &error);
242   g_assert_no_error (error);
243   g_assert (result != NULL);
244   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
245   g_variant_unref (result);
246   _g_assert_signal_received (proxy, "g-properties-changed");
247   variant = g_dbus_proxy_get_cached_property (proxy, "y");
248   g_assert (variant != NULL);
249   g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
250   g_variant_unref (variant);
251
252   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (142));
253   variant = g_dbus_proxy_get_cached_property (proxy, "y");
254   g_assert (variant != NULL);
255   g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
256   g_variant_unref (variant);
257
258   g_dbus_proxy_set_cached_property (proxy, "y", NULL);
259   variant = g_dbus_proxy_get_cached_property (proxy, "y");
260   g_assert (variant == NULL);
261
262   /* Check that the invalidation feature of the PropertiesChanged()
263    * signal works... First, check that we have a cached value of the
264    * property (from the initial GetAll() call)
265    */
266   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
267   g_assert (variant != NULL);
268   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "InitialValue");
269   g_variant_unref (variant);
270   /* now ask to invalidate the property - this causes a
271    *
272    *   PropertiesChanaged("com.example.Frob",
273    *                      {},
274    *                      ["PropertyThatWillBeInvalidated")
275    *
276    * signal to be emitted. This is received before the method reply
277    * for FrobInvalidateProperty *but* since the proxy was created in
278    * the same thread as we're doing this synchronous call, we'll get
279    * the method reply before...
280    */
281   result = g_dbus_proxy_call_sync (proxy,
282                                    "FrobInvalidateProperty",
283                                    g_variant_new ("(s)", "OMGInvalidated"),
284                                    G_DBUS_CALL_FLAGS_NONE,
285                                    -1,
286                                    NULL,
287                                    &error);
288   g_assert_no_error (error);
289   g_assert (result != NULL);
290   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
291   g_variant_unref (result);
292   /* ... hence we wait for the g-properties-changed signal to be delivered */
293   _g_assert_signal_received (proxy, "g-properties-changed");
294   /* ... and now we finally, check that the cached value has been invalidated */
295   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
296   g_assert (variant == NULL);
297
298   /* Now test that G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES works - we need a new proxy for that */
299   gchar *name_owner;
300   GDBusProxy *proxy2;
301   error = NULL;
302   proxy2 = g_dbus_proxy_new_sync (g_dbus_proxy_get_connection (proxy),
303                                   G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
304                                   NULL,                      /* GDBusInterfaceInfo */
305                                   "com.example.TestService", /* name */
306                                   "/com/example/TestObject", /* object path */
307                                   "com.example.Frob",        /* interface */
308                                   NULL, /* GCancellable */
309                                   &error);
310   g_assert_no_error (error);
311
312   name_owner = g_dbus_proxy_get_name_owner (proxy2);
313   g_assert (name_owner != NULL);
314   g_free (name_owner);
315
316   variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated");
317   g_assert (variant != NULL);
318   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated"); /* from previous test */
319   g_variant_unref (variant);
320
321   result = g_dbus_proxy_call_sync (proxy2,
322                                    "FrobInvalidateProperty",
323                                    g_variant_new ("(s)", "OMGInvalidated2"),
324                                    G_DBUS_CALL_FLAGS_NONE,
325                                    -1,
326                                    NULL,
327                                    &error);
328   g_assert_no_error (error);
329   g_assert (result != NULL);
330   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
331   g_variant_unref (result);
332
333   /* this time we should get the ::g-properties-changed _with_ the value */
334   _g_assert_signal_received (proxy2, "g-properties-changed");
335
336   variant = g_dbus_proxy_get_cached_property (proxy2, "PropertyThatWillBeInvalidated");
337   g_assert (variant != NULL);
338   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated2");
339   g_variant_unref (variant);
340
341   g_object_unref (proxy2);
342 }
343
344 /* ---------------------------------------------------------------------------------------------------- */
345 /* Test that the signal aspects of GDBusProxy works */
346 /* ---------------------------------------------------------------------------------------------------- */
347
348 static void
349 test_proxy_signals_on_signal (GDBusProxy  *proxy,
350                               const gchar *sender_name,
351                               const gchar *signal_name,
352                               GVariant    *parameters,
353                               gpointer     user_data)
354 {
355   GString *s = user_data;
356
357   g_assert_cmpstr (signal_name, ==, "TestSignal");
358   g_assert_cmpstr (g_variant_get_type_string (parameters), ==, "(sov)");
359
360   g_variant_print_string (parameters, s, TRUE);
361 }
362
363 typedef struct
364 {
365   GMainLoop *internal_loop;
366   GString *s;
367 } TestSignalData;
368
369 static void
370 test_proxy_signals_on_emit_signal_cb (GDBusProxy   *proxy,
371                                       GAsyncResult *res,
372                                       gpointer      user_data)
373 {
374   TestSignalData *data = user_data;
375   GError *error;
376   GVariant *result;
377
378   error = NULL;
379   result = g_dbus_proxy_call_finish (proxy,
380                                      res,
381                                      &error);
382   g_assert_no_error (error);
383   g_assert (result != NULL);
384   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
385   g_variant_unref (result);
386
387   /* check that the signal was recieved before we got the method result */
388   g_assert (strlen (data->s->str) > 0);
389
390   /* break out of the loop */
391   g_main_loop_quit (data->internal_loop);
392 }
393
394 static void
395 test_signals (GDBusProxy *proxy)
396 {
397   GError *error;
398   GString *s;
399   gulong signal_handler_id;
400   TestSignalData data;
401   GVariant *result;
402
403   error = NULL;
404
405   /*
406    * Ask the service to emit a signal and check that we receive it.
407    *
408    * Note that blocking calls don't block in the mainloop so wait for the signal (which
409    * is dispatched before the method reply)
410    */
411   s = g_string_new (NULL);
412   signal_handler_id = g_signal_connect (proxy,
413                                         "g-signal",
414                                         G_CALLBACK (test_proxy_signals_on_signal),
415                                         s);
416
417   result = g_dbus_proxy_call_sync (proxy,
418                                    "EmitSignal",
419                                    g_variant_new ("(so)",
420                                                   "Accept the next proposition you hear",
421                                                   "/some/path"),
422                                    G_DBUS_CALL_FLAGS_NONE,
423                                    -1,
424                                    NULL,
425                                    &error);
426   g_assert_no_error (error);
427   g_assert (result != NULL);
428   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
429   g_variant_unref (result);
430   /* check that we haven't received the signal just yet */
431   g_assert (strlen (s->str) == 0);
432   /* and now wait for the signal */
433   _g_assert_signal_received (proxy, "g-signal");
434   g_assert_cmpstr (s->str,
435                    ==,
436                    "('Accept the next proposition you hear .. in bed!', objectpath '/some/path/in/bed', <'a variant'>)");
437   g_signal_handler_disconnect (proxy, signal_handler_id);
438   g_string_free (s, TRUE);
439
440   /*
441    * Now do this async to check the signal is received before the method returns.
442    */
443   s = g_string_new (NULL);
444   data.internal_loop = g_main_loop_new (NULL, FALSE);
445   data.s = s;
446   signal_handler_id = g_signal_connect (proxy,
447                                         "g-signal",
448                                         G_CALLBACK (test_proxy_signals_on_signal),
449                                         s);
450   g_dbus_proxy_call (proxy,
451                      "EmitSignal",
452                      g_variant_new ("(so)",
453                                     "You will make a great programmer",
454                                     "/some/other/path"),
455                      G_DBUS_CALL_FLAGS_NONE,
456                      -1,
457                      NULL,
458                      (GAsyncReadyCallback) test_proxy_signals_on_emit_signal_cb,
459                      &data);
460   g_main_loop_run (data.internal_loop);
461   g_main_loop_unref (data.internal_loop);
462   g_assert_cmpstr (s->str,
463                    ==,
464                    "('You will make a great programmer .. in bed!', objectpath '/some/other/path/in/bed', <'a variant'>)");
465   g_signal_handler_disconnect (proxy, signal_handler_id);
466   g_string_free (s, TRUE);
467 }
468
469 /* ---------------------------------------------------------------------------------------------------- */
470
471 static void
472 test_bogus_method_return (GDBusProxy *proxy)
473 {
474   GError *error = NULL;
475   GVariant *result;
476
477   result = g_dbus_proxy_call_sync (proxy,
478                                    "PairReturn",
479                                    NULL,
480                                    G_DBUS_CALL_FLAGS_NONE,
481                                    -1,
482                                    NULL,
483                                    &error);
484   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
485   g_error_free (error);
486   g_assert (result == NULL);
487 }
488
489 #if 0 /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999 */
490 static void
491 test_bogus_signal (GDBusProxy *proxy)
492 {
493   GError *error = NULL;
494   GVariant *result;
495   GDBusInterfaceInfo *old_iface_info;
496
497   result = g_dbus_proxy_call_sync (proxy,
498                                    "EmitSignal2",
499                                    NULL,
500                                    G_DBUS_CALL_FLAGS_NONE,
501                                    -1,
502                                    NULL,
503                                    &error);
504   g_assert_no_error (error);
505   g_assert (result != NULL);
506   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
507   g_variant_unref (result);
508
509   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
510     {
511       /* and now wait for the signal that will never arrive */
512       _g_assert_signal_received (proxy, "g-signal");
513     }
514   g_test_trap_assert_stderr ("*Dropping signal TestSignal2 of type (i) since the type from the expected interface is (u)*");
515   g_test_trap_assert_failed();
516
517   /* Our main branch will also do g_warning() when running the mainloop so
518    * temporarily remove the expected interface
519    */
520   old_iface_info = g_dbus_proxy_get_interface_info (proxy);
521   g_dbus_proxy_set_interface_info (proxy, NULL);
522   _g_assert_signal_received (proxy, "g-signal");
523   g_dbus_proxy_set_interface_info (proxy, old_iface_info);
524 }
525
526 static void
527 test_bogus_property (GDBusProxy *proxy)
528 {
529   GError *error = NULL;
530   GVariant *result;
531   GDBusInterfaceInfo *old_iface_info;
532
533   /* Make the service emit a PropertiesChanged signal for property 'i' of type 'i' - since
534    * our introspection data has this as type 'u' we should get a warning on stderr.
535    */
536   result = g_dbus_proxy_call_sync (proxy,
537                                    "FrobSetProperty",
538                                    g_variant_new ("(sv)",
539                                                   "i", g_variant_new_int32 (42)),
540                                    G_DBUS_CALL_FLAGS_NONE,
541                                    -1,
542                                    NULL,
543                                    &error);
544   g_assert_no_error (error);
545   g_assert (result != NULL);
546   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
547   g_variant_unref (result);
548
549   if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
550     {
551       /* and now wait for the signal that will never arrive */
552       _g_assert_signal_received (proxy, "g-properties-changed");
553     }
554   g_test_trap_assert_stderr ("*Received property i with type i does not match expected type u in the expected interface*");
555   g_test_trap_assert_failed();
556
557   /* Our main branch will also do g_warning() when running the mainloop so
558    * temporarily remove the expected interface
559    */
560   old_iface_info = g_dbus_proxy_get_interface_info (proxy);
561   g_dbus_proxy_set_interface_info (proxy, NULL);
562   _g_assert_signal_received (proxy, "g-properties-changed");
563   g_dbus_proxy_set_interface_info (proxy, old_iface_info);
564 }
565 #endif /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999 */
566
567 /* ---------------------------------------------------------------------------------------------------- */
568
569 static const gchar *frob_dbus_interface_xml =
570   "<node>"
571   "  <interface name='com.example.Frob'>"
572   /* PairReturn() is deliberately different from gdbus-testserver.py's definition */
573   "    <method name='PairReturn'>"
574   "      <arg type='u' name='somenumber' direction='in'/>"
575   "      <arg type='s' name='somestring' direction='out'/>"
576   "    </method>"
577   "    <method name='HelloWorld'>"
578   "      <arg type='s' name='somestring' direction='in'/>"
579   "      <arg type='s' name='somestring' direction='out'/>"
580   "    </method>"
581   "    <method name='Sleep'>"
582   "      <arg type='i' name='timeout' direction='in'/>"
583   "    </method>"
584   /* We deliberately only mention a single property here */
585   "    <property name='y' type='y' access='readwrite'/>"
586   /* The 'i' property is deliberately different from gdbus-testserver.py's definition */
587   "    <property name='i' type='u' access='readwrite'/>"
588   /* ::TestSignal2 is deliberately different from gdbus-testserver.py's definition */
589   "    <signal name='TestSignal2'>"
590   "      <arg type='u' name='somenumber'/>"
591   "    </signal>"
592   "  </interface>"
593   "</node>";
594 static GDBusInterfaceInfo *frob_dbus_interface_info;
595
596 static void
597 test_expected_interface (GDBusProxy *proxy)
598 {
599   GVariant *value;
600   GError *error;
601
602   /* This is obviously wrong but expected interface is not set so we don't fail... */
603   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
604   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
605   g_dbus_proxy_set_cached_property (proxy, "does-not-exist", g_variant_new_string ("something"));
606   g_dbus_proxy_set_cached_property (proxy, "does-not-exist", NULL);
607
608   /* Now repeat the method tests, with an expected interface set */
609   g_dbus_proxy_set_interface_info (proxy, frob_dbus_interface_info);
610   test_methods (proxy);
611   test_signals (proxy);
612
613   /* And also where we deliberately set the expected interface definition incorrectly */
614   test_bogus_method_return (proxy);
615   /* Disabled: see https://bugzilla.gnome.org/show_bug.cgi?id=658999
616   test_bogus_signal (proxy);
617   test_bogus_property (proxy);
618   */
619
620   if (g_test_undefined ())
621     {
622       /* Also check that we complain if setting a cached property of the wrong type */
623       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
624         {
625           g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_string ("error_me_out!"));
626         }
627       g_test_trap_assert_stderr ("*Trying to set property y of type s but according to the expected interface the type is y*");
628       g_test_trap_assert_failed();
629     }
630
631   /* this should work, however (since the type is correct) */
632   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (42));
633
634   if (g_test_undefined ())
635     {
636       /* Try to get the value of a property where the type we expect is different from
637        * what we have in our cache (e.g. what the service returned)
638        */
639       if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDOUT | G_TEST_TRAP_SILENCE_STDERR))
640         {
641           value = g_dbus_proxy_get_cached_property (proxy, "i");
642         }
643       g_test_trap_assert_stderr ("*Trying to get property i with type i but according to the expected interface the type is u*");
644       g_test_trap_assert_failed();
645     }
646
647   /* Even if a property does not exist in expected_interface, looking it
648    * up, or setting it, should never fail. Because it could be that the
649    * property has been added to the service but the GDBusInterfaceInfo*
650    * passed to g_dbus_proxy_set_interface_info() just haven't been updated.
651    *
652    * See https://bugzilla.gnome.org/show_bug.cgi?id=660886
653    */
654   value = g_dbus_proxy_get_cached_property (proxy, "d");
655   g_assert (value != NULL);
656   g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
657   g_assert_cmpfloat (g_variant_get_double (value), ==, 7.5);
658   g_variant_unref (value);
659   /* update it via the cached property... */
660   g_dbus_proxy_set_cached_property (proxy, "d", g_variant_new_double (75.0));
661   /* ... and finally check that it has changed */
662   value = g_dbus_proxy_get_cached_property (proxy, "d");
663   g_assert (value != NULL);
664   g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
665   g_assert_cmpfloat (g_variant_get_double (value), ==, 75.0);
666   g_variant_unref (value);
667   /* now update it via the D-Bus interface... */
668   error = NULL;
669   value = g_dbus_proxy_call_sync (proxy, "FrobSetProperty",
670                                   g_variant_new ("(sv)", "d", g_variant_new_double (85.0)),
671                                   G_DBUS_CALL_FLAGS_NONE,
672                                   -1, NULL, &error);
673   g_assert_no_error (error);
674   g_assert (value != NULL);
675   g_assert_cmpstr (g_variant_get_type_string (value), ==, "()");
676   g_variant_unref (value);
677   /* ...ensure we receive the ::PropertiesChanged signal... */
678   _g_assert_signal_received (proxy, "g-properties-changed");
679   /* ... and finally check that it has changed */
680   value = g_dbus_proxy_get_cached_property (proxy, "d");
681   g_assert (value != NULL);
682   g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_DOUBLE));
683   g_assert_cmpfloat (g_variant_get_double (value), ==, 85.0);
684   g_variant_unref (value);
685 }
686
687 static void
688 test_basic (GDBusProxy *proxy)
689 {
690   GDBusConnection *connection;
691   GDBusConnection *conn;
692   GDBusProxyFlags flags;
693   GDBusInterfaceInfo *info;
694   gchar *name;
695   gchar *path;
696   gchar *interface;
697   gint timeout;
698
699   connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
700
701   g_assert (g_dbus_proxy_get_connection (proxy) == connection);
702   g_assert (g_dbus_proxy_get_flags (proxy) == G_DBUS_PROXY_FLAGS_NONE);
703   g_assert (g_dbus_proxy_get_interface_info (proxy) == NULL);
704   g_assert_cmpstr (g_dbus_proxy_get_name (proxy), ==, "com.example.TestService");
705   g_assert_cmpstr (g_dbus_proxy_get_object_path (proxy), ==, "/com/example/TestObject");
706   g_assert_cmpstr (g_dbus_proxy_get_interface_name (proxy), ==, "com.example.Frob");
707   g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, -1);
708
709   g_object_get (proxy,
710                 "g-connection", &conn,
711                 "g-interface-info", &info,
712                 "g-flags", &flags,
713                 "g-name", &name,
714                 "g-object-path", &path,
715                 "g-interface-name", &interface,
716                 "g-default-timeout", &timeout,
717                 NULL);
718
719   g_assert (conn == connection);
720   g_assert (info == NULL);
721   g_assert_cmpint (flags, ==, G_DBUS_PROXY_FLAGS_NONE);
722   g_assert_cmpstr (name, ==, "com.example.TestService");
723   g_assert_cmpstr (path, ==, "/com/example/TestObject");
724   g_assert_cmpstr (interface, ==, "com.example.Frob");
725   g_assert_cmpint (timeout, ==, -1);
726
727   g_object_unref (conn);
728   g_free (name);
729   g_free (path);
730   g_free (interface);
731
732   g_object_unref (connection);
733 }
734
735 static void
736 test_proxy (void)
737 {
738   GDBusProxy *proxy;
739   GDBusConnection *connection;
740   GError *error;
741
742   session_bus_up ();
743
744   error = NULL;
745   connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
746                                NULL,
747                                &error);
748   g_assert_no_error (error);
749   error = NULL;
750   proxy = g_dbus_proxy_new_sync (connection,
751                                  G_DBUS_PROXY_FLAGS_NONE,
752                                  NULL,                      /* GDBusInterfaceInfo */
753                                  "com.example.TestService", /* name */
754                                  "/com/example/TestObject", /* object path */
755                                  "com.example.Frob",        /* interface */
756                                  NULL, /* GCancellable */
757                                  &error);
758   g_assert_no_error (error);
759
760   /* this is safe; testserver will exit once the bus goes away */
761   g_assert (g_spawn_command_line_async (SRCDIR "/gdbus-testserver.py", NULL));
762
763   _g_assert_property_notify (proxy, "g-name-owner");
764
765   test_basic (proxy);
766   test_methods (proxy);
767   test_properties (proxy);
768   test_signals (proxy);
769   test_expected_interface (proxy);
770
771   g_object_unref (proxy);
772   g_object_unref (connection);
773 }
774
775 /* ---------------------------------------------------------------------------------------------------- */
776
777 static void
778 proxy_ready (GObject      *source,
779              GAsyncResult *result,
780              gpointer      user_data)
781 {
782   GDBusProxy *proxy;
783   GError *error;
784
785   error = NULL;
786   proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
787   g_assert_no_error (error);
788
789   test_basic (proxy);
790   test_methods (proxy);
791   test_properties (proxy);
792   test_signals (proxy);
793   test_expected_interface (proxy);
794
795   g_object_unref (proxy);
796 }
797
798 static void
799 test_async (void)
800 {
801   g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
802                             G_DBUS_PROXY_FLAGS_NONE,
803                             NULL,                      /* GDBusInterfaceInfo */
804                             "com.example.TestService", /* name */
805                             "/com/example/TestObject", /* object path */
806                             "com.example.Frob",        /* interface */
807                             NULL, /* GCancellable */
808                             proxy_ready,
809                             NULL);
810 }
811
812 static void
813 test_no_properties (void)
814 {
815   GDBusProxy *proxy;
816   GError *error;
817
818   error = NULL;
819   proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
820                                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
821                                          NULL,                      /* GDBusInterfaceInfo */
822                                          "com.example.TestService", /* name */
823                                          "/com/example/TestObject", /* object path */
824                                          "com.example.Frob",        /* interface */
825                                          NULL, /* GCancellable */
826                                          &error);
827   g_assert_no_error (error);
828
829   test_properties (proxy);
830
831   g_object_unref (proxy);
832 }
833
834 static gboolean
835 fail_test (gpointer user_data)
836 {
837   g_assert_not_reached ();
838 }
839
840 static void
841 check_error (GObject      *source,
842              GAsyncResult *result,
843              gpointer      user_data)
844 {
845   GError *error = NULL;
846   GVariant *reply;
847
848   reply = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
849   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
850   g_assert (reply == NULL);
851   g_error_free (error);
852
853   g_main_loop_quit (loop);
854 }
855
856 static void
857 test_wellknown_noauto (void)
858 {
859   GError *error = NULL;
860   GDBusProxy *proxy;
861
862   proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
863                                          G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
864                                          NULL, "some.name.that.does.not.exist",
865                                          "/", "some.interface", NULL, &error);
866   g_assert_no_error (error);
867   g_assert (proxy != NULL);
868
869   g_dbus_proxy_call (proxy, "method", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, check_error, NULL);
870   g_timeout_add (10000, fail_test, NULL);
871   g_main_loop_run (loop);
872   g_object_unref (proxy);
873 }
874
875 int
876 main (int   argc,
877       char *argv[])
878 {
879   gint ret;
880   GDBusNodeInfo *introspection_data = NULL;
881
882   g_type_init ();
883   g_test_init (&argc, &argv, NULL);
884
885   introspection_data = g_dbus_node_info_new_for_xml (frob_dbus_interface_xml, NULL);
886   g_assert (introspection_data != NULL);
887   frob_dbus_interface_info = introspection_data->interfaces[0];
888
889   /* all the tests rely on a shared main loop */
890   loop = g_main_loop_new (NULL, FALSE);
891
892   g_test_dbus_unset ();
893
894   g_test_add_func ("/gdbus/proxy", test_proxy);
895   g_test_add_func ("/gdbus/proxy/no-properties", test_no_properties);
896   g_test_add_func ("/gdbus/proxy/wellknown-noauto", test_wellknown_noauto);
897   g_test_add_func ("/gdbus/proxy/async", test_async);
898
899   ret = g_test_run();
900
901   g_dbus_node_info_unref (introspection_data);
902   return ret;
903 }