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