nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | } |