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 */
28static GMainLoop *loop = NULL;
29
30/* ---------------------------------------------------------------------------------------------------- */
31/* Test that the method aspects of GDBusProxy works */
32/* ---------------------------------------------------------------------------------------------------- */
33
34static void
35test_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 method_name: "HelloWorld",
46 parameters: g_variant_new (format_string: "(s)", "Hey"),
47 flags: G_DBUS_CALL_FLAGS_NONE,
48 timeout_msec: -1,
49 NULL,
50 error: &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 (value: result, format_string: "(&s)", &str);
55 g_assert_cmpstr (str, ==, "You greeted me with 'Hey'. Thanks!");
56 g_variant_unref (value: result);
57
58 /* Check that we can completely recover the returned error */
59 result = g_dbus_proxy_call_sync (proxy,
60 method_name: "HelloWorld",
61 parameters: g_variant_new (format_string: "(s)", "Yo"),
62 flags: G_DBUS_CALL_FLAGS_NONE,
63 timeout_msec: -1,
64 NULL,
65 error: &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 (mem: 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 (err: &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 method_name: "Sleep",
85 parameters: g_variant_new (format_string: "(i)", 10000 /* msec */),
86 flags: G_DBUS_CALL_FLAGS_NONE,
87 timeout_msec: 100 /* msec */,
88 NULL,
89 error: &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 (err: &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 method_name: "Sleep",
101 parameters: g_variant_new (format_string: "(i)", 500 /* msec */),
102 flags: G_DBUS_CALL_FLAGS_NONE,
103 timeout_msec: -1, /* use proxy default (e.g. -1 -> e.g. 25000 msec) */
104 NULL,
105 error: &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 (value: 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, timeout_msec: 250);
115 g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, 250);
116 result = g_dbus_proxy_call_sync (proxy,
117 method_name: "Sleep",
118 parameters: g_variant_new (format_string: "(i)", 10000 /* msec */),
119 flags: G_DBUS_CALL_FLAGS_NONE,
120 timeout_msec: -1, /* use proxy default (e.g. 250 msec) */
121 NULL,
122 error: &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 (err: &error);
127
128 /* clean up after ourselves */
129 g_dbus_proxy_set_default_timeout (proxy, timeout_msec: -1);
130}
131
132static gboolean
133strv_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 (str1: str, str2: 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 (str_array: strv) == count;
159
160 return res;
161}
162
163/* ---------------------------------------------------------------------------------------------------- */
164/* Test that the property aspects of GDBusProxy works */
165/* ---------------------------------------------------------------------------------------------------- */
166
167static void
168test_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 (str_array: 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, property_name: "y");
226 g_assert_nonnull (variant);
227 g_assert_cmpint (g_variant_get_byte (variant), ==, 1);
228 g_variant_unref (value: variant);
229 variant = g_dbus_proxy_get_cached_property (proxy, property_name: "o");
230 g_assert_nonnull (variant);
231 g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "/some/path");
232 g_variant_unref (value: 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 (value: 42);
239 result = g_dbus_proxy_call_sync (proxy,
240 method_name: "FrobSetProperty",
241 parameters: g_variant_new (format_string: "(sv)",
242 "y",
243 variant2),
244 flags: G_DBUS_CALL_FLAGS_NONE,
245 timeout_msec: -1,
246 NULL,
247 error: &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 (value: result);
252 _g_assert_signal_received (proxy, "g-properties-changed");
253 variant = g_dbus_proxy_get_cached_property (proxy, property_name: "y");
254 g_assert_nonnull (variant);
255 g_assert_cmpint (g_variant_get_byte (variant), ==, 42);
256 g_variant_unref (value: variant);
257
258 g_dbus_proxy_set_cached_property (proxy, property_name: "y", value: g_variant_new_byte (value: 142));
259 variant = g_dbus_proxy_get_cached_property (proxy, property_name: "y");
260 g_assert_nonnull (variant);
261 g_assert_cmpint (g_variant_get_byte (variant), ==, 142);
262 g_variant_unref (value: variant);
263
264 g_dbus_proxy_set_cached_property (proxy, property_name: "y", NULL);
265 variant = g_dbus_proxy_get_cached_property (proxy, property_name: "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, property_name: "PropertyThatWillBeInvalidated");
273 g_assert_nonnull (variant);
274 g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "InitialValue");
275 g_variant_unref (value: 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 method_name: "FrobInvalidateProperty",
289 parameters: g_variant_new (format_string: "(s)", "OMGInvalidated"),
290 flags: G_DBUS_CALL_FLAGS_NONE,
291 timeout_msec: -1,
292 NULL,
293 error: &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 (value: 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, property_name: "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 (connection: g_dbus_proxy_get_connection (proxy),
307 flags: G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
308 NULL, /* GDBusInterfaceInfo */
309 name: "com.example.TestService", /* name */
310 object_path: "/com/example/TestObject", /* object path */
311 interface_name: "com.example.Frob", /* interface */
312 NULL, /* GCancellable */
313 error: &error);
314 g_assert_no_error (error);
315
316 name_owner = g_dbus_proxy_get_name_owner (proxy: proxy2);
317 g_assert_nonnull (name_owner);
318 g_free (mem: name_owner);
319
320 variant = g_dbus_proxy_get_cached_property (proxy: proxy2, property_name: "PropertyThatWillBeInvalidated");
321 g_assert_nonnull (variant);
322 g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated"); /* from previous test */
323 g_variant_unref (value: variant);
324
325 result = g_dbus_proxy_call_sync (proxy: proxy2,
326 method_name: "FrobInvalidateProperty",
327 parameters: g_variant_new (format_string: "(s)", "OMGInvalidated2"),
328 flags: G_DBUS_CALL_FLAGS_NONE,
329 timeout_msec: -1,
330 NULL,
331 error: &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 (value: 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 (proxy: proxy2, property_name: "PropertyThatWillBeInvalidated");
341 g_assert_nonnull (variant);
342 g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "OMGInvalidated2");
343 g_variant_unref (value: variant);
344
345 g_object_unref (object: proxy2);
346}
347
348/* ---------------------------------------------------------------------------------------------------- */
349/* Test that the signal aspects of GDBusProxy works */
350/* ---------------------------------------------------------------------------------------------------- */
351
352static void
353test_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 (value: parameters, string: s, TRUE);
365}
366
367typedef struct
368{
369 GMainLoop *internal_loop;
370 GString *s;
371} TestSignalData;
372
373static void
374test_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: &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 (value: 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 (loop: data->internal_loop);
396}
397
398static void
399test_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 method_name: "EmitSignal",
423 parameters: g_variant_new (format_string: "(so)",
424 "Accept the next proposition you hear",
425 "/some/path"),
426 flags: G_DBUS_CALL_FLAGS_NONE,
427 timeout_msec: -1,
428 NULL,
429 error: &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 (value: 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 (instance: proxy, handler_id: signal_handler_id);
442 g_string_free (string: 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 method_name: "EmitSignal",
456 parameters: g_variant_new (format_string: "(so)",
457 "You will make a great programmer",
458 "/some/other/path"),
459 flags: G_DBUS_CALL_FLAGS_NONE,
460 timeout_msec: -1,
461 NULL,
462 callback: (GAsyncReadyCallback) test_proxy_signals_on_emit_signal_cb,
463 user_data: &data);
464 g_main_loop_run (loop: data.internal_loop);
465 g_main_loop_unref (loop: 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 (instance: proxy, handler_id: signal_handler_id);
470 g_string_free (string: s, TRUE);
471}
472
473/* ---------------------------------------------------------------------------------------------------- */
474
475static void
476test_bogus_method_return (GDBusProxy *proxy)
477{
478 GError *error = NULL;
479 GVariant *result;
480
481 result = g_dbus_proxy_call_sync (proxy,
482 method_name: "PairReturn",
483 NULL,
484 flags: G_DBUS_CALL_FLAGS_NONE,
485 timeout_msec: -1,
486 NULL,
487 error: &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 */
494static void
495test_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
530static void
531test_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
573static 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>";
598static GDBusInterfaceInfo *frob_dbus_interface_info;
599
600static void
601test_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, property_name: "y", value: g_variant_new_string (string: "error_me_out!"));
608 g_dbus_proxy_set_cached_property (proxy, property_name: "y", value: g_variant_new_byte (value: 42));
609 g_dbus_proxy_set_cached_property (proxy, property_name: "does-not-exist", value: g_variant_new_string (string: "something"));
610 g_dbus_proxy_set_cached_property (proxy, property_name: "does-not-exist", NULL);
611
612 /* Now repeat the method tests, with an expected interface set */
613 g_dbus_proxy_set_interface_info (proxy, info: 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, log_level: G_LOG_LEVEL_WARNING,
628 pattern: "*Trying to set property y of type s but according to the expected interface the type is y*");
629 value = g_variant_ref_sink (value: g_variant_new_string (string: "error_me_out!"));
630 g_dbus_proxy_set_cached_property (proxy, property_name: "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, property_name: "y", value: g_variant_new_byte (value: 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, log_level: G_LOG_LEVEL_WARNING,
644 pattern: "*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, property_name: "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, property_name: "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, property_name: "d", value: g_variant_new_double (value: 75.0));
663 /* ... and finally check that it has changed */
664 value = g_dbus_proxy_get_cached_property (proxy, property_name: "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, method_name: "FrobSetProperty",
672 parameters: g_variant_new (format_string: "(sv)", "d", g_variant_new_double (value: 85.0)),
673 flags: G_DBUS_CALL_FLAGS_NONE,
674 timeout_msec: -1, NULL, error: &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, property_name: "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
689static void
690test_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 (bus_type: 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 (object: proxy,
712 first_property_name: "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 (object: conn);
730 g_free (mem: name);
731 g_free (mem: path);
732 g_free (mem: interface);
733
734 g_object_unref (object: connection);
735}
736
737static void
738kill_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 bus_name: "org.freedesktop.DBus",
748 object_path: "/org/freedesktop/DBus",
749 interface_name: "org.freedesktop.DBus",
750 method_name: "GetConnectionUnixProcessID",
751 parameters: g_variant_new (format_string: "(s)", name),
752 NULL,
753 flags: G_DBUS_CALL_FLAGS_NONE,
754 timeout_msec: -1,
755 NULL,
756 error: &error);
757 g_variant_get (value: ret, format_string: "(u)", &pid);
758 g_variant_unref (value: ret);
759 kill (pid: pid, SIGTERM);
760#else
761 g_warning ("Can't kill com.example.TestService");
762#endif
763}
764
765static void
766test_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 (bus_type: G_BUS_TYPE_SESSION,
775 NULL,
776 error: &error);
777 g_assert_no_error (error);
778 error = NULL;
779 proxy = g_dbus_proxy_new_sync (connection,
780 flags: G_DBUS_PROXY_FLAGS_NONE,
781 NULL, /* GDBusInterfaceInfo */
782 name: "com.example.TestService", /* name */
783 object_path: "/com/example/TestObject", /* object path */
784 interface_name: "com.example.Frob", /* interface */
785 NULL, /* GCancellable */
786 error: &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 (mem: owner);
807
808 g_object_unref (object: proxy);
809 g_object_unref (object: connection);
810}
811
812/* ---------------------------------------------------------------------------------------------------- */
813
814static void
815proxy_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 (res: result, error: &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 (mem: 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 (connection: g_dbus_proxy_get_connection (proxy));
843 g_object_unref (object: proxy);
844 g_main_loop_quit (loop);
845}
846
847static gboolean
848fail_test (gpointer user_data)
849{
850 g_assert_not_reached ();
851}
852
853static void
854test_async (void)
855{
856 guint id;
857
858 g_dbus_proxy_new_for_bus (bus_type: G_BUS_TYPE_SESSION,
859 flags: G_DBUS_PROXY_FLAGS_NONE,
860 NULL, /* GDBusInterfaceInfo */
861 name: "com.example.TestService", /* name */
862 object_path: "/com/example/TestObject", /* object path */
863 interface_name: "com.example.Frob", /* interface */
864 NULL, /* GCancellable */
865 callback: proxy_ready,
866 NULL);
867
868 id = g_timeout_add (interval: 10000, function: fail_test, NULL);
869 g_main_loop_run (loop);
870
871 g_source_remove (tag: id);
872}
873
874static void
875test_no_properties (void)
876{
877 GDBusProxy *proxy;
878 GError *error;
879
880 error = NULL;
881 proxy = g_dbus_proxy_new_for_bus_sync (bus_type: G_BUS_TYPE_SESSION,
882 flags: G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
883 NULL, /* GDBusInterfaceInfo */
884 name: "com.example.TestService", /* name */
885 object_path: "/com/example/TestObject", /* object path */
886 interface_name: "com.example.Frob", /* interface */
887 NULL, /* GCancellable */
888 error: &error);
889 g_assert_no_error (error);
890
891 test_properties (proxy);
892
893 g_object_unref (object: proxy);
894}
895
896static void
897check_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), res: result, error: &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
912static void
913test_wellknown_noauto (void)
914{
915 GError *error = NULL;
916 GDBusProxy *proxy;
917 guint id;
918
919 proxy = g_dbus_proxy_new_for_bus_sync (bus_type: G_BUS_TYPE_SESSION,
920 flags: G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
921 NULL, name: "some.name.that.does.not.exist",
922 object_path: "/", interface_name: "some.interface", NULL, error: &error);
923 g_assert_no_error (error);
924 g_assert_nonnull (proxy);
925
926 g_dbus_proxy_call (proxy, method_name: "method", NULL, flags: G_DBUS_CALL_FLAGS_NONE, timeout_msec: -1, NULL, callback: check_error, NULL);
927 id = g_timeout_add (interval: 10000, function: fail_test, NULL);
928 g_main_loop_run (loop);
929 g_object_unref (object: proxy);
930 g_source_remove (tag: id);
931}
932
933int
934main (int argc,
935 char *argv[])
936{
937 gint ret;
938 GDBusNodeInfo *introspection_data = NULL;
939
940 g_test_init (argc: &argc, argv: &argv, NULL);
941
942 introspection_data = g_dbus_node_info_new_for_xml (xml_data: 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 (testpath: "/gdbus/proxy", test_func: test_proxy);
950 g_test_add_func (testpath: "/gdbus/proxy/no-properties", test_func: test_no_properties);
951 g_test_add_func (testpath: "/gdbus/proxy/wellknown-noauto", test_func: test_wellknown_noauto);
952 g_test_add_func (testpath: "/gdbus/proxy/async", test_func: test_async);
953
954 ret = session_bus_run();
955
956 g_dbus_node_info_unref (info: introspection_data);
957 g_main_loop_unref (loop);
958
959 return ret;
960}
961

source code of gtk/subprojects/glib/gio/tests/gdbus-proxy.c