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