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 */
27static GMainLoop *loop;
28
29/* ---------------------------------------------------------------------------------------------------- */
30/* Test that g_bus_own_name() works correctly */
31/* ---------------------------------------------------------------------------------------------------- */
32
33typedef 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
42static void
43own_name_data_free_func (OwnNameData *data)
44{
45 data->num_free_func++;
46 g_main_loop_quit (loop);
47}
48
49static void
50bus_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
60static void
61name_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
70static void
71name_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
89static void
90test_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
488typedef 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
498static void
499watch_name_data_free_func (WatchNameData *data)
500{
501 data->num_free_func++;
502 g_main_loop_quit (loop);
503}
504
505static void
506w_bus_acquired_handler (GDBusConnection *connection,
507 const gchar *name,
508 gpointer user_data)
509{
510}
511
512static void
513w_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
522static void
523w_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
532static void
533name_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
553static void
554name_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
573typedef struct
574{
575 guint watcher_flags;
576 gboolean watch_with_closures;
577 gboolean existing_service;
578} WatchNameTest;
579
580static 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
586static 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
592static 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
598static 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
604static 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
610static void
611stop_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
642static void
643test_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
860static void
861test_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
908static void
909assert_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
929static void
930test_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
953int
954main (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

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