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 | |
24 | #include "gdbus-tests.h" |
25 | |
26 | /* all tests rely on a shared mainloop */ |
27 | static GMainLoop *loop; |
28 | |
29 | /* ---------------------------------------------------------------------------------------------------- */ |
30 | /* Test that g_bus_own_name() works correctly */ |
31 | /* ---------------------------------------------------------------------------------------------------- */ |
32 | |
33 | typedef struct |
34 | { |
35 | gboolean expect_null_connection; |
36 | guint num_bus_acquired; |
37 | guint num_acquired; |
38 | guint num_lost; |
39 | guint num_free_func; |
40 | } OwnNameData; |
41 | |
42 | static void |
43 | own_name_data_free_func (OwnNameData *data) |
44 | { |
45 | data->num_free_func++; |
46 | g_main_loop_quit (loop); |
47 | } |
48 | |
49 | static void |
50 | bus_acquired_handler (GDBusConnection *connection, |
51 | const gchar *name, |
52 | gpointer user_data) |
53 | { |
54 | OwnNameData *data = user_data; |
55 | g_dbus_connection_set_exit_on_close (connection, FALSE); |
56 | data->num_bus_acquired += 1; |
57 | g_main_loop_quit (loop); |
58 | } |
59 | |
60 | static void |
61 | name_acquired_handler (GDBusConnection *connection, |
62 | const gchar *name, |
63 | gpointer user_data) |
64 | { |
65 | OwnNameData *data = user_data; |
66 | data->num_acquired += 1; |
67 | g_main_loop_quit (loop); |
68 | } |
69 | |
70 | static void |
71 | name_lost_handler (GDBusConnection *connection, |
72 | const gchar *name, |
73 | gpointer user_data) |
74 | { |
75 | OwnNameData *data = user_data; |
76 | if (data->expect_null_connection) |
77 | { |
78 | g_assert (connection == NULL); |
79 | } |
80 | else |
81 | { |
82 | g_assert (connection != NULL); |
83 | g_dbus_connection_set_exit_on_close (connection, FALSE); |
84 | } |
85 | data->num_lost += 1; |
86 | g_main_loop_quit (loop); |
87 | } |
88 | |
89 | static void |
90 | test_bus_own_name (void) |
91 | { |
92 | guint id; |
93 | guint id2; |
94 | OwnNameData data; |
95 | OwnNameData data2; |
96 | const gchar *name; |
97 | GDBusConnection *c; |
98 | GError *error; |
99 | gboolean name_has_owner_reply; |
100 | GDBusConnection *c2; |
101 | GVariant *result; |
102 | |
103 | error = NULL; |
104 | name = "org.gtk.GDBus.Name1" ; |
105 | |
106 | /* |
107 | * First check that name_lost_handler() is invoked if there is no bus. |
108 | * |
109 | * Also make sure name_lost_handler() isn't invoked when unowning the name. |
110 | */ |
111 | data.num_bus_acquired = 0; |
112 | data.num_free_func = 0; |
113 | data.num_acquired = 0; |
114 | data.num_lost = 0; |
115 | data.expect_null_connection = TRUE; |
116 | id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
117 | name, |
118 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
119 | bus_acquired_handler, |
120 | name_acquired_handler, |
121 | name_lost_handler, |
122 | user_data: &data, |
123 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
124 | g_assert_cmpint (data.num_bus_acquired, ==, 0); |
125 | g_assert_cmpint (data.num_acquired, ==, 0); |
126 | g_assert_cmpint (data.num_lost, ==, 0); |
127 | g_main_loop_run (loop); |
128 | g_assert_cmpint (data.num_bus_acquired, ==, 0); |
129 | g_assert_cmpint (data.num_acquired, ==, 0); |
130 | g_assert_cmpint (data.num_lost, ==, 1); |
131 | g_bus_unown_name (owner_id: id); |
132 | g_assert_cmpint (data.num_acquired, ==, 0); |
133 | g_assert_cmpint (data.num_lost, ==, 1); |
134 | g_assert_cmpint (data.num_free_func, ==, 1); |
135 | |
136 | /* |
137 | * Bring up a bus, then own a name and check bus_acquired_handler() then name_acquired_handler() is invoked. |
138 | */ |
139 | session_bus_up (); |
140 | data.num_bus_acquired = 0; |
141 | data.num_acquired = 0; |
142 | data.num_lost = 0; |
143 | data.expect_null_connection = FALSE; |
144 | id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
145 | name, |
146 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
147 | bus_acquired_handler, |
148 | name_acquired_handler, |
149 | name_lost_handler, |
150 | user_data: &data, |
151 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
152 | g_assert_cmpint (data.num_bus_acquired, ==, 0); |
153 | g_assert_cmpint (data.num_acquired, ==, 0); |
154 | g_assert_cmpint (data.num_lost, ==, 0); |
155 | g_main_loop_run (loop); |
156 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
157 | g_assert_cmpint (data.num_acquired, ==, 0); |
158 | g_assert_cmpint (data.num_lost, ==, 0); |
159 | g_main_loop_run (loop); |
160 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
161 | g_assert_cmpint (data.num_acquired, ==, 1); |
162 | g_assert_cmpint (data.num_lost, ==, 0); |
163 | |
164 | /* |
165 | * Check that the name was actually acquired. |
166 | */ |
167 | c = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
168 | g_assert (c != NULL); |
169 | g_assert (!g_dbus_connection_is_closed (c)); |
170 | result = g_dbus_connection_call_sync (connection: c, |
171 | bus_name: "org.freedesktop.DBus" , /* bus name */ |
172 | object_path: "/org/freedesktop/DBus" , /* object path */ |
173 | interface_name: "org.freedesktop.DBus" , /* interface name */ |
174 | method_name: "NameHasOwner" , /* method name */ |
175 | parameters: g_variant_new (format_string: "(s)" , name), |
176 | G_VARIANT_TYPE ("(b)" ), |
177 | flags: G_DBUS_CALL_FLAGS_NONE, |
178 | timeout_msec: -1, |
179 | NULL, |
180 | error: &error); |
181 | g_assert_no_error (error); |
182 | g_assert (result != NULL); |
183 | g_variant_get (value: result, format_string: "(b)" , &name_has_owner_reply); |
184 | g_assert (name_has_owner_reply); |
185 | g_variant_unref (value: result); |
186 | |
187 | /* |
188 | * Stop owning the name - this should invoke our free func |
189 | */ |
190 | g_bus_unown_name (owner_id: id); |
191 | g_main_loop_run (loop); |
192 | g_assert_cmpint (data.num_free_func, ==, 2); |
193 | |
194 | /* |
195 | * Check that the name was actually released. |
196 | */ |
197 | result = g_dbus_connection_call_sync (connection: c, |
198 | bus_name: "org.freedesktop.DBus" , /* bus name */ |
199 | object_path: "/org/freedesktop/DBus" , /* object path */ |
200 | interface_name: "org.freedesktop.DBus" , /* interface name */ |
201 | method_name: "NameHasOwner" , /* method name */ |
202 | parameters: g_variant_new (format_string: "(s)" , name), |
203 | G_VARIANT_TYPE ("(b)" ), |
204 | flags: G_DBUS_CALL_FLAGS_NONE, |
205 | timeout_msec: -1, |
206 | NULL, |
207 | error: &error); |
208 | g_assert_no_error (error); |
209 | g_assert (result != NULL); |
210 | g_variant_get (value: result, format_string: "(b)" , &name_has_owner_reply); |
211 | g_assert (!name_has_owner_reply); |
212 | g_variant_unref (value: result); |
213 | |
214 | /* Now try owning the name and then immediately decide to unown the name */ |
215 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
216 | g_assert_cmpint (data.num_acquired, ==, 1); |
217 | g_assert_cmpint (data.num_lost, ==, 0); |
218 | g_assert_cmpint (data.num_free_func, ==, 2); |
219 | id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
220 | name, |
221 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
222 | bus_acquired_handler, |
223 | name_acquired_handler, |
224 | name_lost_handler, |
225 | user_data: &data, |
226 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
227 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
228 | g_assert_cmpint (data.num_acquired, ==, 1); |
229 | g_assert_cmpint (data.num_lost, ==, 0); |
230 | g_assert_cmpint (data.num_free_func, ==, 2); |
231 | g_bus_unown_name (owner_id: id); |
232 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
233 | g_assert_cmpint (data.num_acquired, ==, 1); |
234 | g_assert_cmpint (data.num_lost, ==, 0); |
235 | g_assert_cmpint (data.num_free_func, ==, 2); |
236 | g_main_loop_run (loop); /* the GDestroyNotify is called in idle because the bus is acquired in idle */ |
237 | g_assert_cmpint (data.num_free_func, ==, 3); |
238 | |
239 | /* |
240 | * Own the name again. |
241 | */ |
242 | data.num_bus_acquired = 0; |
243 | data.num_acquired = 0; |
244 | data.num_lost = 0; |
245 | data.expect_null_connection = FALSE; |
246 | id = g_bus_own_name_with_closures (bus_type: G_BUS_TYPE_SESSION, |
247 | name, |
248 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
249 | bus_acquired_closure: g_cclosure_new (G_CALLBACK (bus_acquired_handler), |
250 | user_data: &data, |
251 | NULL), |
252 | name_acquired_closure: g_cclosure_new (G_CALLBACK (name_acquired_handler), |
253 | user_data: &data, |
254 | NULL), |
255 | name_lost_closure: g_cclosure_new (G_CALLBACK (name_lost_handler), |
256 | user_data: &data, |
257 | destroy_data: (GClosureNotify) own_name_data_free_func)); |
258 | g_assert_cmpint (data.num_bus_acquired, ==, 0); |
259 | g_assert_cmpint (data.num_acquired, ==, 0); |
260 | g_assert_cmpint (data.num_lost, ==, 0); |
261 | g_main_loop_run (loop); |
262 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
263 | g_assert_cmpint (data.num_acquired, ==, 0); |
264 | g_assert_cmpint (data.num_lost, ==, 0); |
265 | g_main_loop_run (loop); |
266 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
267 | g_assert_cmpint (data.num_acquired, ==, 1); |
268 | g_assert_cmpint (data.num_lost, ==, 0); |
269 | |
270 | /* |
271 | * Try owning the name with another object on the same connection - this should |
272 | * fail because we already own the name. |
273 | */ |
274 | data2.num_free_func = 0; |
275 | data2.num_bus_acquired = 0; |
276 | data2.num_acquired = 0; |
277 | data2.num_lost = 0; |
278 | data2.expect_null_connection = FALSE; |
279 | id2 = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
280 | name, |
281 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
282 | bus_acquired_handler, |
283 | name_acquired_handler, |
284 | name_lost_handler, |
285 | user_data: &data2, |
286 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
287 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
288 | g_assert_cmpint (data2.num_acquired, ==, 0); |
289 | g_assert_cmpint (data2.num_lost, ==, 0); |
290 | g_main_loop_run (loop); |
291 | g_assert_cmpint (data2.num_bus_acquired, ==, 1); |
292 | g_assert_cmpint (data2.num_acquired, ==, 0); |
293 | g_assert_cmpint (data2.num_lost, ==, 0); |
294 | g_main_loop_run (loop); |
295 | g_assert_cmpint (data2.num_bus_acquired, ==, 1); |
296 | g_assert_cmpint (data2.num_acquired, ==, 0); |
297 | g_assert_cmpint (data2.num_lost, ==, 1); |
298 | g_bus_unown_name (owner_id: id2); |
299 | g_main_loop_run (loop); |
300 | g_assert_cmpint (data2.num_bus_acquired, ==, 1); |
301 | g_assert_cmpint (data2.num_acquired, ==, 0); |
302 | g_assert_cmpint (data2.num_lost, ==, 1); |
303 | g_assert_cmpint (data2.num_free_func, ==, 1); |
304 | |
305 | /* |
306 | * Create a secondary (e.g. private) connection and try owning the name on that |
307 | * connection. This should fail both with and without _REPLACE because we |
308 | * didn't specify ALLOW_REPLACEMENT. |
309 | */ |
310 | c2 = _g_bus_get_priv (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
311 | g_assert (c2 != NULL); |
312 | g_assert (!g_dbus_connection_is_closed (c2)); |
313 | /* first without _REPLACE */ |
314 | data2.num_bus_acquired = 0; |
315 | data2.num_acquired = 0; |
316 | data2.num_lost = 0; |
317 | data2.expect_null_connection = FALSE; |
318 | data2.num_free_func = 0; |
319 | id2 = g_bus_own_name_on_connection (connection: c2, |
320 | name, |
321 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
322 | name_acquired_handler, |
323 | name_lost_handler, |
324 | user_data: &data2, |
325 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
326 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
327 | g_assert_cmpint (data2.num_acquired, ==, 0); |
328 | g_assert_cmpint (data2.num_lost, ==, 0); |
329 | g_main_loop_run (loop); |
330 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
331 | g_assert_cmpint (data2.num_acquired, ==, 0); |
332 | g_assert_cmpint (data2.num_lost, ==, 1); |
333 | g_bus_unown_name (owner_id: id2); |
334 | g_main_loop_run (loop); |
335 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
336 | g_assert_cmpint (data2.num_acquired, ==, 0); |
337 | g_assert_cmpint (data2.num_lost, ==, 1); |
338 | g_assert_cmpint (data2.num_free_func, ==, 1); |
339 | /* then with _REPLACE */ |
340 | data2.num_bus_acquired = 0; |
341 | data2.num_acquired = 0; |
342 | data2.num_lost = 0; |
343 | data2.expect_null_connection = FALSE; |
344 | data2.num_free_func = 0; |
345 | id2 = g_bus_own_name_on_connection (connection: c2, |
346 | name, |
347 | flags: G_BUS_NAME_OWNER_FLAGS_REPLACE, |
348 | name_acquired_handler, |
349 | name_lost_handler, |
350 | user_data: &data2, |
351 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
352 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
353 | g_assert_cmpint (data2.num_acquired, ==, 0); |
354 | g_assert_cmpint (data2.num_lost, ==, 0); |
355 | g_main_loop_run (loop); |
356 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
357 | g_assert_cmpint (data2.num_acquired, ==, 0); |
358 | g_assert_cmpint (data2.num_lost, ==, 1); |
359 | g_bus_unown_name (owner_id: id2); |
360 | g_main_loop_run (loop); |
361 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
362 | g_assert_cmpint (data2.num_acquired, ==, 0); |
363 | g_assert_cmpint (data2.num_lost, ==, 1); |
364 | g_assert_cmpint (data2.num_free_func, ==, 1); |
365 | |
366 | /* |
367 | * Stop owning the name and grab it again with _ALLOW_REPLACEMENT. |
368 | */ |
369 | data.expect_null_connection = FALSE; |
370 | g_bus_unown_name (owner_id: id); |
371 | g_main_loop_run (loop); |
372 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
373 | g_assert_cmpint (data.num_acquired, ==, 1); |
374 | g_assert_cmpint (data.num_free_func, ==, 4); |
375 | /* grab it again */ |
376 | data.num_bus_acquired = 0; |
377 | data.num_acquired = 0; |
378 | data.num_lost = 0; |
379 | data.expect_null_connection = FALSE; |
380 | id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
381 | name, |
382 | flags: G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, |
383 | bus_acquired_handler, |
384 | name_acquired_handler, |
385 | name_lost_handler, |
386 | user_data: &data, |
387 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
388 | g_assert_cmpint (data.num_bus_acquired, ==, 0); |
389 | g_assert_cmpint (data.num_acquired, ==, 0); |
390 | g_assert_cmpint (data.num_lost, ==, 0); |
391 | g_main_loop_run (loop); |
392 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
393 | g_assert_cmpint (data.num_acquired, ==, 0); |
394 | g_assert_cmpint (data.num_lost, ==, 0); |
395 | g_main_loop_run (loop); |
396 | g_assert_cmpint (data.num_bus_acquired, ==, 1); |
397 | g_assert_cmpint (data.num_acquired, ==, 1); |
398 | g_assert_cmpint (data.num_lost, ==, 0); |
399 | |
400 | /* |
401 | * Now try to grab the name from the secondary connection. |
402 | * |
403 | */ |
404 | /* first without _REPLACE - this won't make us acquire the name */ |
405 | data2.num_bus_acquired = 0; |
406 | data2.num_acquired = 0; |
407 | data2.num_lost = 0; |
408 | data2.expect_null_connection = FALSE; |
409 | data2.num_free_func = 0; |
410 | id2 = g_bus_own_name_on_connection (connection: c2, |
411 | name, |
412 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
413 | name_acquired_handler, |
414 | name_lost_handler, |
415 | user_data: &data2, |
416 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
417 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
418 | g_assert_cmpint (data2.num_acquired, ==, 0); |
419 | g_assert_cmpint (data2.num_lost, ==, 0); |
420 | g_main_loop_run (loop); |
421 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
422 | g_assert_cmpint (data2.num_acquired, ==, 0); |
423 | g_assert_cmpint (data2.num_lost, ==, 1); |
424 | g_bus_unown_name (owner_id: id2); |
425 | g_main_loop_run (loop); |
426 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
427 | g_assert_cmpint (data2.num_acquired, ==, 0); |
428 | g_assert_cmpint (data2.num_lost, ==, 1); |
429 | g_assert_cmpint (data2.num_free_func, ==, 1); |
430 | /* then with _REPLACE - here we should acquire the name - e.g. owner should lose it |
431 | * and owner2 should acquire it */ |
432 | data2.num_bus_acquired = 0; |
433 | data2.num_acquired = 0; |
434 | data2.num_lost = 0; |
435 | data2.expect_null_connection = FALSE; |
436 | data2.num_free_func = 0; |
437 | id2 = g_bus_own_name_on_connection (connection: c2, |
438 | name, |
439 | flags: G_BUS_NAME_OWNER_FLAGS_REPLACE, |
440 | name_acquired_handler, |
441 | name_lost_handler, |
442 | user_data: &data2, |
443 | user_data_free_func: (GDestroyNotify) own_name_data_free_func); |
444 | g_assert_cmpint (data.num_acquired, ==, 1); |
445 | g_assert_cmpint (data.num_lost, ==, 0); |
446 | g_assert_cmpint (data2.num_acquired, ==, 0); |
447 | g_assert_cmpint (data2.num_lost, ==, 0); |
448 | /* wait for handlers for both owner and owner2 to fire */ |
449 | while (data.num_lost == 0 || data2.num_acquired == 0) |
450 | g_main_loop_run (loop); |
451 | g_assert_cmpint (data.num_acquired, ==, 1); |
452 | g_assert_cmpint (data.num_lost, ==, 1); |
453 | g_assert_cmpint (data2.num_acquired, ==, 1); |
454 | g_assert_cmpint (data2.num_lost, ==, 0); |
455 | g_assert_cmpint (data2.num_bus_acquired, ==, 0); |
456 | /* ok, make owner2 release the name - then wait for owner to automagically reacquire it */ |
457 | g_bus_unown_name (owner_id: id2); |
458 | g_main_loop_run (loop); |
459 | g_main_loop_run (loop); |
460 | g_assert_cmpint (data2.num_free_func, ==, 1); |
461 | g_assert_cmpint (data.num_acquired, ==, 2); |
462 | g_assert_cmpint (data.num_lost, ==, 1); |
463 | |
464 | /* |
465 | * Finally, nuke the bus and check name_lost_handler() is invoked. |
466 | * |
467 | */ |
468 | data.expect_null_connection = TRUE; |
469 | session_bus_stop (); |
470 | while (data.num_lost != 2) |
471 | g_main_loop_run (loop); |
472 | g_assert_cmpint (data.num_acquired, ==, 2); |
473 | g_assert_cmpint (data.num_lost, ==, 2); |
474 | g_bus_unown_name (owner_id: id); |
475 | g_main_loop_run (loop); |
476 | g_assert_cmpint (data.num_free_func, ==, 5); |
477 | |
478 | g_object_unref (object: c); |
479 | g_object_unref (object: c2); |
480 | |
481 | session_bus_down (); |
482 | } |
483 | |
484 | /* ---------------------------------------------------------------------------------------------------- */ |
485 | /* Test that g_bus_watch_name() works correctly */ |
486 | /* ---------------------------------------------------------------------------------------------------- */ |
487 | |
488 | typedef struct |
489 | { |
490 | gboolean expect_null_connection; |
491 | guint num_acquired; |
492 | guint num_lost; |
493 | guint num_appeared; |
494 | guint num_vanished; |
495 | guint num_free_func; |
496 | } WatchNameData; |
497 | |
498 | static void |
499 | watch_name_data_free_func (WatchNameData *data) |
500 | { |
501 | data->num_free_func++; |
502 | g_main_loop_quit (loop); |
503 | } |
504 | |
505 | static void |
506 | w_bus_acquired_handler (GDBusConnection *connection, |
507 | const gchar *name, |
508 | gpointer user_data) |
509 | { |
510 | } |
511 | |
512 | static void |
513 | w_name_acquired_handler (GDBusConnection *connection, |
514 | const gchar *name, |
515 | gpointer user_data) |
516 | { |
517 | WatchNameData *data = user_data; |
518 | data->num_acquired += 1; |
519 | g_main_loop_quit (loop); |
520 | } |
521 | |
522 | static void |
523 | w_name_lost_handler (GDBusConnection *connection, |
524 | const gchar *name, |
525 | gpointer user_data) |
526 | { |
527 | WatchNameData *data = user_data; |
528 | data->num_lost += 1; |
529 | g_main_loop_quit (loop); |
530 | } |
531 | |
532 | static void |
533 | name_appeared_handler (GDBusConnection *connection, |
534 | const gchar *name, |
535 | const gchar *name_owner, |
536 | gpointer user_data) |
537 | { |
538 | WatchNameData *data = user_data; |
539 | |
540 | if (data->expect_null_connection) |
541 | { |
542 | g_assert (connection == NULL); |
543 | } |
544 | else |
545 | { |
546 | g_assert (connection != NULL); |
547 | g_dbus_connection_set_exit_on_close (connection, FALSE); |
548 | } |
549 | data->num_appeared += 1; |
550 | g_main_loop_quit (loop); |
551 | } |
552 | |
553 | static void |
554 | name_vanished_handler (GDBusConnection *connection, |
555 | const gchar *name, |
556 | gpointer user_data) |
557 | { |
558 | WatchNameData *data = user_data; |
559 | |
560 | if (data->expect_null_connection) |
561 | { |
562 | g_assert (connection == NULL); |
563 | } |
564 | else |
565 | { |
566 | g_assert (connection != NULL); |
567 | g_dbus_connection_set_exit_on_close (connection, FALSE); |
568 | } |
569 | data->num_vanished += 1; |
570 | g_main_loop_quit (loop); |
571 | } |
572 | |
573 | typedef struct |
574 | { |
575 | guint watcher_flags; |
576 | gboolean watch_with_closures; |
577 | gboolean existing_service; |
578 | } WatchNameTest; |
579 | |
580 | static const WatchNameTest watch_no_closures_no_flags = { |
581 | .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE, |
582 | .watch_with_closures = FALSE, |
583 | .existing_service = FALSE |
584 | }; |
585 | |
586 | static const WatchNameTest watch_no_closures_flags_auto_start = { |
587 | .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START, |
588 | .watch_with_closures = FALSE, |
589 | .existing_service = FALSE |
590 | }; |
591 | |
592 | static const WatchNameTest watch_no_closures_flags_auto_start_service_exist = { |
593 | .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START, |
594 | .watch_with_closures = FALSE, |
595 | .existing_service = TRUE |
596 | }; |
597 | |
598 | static const WatchNameTest watch_closures_no_flags = { |
599 | .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE, |
600 | .watch_with_closures = TRUE, |
601 | .existing_service = FALSE |
602 | }; |
603 | |
604 | static const WatchNameTest watch_closures_flags_auto_start = { |
605 | .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START, |
606 | .watch_with_closures = TRUE, |
607 | .existing_service = FALSE |
608 | }; |
609 | |
610 | static void |
611 | stop_service (GDBusConnection *connection, |
612 | WatchNameData *data) |
613 | { |
614 | GError *error = NULL; |
615 | GDBusProxy *proxy = NULL; |
616 | |
617 | data->num_vanished = 0; |
618 | |
619 | proxy = g_dbus_proxy_new_sync (connection, |
620 | flags: G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, |
621 | NULL, |
622 | name: "org.gtk.GDBus.FakeService" , |
623 | object_path: "/org/gtk/GDBus/FakeService" , |
624 | interface_name: "org.gtk.GDBus.FakeService" , |
625 | NULL, |
626 | error: &error); |
627 | g_assert_no_error (error); |
628 | |
629 | g_dbus_proxy_call_sync (proxy, |
630 | method_name: "Quit" , |
631 | NULL, |
632 | flags: G_DBUS_CALL_FLAGS_NO_AUTO_START, |
633 | timeout_msec: 100, |
634 | NULL, |
635 | error: &error); |
636 | g_assert_no_error (error); |
637 | g_object_unref (object: proxy); |
638 | while (data->num_vanished == 0) |
639 | g_main_loop_run (loop); |
640 | } |
641 | |
642 | static void |
643 | test_bus_watch_name (gconstpointer d) |
644 | { |
645 | WatchNameData data; |
646 | guint id; |
647 | guint owner_id; |
648 | GDBusConnection *connection; |
649 | const WatchNameTest *watch_name_test; |
650 | const gchar *name; |
651 | |
652 | watch_name_test = (WatchNameTest *) d; |
653 | |
654 | if (watch_name_test->existing_service) |
655 | { |
656 | name = "org.gtk.GDBus.FakeService" ; |
657 | } |
658 | else |
659 | { |
660 | name = "org.gtk.GDBus.Name1" ; |
661 | } |
662 | |
663 | /* |
664 | * First check that name_vanished_handler() is invoked if there is no bus. |
665 | * |
666 | * Also make sure name_vanished_handler() isn't invoked when unwatching the name. |
667 | */ |
668 | data.num_free_func = 0; |
669 | data.num_appeared = 0; |
670 | data.num_vanished = 0; |
671 | data.expect_null_connection = TRUE; |
672 | id = g_bus_watch_name (bus_type: G_BUS_TYPE_SESSION, |
673 | name, |
674 | flags: watch_name_test->watcher_flags, |
675 | name_appeared_handler, |
676 | name_vanished_handler, |
677 | user_data: &data, |
678 | user_data_free_func: (GDestroyNotify) watch_name_data_free_func); |
679 | g_assert_cmpint (data.num_appeared, ==, 0); |
680 | g_assert_cmpint (data.num_vanished, ==, 0); |
681 | g_main_loop_run (loop); |
682 | g_assert_cmpint (data.num_appeared, ==, 0); |
683 | g_assert_cmpint (data.num_vanished, ==, 1); |
684 | g_bus_unwatch_name (watcher_id: id); |
685 | g_assert_cmpint (data.num_appeared, ==, 0); |
686 | g_assert_cmpint (data.num_vanished, ==, 1); |
687 | g_assert_cmpint (data.num_free_func, ==, 1); |
688 | |
689 | /* |
690 | * Now bring up a bus, own a name, and then start watching it. |
691 | */ |
692 | session_bus_up (); |
693 | /* own the name */ |
694 | data.num_free_func = 0; |
695 | data.num_acquired = 0; |
696 | data.num_lost = 0; |
697 | data.expect_null_connection = FALSE; |
698 | owner_id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
699 | name, |
700 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
701 | bus_acquired_handler: w_bus_acquired_handler, |
702 | name_acquired_handler: w_name_acquired_handler, |
703 | name_lost_handler: w_name_lost_handler, |
704 | user_data: &data, |
705 | user_data_free_func: (GDestroyNotify) watch_name_data_free_func); |
706 | g_main_loop_run (loop); |
707 | g_assert_cmpint (data.num_acquired, ==, 1); |
708 | g_assert_cmpint (data.num_lost, ==, 0); |
709 | |
710 | connection = g_bus_get_sync (bus_type: G_BUS_TYPE_SESSION, NULL, NULL); |
711 | g_assert (connection != NULL); |
712 | |
713 | /* now watch the name */ |
714 | data.num_appeared = 0; |
715 | data.num_vanished = 0; |
716 | if (watch_name_test->watch_with_closures) |
717 | { |
718 | id = g_bus_watch_name_on_connection_with_closures (connection, |
719 | name, |
720 | flags: watch_name_test->watcher_flags, |
721 | name_appeared_closure: g_cclosure_new (G_CALLBACK (name_appeared_handler), |
722 | user_data: &data, |
723 | NULL), |
724 | name_vanished_closure: g_cclosure_new (G_CALLBACK (name_vanished_handler), |
725 | user_data: &data, |
726 | destroy_data: (GClosureNotify) watch_name_data_free_func)); |
727 | } |
728 | else |
729 | { |
730 | id = g_bus_watch_name_on_connection (connection, |
731 | name, |
732 | flags: watch_name_test->watcher_flags, |
733 | name_appeared_handler, |
734 | name_vanished_handler, |
735 | user_data: &data, |
736 | user_data_free_func: (GDestroyNotify) watch_name_data_free_func); |
737 | } |
738 | g_assert_cmpint (data.num_appeared, ==, 0); |
739 | g_assert_cmpint (data.num_vanished, ==, 0); |
740 | g_main_loop_run (loop); |
741 | g_assert_cmpint (data.num_appeared, ==, 1); |
742 | g_assert_cmpint (data.num_vanished, ==, 0); |
743 | |
744 | /* |
745 | * Unwatch the name. |
746 | */ |
747 | g_bus_unwatch_name (watcher_id: id); |
748 | g_assert_cmpint (data.num_free_func, ==, 1); |
749 | |
750 | /* unown the name */ |
751 | g_bus_unown_name (owner_id); |
752 | g_main_loop_run (loop); |
753 | g_assert_cmpint (data.num_acquired, ==, 1); |
754 | g_assert_cmpint (data.num_free_func, ==, 2); |
755 | |
756 | /* |
757 | * Create a watcher and then make a name be owned. |
758 | * |
759 | * This should trigger name_appeared_handler() ... |
760 | */ |
761 | /* watch the name */ |
762 | data.num_appeared = 0; |
763 | data.num_vanished = 0; |
764 | data.num_free_func = 0; |
765 | if (watch_name_test->watch_with_closures) |
766 | { |
767 | id = g_bus_watch_name_with_closures (bus_type: G_BUS_TYPE_SESSION, |
768 | name, |
769 | flags: watch_name_test->watcher_flags, |
770 | name_appeared_closure: g_cclosure_new (G_CALLBACK (name_appeared_handler), |
771 | user_data: &data, |
772 | NULL), |
773 | name_vanished_closure: g_cclosure_new (G_CALLBACK (name_vanished_handler), |
774 | user_data: &data, |
775 | destroy_data: (GClosureNotify) watch_name_data_free_func)); |
776 | } |
777 | else |
778 | { |
779 | id = g_bus_watch_name (bus_type: G_BUS_TYPE_SESSION, |
780 | name, |
781 | flags: watch_name_test->watcher_flags, |
782 | name_appeared_handler, |
783 | name_vanished_handler, |
784 | user_data: &data, |
785 | user_data_free_func: (GDestroyNotify) watch_name_data_free_func); |
786 | } |
787 | |
788 | g_assert_cmpint (data.num_appeared, ==, 0); |
789 | g_assert_cmpint (data.num_vanished, ==, 0); |
790 | g_main_loop_run (loop); |
791 | if (watch_name_test->existing_service) |
792 | { |
793 | g_assert_cmpint (data.num_appeared, ==, 1); |
794 | g_assert_cmpint (data.num_vanished, ==, 0); |
795 | } |
796 | else |
797 | { |
798 | g_assert_cmpint (data.num_appeared, ==, 0); |
799 | g_assert_cmpint (data.num_vanished, ==, 1); |
800 | } |
801 | |
802 | if (!watch_name_test->existing_service) |
803 | { |
804 | /* own the name */ |
805 | data.num_acquired = 0; |
806 | data.num_lost = 0; |
807 | data.expect_null_connection = FALSE; |
808 | owner_id = g_bus_own_name (bus_type: G_BUS_TYPE_SESSION, |
809 | name, |
810 | flags: G_BUS_NAME_OWNER_FLAGS_NONE, |
811 | bus_acquired_handler: w_bus_acquired_handler, |
812 | name_acquired_handler: w_name_acquired_handler, |
813 | name_lost_handler: w_name_lost_handler, |
814 | user_data: &data, |
815 | user_data_free_func: (GDestroyNotify) watch_name_data_free_func); |
816 | while (data.num_acquired == 0 || data.num_appeared == 0) |
817 | g_main_loop_run (loop); |
818 | g_assert_cmpint (data.num_acquired, ==, 1); |
819 | g_assert_cmpint (data.num_lost, ==, 0); |
820 | g_assert_cmpint (data.num_appeared, ==, 1); |
821 | g_assert_cmpint (data.num_vanished, ==, 1); |
822 | } |
823 | |
824 | data.expect_null_connection = TRUE; |
825 | if (watch_name_test->existing_service) |
826 | { |
827 | data.expect_null_connection = FALSE; |
828 | stop_service (connection, data: &data); |
829 | } |
830 | g_object_unref (object: connection); |
831 | /* |
832 | * Nuke the bus and check that the name vanishes and is lost. |
833 | */ |
834 | session_bus_stop (); |
835 | if (!watch_name_test->existing_service) |
836 | { |
837 | g_main_loop_run (loop); |
838 | g_assert_cmpint (data.num_lost, ==, 1); |
839 | g_assert_cmpint (data.num_vanished, ==, 2); |
840 | } |
841 | else |
842 | { |
843 | g_assert_cmpint (data.num_lost, ==, 0); |
844 | g_assert_cmpint (data.num_vanished, ==, 1); |
845 | } |
846 | g_bus_unwatch_name (watcher_id: id); |
847 | g_assert_cmpint (data.num_free_func, ==, 1); |
848 | |
849 | if (!watch_name_test->existing_service) |
850 | { |
851 | g_bus_unown_name (owner_id); |
852 | g_main_loop_run (loop); |
853 | g_assert_cmpint (data.num_free_func, ==, 2); |
854 | } |
855 | session_bus_down (); |
856 | } |
857 | |
858 | /* ---------------------------------------------------------------------------------------------------- */ |
859 | |
860 | static void |
861 | test_validate_names (void) |
862 | { |
863 | guint n; |
864 | static const struct |
865 | { |
866 | gboolean name; |
867 | gboolean unique; |
868 | gboolean interface; |
869 | const gchar *string; |
870 | } names[] = { |
871 | { 1, 0, 1, "valid.well_known.name" }, |
872 | { 1, 0, 0, "valid.well-known.name" }, |
873 | { 1, 1, 0, ":valid.unique.name" }, |
874 | { 0, 0, 0, "invalid.5well_known.name" }, |
875 | { 0, 0, 0, "4invalid.5well_known.name" }, |
876 | { 1, 1, 0, ":4valid.5unique.name" }, |
877 | { 0, 0, 0, "" }, |
878 | { 1, 0, 1, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name1" }, /* 255 */ |
879 | { 0, 0, 0, "very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.very.long.name12" }, /* 256 - too long! */ |
880 | { 0, 0, 0, ".starts.with.a.dot" }, |
881 | { 0, 0, 0, "contains.invalid;.characters" }, |
882 | { 0, 0, 0, "contains.inva/lid.characters" }, |
883 | { 0, 0, 0, "contains.inva[lid.characters" }, |
884 | { 0, 0, 0, "contains.inva]lid.characters" }, |
885 | { 0, 0, 0, "contains.inva_æøå_lid.characters" }, |
886 | { 1, 1, 0, ":1.1" }, |
887 | }; |
888 | |
889 | for (n = 0; n < G_N_ELEMENTS (names); n++) |
890 | { |
891 | if (names[n].name) |
892 | g_assert (g_dbus_is_name (names[n].string)); |
893 | else |
894 | g_assert (!g_dbus_is_name (names[n].string)); |
895 | |
896 | if (names[n].unique) |
897 | g_assert (g_dbus_is_unique_name (names[n].string)); |
898 | else |
899 | g_assert (!g_dbus_is_unique_name (names[n].string)); |
900 | |
901 | if (names[n].interface) |
902 | g_assert (g_dbus_is_interface_name (names[n].string)); |
903 | else |
904 | g_assert (!g_dbus_is_interface_name (names[n].string)); |
905 | } |
906 | } |
907 | |
908 | static void |
909 | assert_cmp_escaped_object_path (const gchar *s, |
910 | const gchar *correct_escaped) |
911 | { |
912 | gchar *escaped; |
913 | guint8 *unescaped; |
914 | |
915 | escaped = g_dbus_escape_object_path (s); |
916 | g_assert_cmpstr (escaped, ==, correct_escaped); |
917 | |
918 | g_free (mem: escaped); |
919 | escaped = g_dbus_escape_object_path_bytestring (bytes: (const guint8 *) s); |
920 | g_assert_cmpstr (escaped, ==, correct_escaped); |
921 | |
922 | unescaped = g_dbus_unescape_object_path (s: escaped); |
923 | g_assert_cmpstr ((const gchar *) unescaped, ==, s); |
924 | |
925 | g_free (mem: escaped); |
926 | g_free (mem: unescaped); |
927 | } |
928 | |
929 | static void |
930 | test_escape_object_path (void) |
931 | { |
932 | assert_cmp_escaped_object_path (s: "Foo42" , correct_escaped: "Foo42" ); |
933 | assert_cmp_escaped_object_path (s: "foo.bar.baz" , correct_escaped: "foo_2ebar_2ebaz" ); |
934 | assert_cmp_escaped_object_path (s: "foo_bar_baz" , correct_escaped: "foo_5fbar_5fbaz" ); |
935 | assert_cmp_escaped_object_path (s: "_" , correct_escaped: "_5f" ); |
936 | assert_cmp_escaped_object_path (s: "__" , correct_escaped: "_5f_5f" ); |
937 | assert_cmp_escaped_object_path (s: "" , correct_escaped: "_" ); |
938 | assert_cmp_escaped_object_path (s: ":1.42" , correct_escaped: "_3a1_2e42" ); |
939 | assert_cmp_escaped_object_path (s: "a/b" , correct_escaped: "a_2fb" ); |
940 | assert_cmp_escaped_object_path (s: " " , correct_escaped: "_20" ); |
941 | assert_cmp_escaped_object_path (s: "\n" , correct_escaped: "_0a" ); |
942 | |
943 | g_assert_null (g_dbus_unescape_object_path ("_ii" )); |
944 | g_assert_null (g_dbus_unescape_object_path ("döner" )); |
945 | g_assert_null (g_dbus_unescape_object_path ("_00" )); |
946 | g_assert_null (g_dbus_unescape_object_path ("_61" )); |
947 | g_assert_null (g_dbus_unescape_object_path ("_ga" )); |
948 | g_assert_null (g_dbus_unescape_object_path ("_ag" )); |
949 | } |
950 | |
951 | /* ---------------------------------------------------------------------------------------------------- */ |
952 | |
953 | int |
954 | main (int argc, |
955 | char *argv[]) |
956 | { |
957 | gint ret; |
958 | |
959 | g_test_init (argc: &argc, argv: &argv, NULL); |
960 | |
961 | loop = g_main_loop_new (NULL, FALSE); |
962 | |
963 | g_test_dbus_unset (); |
964 | |
965 | g_test_add_func (testpath: "/gdbus/validate-names" , test_func: test_validate_names); |
966 | g_test_add_func (testpath: "/gdbus/bus-own-name" , test_func: test_bus_own_name); |
967 | g_test_add_data_func (testpath: "/gdbus/bus-watch-name" , |
968 | test_data: &watch_no_closures_no_flags, |
969 | test_func: test_bus_watch_name); |
970 | g_test_add_data_func (testpath: "/gdbus/bus-watch-name-auto-start" , |
971 | test_data: &watch_no_closures_flags_auto_start, |
972 | test_func: test_bus_watch_name); |
973 | g_test_add_data_func (testpath: "/gdbus/bus-watch-name-auto-start-service-exist" , |
974 | test_data: &watch_no_closures_flags_auto_start_service_exist, |
975 | test_func: test_bus_watch_name); |
976 | g_test_add_data_func (testpath: "/gdbus/bus-watch-name-closures" , |
977 | test_data: &watch_closures_no_flags, |
978 | test_func: test_bus_watch_name); |
979 | g_test_add_data_func (testpath: "/gdbus/bus-watch-name-closures-auto-start" , |
980 | test_data: &watch_closures_flags_auto_start, |
981 | test_func: test_bus_watch_name); |
982 | g_test_add_func (testpath: "/gdbus/escape-object-path" , test_func: test_escape_object_path); |
983 | ret = g_test_run(); |
984 | |
985 | g_main_loop_unref (loop); |
986 | |
987 | return ret; |
988 | } |
989 | |