Fix distcheck
[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   gchar *name_owner;
172   GDBusProxy *proxy2;
173
174   error = NULL;
175
176   if (g_dbus_proxy_get_flags (proxy) & G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES)
177     {
178        g_assert (g_dbus_proxy_get_cached_property_names (proxy) == NULL);
179        return;
180     }
181
182   /*
183    * Check that we can list all cached properties.
184    */
185   names = g_dbus_proxy_get_cached_property_names (proxy);
186
187   g_assert (strv_equal (names,
188                         "PropertyThatWillBeInvalidated",
189                         "ab",
190                         "ad",
191                         "ai",
192                         "an",
193                         "ao",
194                         "aq",
195                         "as",
196                         "at",
197                         "au",
198                         "ax",
199                         "ay",
200                         "b",
201                         "d",
202                         "foo",
203                         "i",
204                         "n",
205                         "o",
206                         "q",
207                         "s",
208                         "t",
209                         "u",
210                         "x",
211                         "y",
212                         NULL));
213
214   g_strfreev (names);
215
216   /*
217    * Check that we can read cached properties.
218    *
219    * No need to test all properties - GVariant has already been tested
220    */
221   variant = g_dbus_proxy_get_cached_property (proxy, "y");
222   g_assert (variant != NULL);
223   g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
224   g_variant_unref (variant);
225   variant = g_dbus_proxy_get_cached_property (proxy, "o");
226   g_assert (variant != NULL);
227   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
228   g_variant_unref (variant);
229
230   /*
231    * Now ask the service to change a property and check that #GDBusProxy::g-property-changed
232    * is received. Also check that the cache is updated.
233    */
234   variant2 = g_variant_new_byte (42);
235   result = g_dbus_proxy_call_sync (proxy,
236                                    "FrobSetProperty",
237                                    g_variant_new ("(sv)",
238                                                   "y",
239                                                   variant2),
240                                    G_DBUS_CALL_FLAGS_NONE,
241                                    -1,
242                                    NULL,
243                                    &error);
244   g_assert_no_error (error);
245   g_assert (result != NULL);
246   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
247   g_variant_unref (result);
248   _g_assert_signal_received (proxy, "g-properties-changed");
249   variant = g_dbus_proxy_get_cached_property (proxy, "y");
250   g_assert (variant != NULL);
251   g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
252   g_variant_unref (variant);
253
254   g_dbus_proxy_set_cached_property (proxy, "y", g_variant_new_byte (142));
255   variant = g_dbus_proxy_get_cached_property (proxy, "y");
256   g_assert (variant != NULL);
257   g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
258   g_variant_unref (variant);
259
260   g_dbus_proxy_set_cached_property (proxy, "y", NULL);
261   variant = g_dbus_proxy_get_cached_property (proxy, "y");
262   g_assert (variant == NULL);
263
264   /* Check that the invalidation feature of the PropertiesChanged()
265    * signal works... First, check that we have a cached value of the
266    * property (from the initial GetAll() call)
267    */
268   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
269   g_assert (variant != NULL);
270   g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "InitialValue");
271   g_variant_unref (variant);
272   /* now ask to invalidate the property - this causes a
273    *
274    *   PropertiesChanaged("com.example.Frob",
275    *                      {},
276    *                      ["PropertyThatWillBeInvalidated")
277    *
278    * signal to be emitted. This is received before the method reply
279    * for FrobInvalidateProperty *but* since the proxy was created in
280    * the same thread as we're doing this synchronous call, we'll get
281    * the method reply before...
282    */
283   result = g_dbus_proxy_call_sync (proxy,
284                                    "FrobInvalidateProperty",
285                                    g_variant_new ("(s)", "OMGInvalidated"),
286                                    G_DBUS_CALL_FLAGS_NONE,
287                                    -1,
288                                    NULL,
289                                    &error);
290   g_assert_no_error (error);
291   g_assert (result != NULL);
292   g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
293   g_variant_unref (result);
294   /* ... hence we wait for the g-properties-changed signal to be delivered */
295   _g_assert_signal_received (proxy, "g-properties-changed");
296   /* ... and now we finally, check that the cached value has been invalidated */
297   variant = g_dbus_proxy_get_cached_property (proxy, "PropertyThatWillBeInvalidated");
298   g_assert (variant == NULL);
299
300   /* Now test that G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES works - we need a new proxy for that */
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'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's definition */
587   "    <property name='i' type='u' access='readwrite'/>"
588   /* ::TestSignal2 is deliberately different from gdbus-testserver'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 kill_test_service (GDBusConnection *connection)
737 {
738 #ifdef G_OS_UNIX
739   guint pid;
740   GVariant *ret;
741   GError *error = NULL;
742   const gchar *name = "com.example.TestService";
743
744   ret = g_dbus_connection_call_sync (connection,
745                                      "org.freedesktop.DBus",
746                                      "/org/freedesktop/DBus",
747                                      "org.freedesktop.DBus",
748                                      "GetConnectionUnixProcessID",
749                                      g_variant_new ("(s)", name),
750                                      NULL,
751                                      G_DBUS_CALL_FLAGS_NONE,
752                                      -1,
753                                      NULL,
754                                      &error);
755   g_variant_get (ret, "(u)", &pid);
756   g_variant_unref (ret);
757   kill (pid, SIGTERM);
758 #else
759   g_warning ("Can't kill com.example.TestService");
760 #endif
761 }
762
763 static void
764 test_proxy (void)
765 {
766   GDBusProxy *proxy;
767   GDBusConnection *connection;
768   GError *error;
769
770   error = NULL;
771   connection = g_bus_get_sync (G_BUS_TYPE_SESSION,
772                                NULL,
773                                &error);
774   g_assert_no_error (error);
775   error = NULL;
776   proxy = g_dbus_proxy_new_sync (connection,
777                                  G_DBUS_PROXY_FLAGS_NONE,
778                                  NULL,                      /* GDBusInterfaceInfo */
779                                  "com.example.TestService", /* name */
780                                  "/com/example/TestObject", /* object path */
781                                  "com.example.Frob",        /* interface */
782                                  NULL, /* GCancellable */
783                                  &error);
784   g_assert_no_error (error);
785
786   /* this is safe; testserver will exit once the bus goes away */
787   g_assert (g_spawn_command_line_async ("./gdbus-testserver", NULL));
788
789   _g_assert_property_notify (proxy, "g-name-owner");
790
791   test_basic (proxy);
792   test_methods (proxy);
793   test_properties (proxy);
794   test_signals (proxy);
795   test_expected_interface (proxy);
796
797   g_object_unref (proxy);
798   kill_test_service (connection);
799   g_object_unref (connection);
800 }
801
802 /* ---------------------------------------------------------------------------------------------------- */
803
804 static void
805 proxy_ready (GObject      *source,
806              GAsyncResult *result,
807              gpointer      user_data)
808 {
809   GDBusProxy *proxy;
810   GError *error;
811
812   error = NULL;
813   proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
814   g_assert_no_error (error);
815
816   _g_assert_property_notify (proxy, "g-name-owner");
817
818   test_basic (proxy);
819   test_methods (proxy);
820   test_properties (proxy);
821   test_signals (proxy);
822   test_expected_interface (proxy);
823
824   kill_test_service (g_dbus_proxy_get_connection (proxy));
825   g_object_unref (proxy);
826   g_main_loop_quit (loop);
827 }
828
829 static gboolean
830 fail_test (gpointer user_data)
831 {
832   g_assert_not_reached ();
833 }
834
835 static void
836 test_async (void)
837 {
838   g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
839                             G_DBUS_PROXY_FLAGS_NONE,
840                             NULL,                      /* GDBusInterfaceInfo */
841                             "com.example.TestService", /* name */
842                             "/com/example/TestObject", /* object path */
843                             "com.example.Frob",        /* interface */
844                             NULL, /* GCancellable */
845                             proxy_ready,
846                             NULL);
847
848   /* this is safe; testserver will exit once the bus goes away */
849   g_assert (g_spawn_command_line_async ("./gdbus-testserver", NULL));
850
851   g_timeout_add (10000, fail_test, NULL);
852   g_main_loop_run (loop);
853 }
854
855 static void
856 test_no_properties (void)
857 {
858   GDBusProxy *proxy;
859   GError *error;
860
861   error = NULL;
862   proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
863                                          G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
864                                          NULL,                      /* GDBusInterfaceInfo */
865                                          "com.example.TestService", /* name */
866                                          "/com/example/TestObject", /* object path */
867                                          "com.example.Frob",        /* interface */
868                                          NULL, /* GCancellable */
869                                          &error);
870   g_assert_no_error (error);
871
872   test_properties (proxy);
873
874   g_object_unref (proxy);
875 }
876
877 static void
878 check_error (GObject      *source,
879              GAsyncResult *result,
880              gpointer      user_data)
881 {
882   GError *error = NULL;
883   GVariant *reply;
884
885   reply = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
886   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
887   g_assert (reply == NULL);
888   g_error_free (error);
889
890   g_main_loop_quit (loop);
891 }
892
893 static void
894 test_wellknown_noauto (void)
895 {
896   GError *error = NULL;
897   GDBusProxy *proxy;
898
899   proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
900                                          G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
901                                          NULL, "some.name.that.does.not.exist",
902                                          "/", "some.interface", NULL, &error);
903   g_assert_no_error (error);
904   g_assert (proxy != NULL);
905
906   g_dbus_proxy_call (proxy, "method", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, check_error, NULL);
907   g_timeout_add (10000, fail_test, NULL);
908   g_main_loop_run (loop);
909   g_object_unref (proxy);
910 }
911
912 int
913 main (int   argc,
914       char *argv[])
915 {
916   gint ret;
917   GDBusNodeInfo *introspection_data = NULL;
918
919   g_test_init (&argc, &argv, NULL);
920
921   introspection_data = g_dbus_node_info_new_for_xml (frob_dbus_interface_xml, NULL);
922   g_assert (introspection_data != NULL);
923   frob_dbus_interface_info = introspection_data->interfaces[0];
924
925   /* all the tests rely on a shared main loop */
926   loop = g_main_loop_new (NULL, FALSE);
927
928   session_bus_up ();
929
930   g_test_add_func ("/gdbus/proxy", test_proxy);
931   g_test_add_func ("/gdbus/proxy/no-properties", test_no_properties);
932   g_test_add_func ("/gdbus/proxy/wellknown-noauto", test_wellknown_noauto);
933   g_test_add_func ("/gdbus/proxy/async", test_async);
934
935   ret = g_test_run();
936
937   g_dbus_node_info_unref (introspection_data);
938
939   session_bus_down ();
940   return ret;
941 }