Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright (C) 2008-2010 Red Hat, Inc.
4 : : * Copyright (C) 2021 Frederic Martinsons
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General
19 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 : : *
21 : : * Author: David Zeuthen <davidz@redhat.com>
22 : : * Author: Frederic Martinsons <frederic.martinsons@gmail.com>
23 : : */
24 : :
25 : : #include <gio/gio.h>
26 : : #include <unistd.h>
27 : :
28 : : #include "gdbus-tests.h"
29 : :
30 : : /* ---------------------------------------------------------------------------------------------------- */
31 : : /* Test that g_bus_own_name() works correctly */
32 : : /* ---------------------------------------------------------------------------------------------------- */
33 : :
34 : : typedef struct
35 : : {
36 : : gboolean expect_null_connection;
37 : : guint num_bus_acquired;
38 : : guint num_acquired;
39 : : guint num_lost;
40 : : guint num_free_func;
41 : : GMainContext *main_context; /* (unowned) */
42 : : } OwnNameData;
43 : :
44 : : static void
45 : 21 : own_name_data_free_func (OwnNameData *data)
46 : : {
47 : 21 : data->num_free_func++;
48 : 21 : g_main_context_wakeup (data->main_context);
49 : 21 : }
50 : :
51 : : static void
52 : 4 : bus_acquired_handler (GDBusConnection *connection,
53 : : const gchar *name,
54 : : gpointer user_data)
55 : : {
56 : 4 : OwnNameData *data = user_data;
57 : 4 : g_dbus_connection_set_exit_on_close (connection, FALSE);
58 : 4 : data->num_bus_acquired += 1;
59 : 4 : g_main_context_wakeup (data->main_context);
60 : 4 : }
61 : :
62 : : static void
63 : 5 : name_acquired_handler (GDBusConnection *connection,
64 : : const gchar *name,
65 : : gpointer user_data)
66 : : {
67 : 5 : OwnNameData *data = user_data;
68 : 5 : data->num_acquired += 1;
69 : 5 : g_main_context_wakeup (data->main_context);
70 : 5 : }
71 : :
72 : : static void
73 : 7 : name_lost_handler (GDBusConnection *connection,
74 : : const gchar *name,
75 : : gpointer user_data)
76 : : {
77 : 7 : OwnNameData *data = user_data;
78 [ + + ]: 7 : if (data->expect_null_connection)
79 : : {
80 : 2 : g_assert (connection == NULL);
81 : : }
82 : : else
83 : : {
84 : 5 : g_assert (connection != NULL);
85 : 5 : g_dbus_connection_set_exit_on_close (connection, FALSE);
86 : : }
87 : 7 : data->num_lost += 1;
88 : 7 : g_main_context_wakeup (data->main_context);
89 : 7 : }
90 : :
91 : : static void
92 : 1 : test_bus_own_name (void)
93 : : {
94 : : guint id;
95 : : guint id2;
96 : : OwnNameData data;
97 : : OwnNameData data2;
98 : : const gchar *name;
99 : : GDBusConnection *c;
100 : : GError *error;
101 : : gboolean name_has_owner_reply;
102 : : GDBusConnection *c2;
103 : : GVariant *result;
104 : 1 : GMainContext *main_context = NULL; /* use the global default for now */
105 : :
106 : 1 : error = NULL;
107 : 1 : name = "org.gtk.GDBus.Name1";
108 : :
109 : : /*
110 : : * First check that name_lost_handler() is invoked if there is no bus.
111 : : *
112 : : * Also make sure name_lost_handler() isn't invoked when unowning the name.
113 : : */
114 : 1 : data.num_bus_acquired = 0;
115 : 1 : data.num_free_func = 0;
116 : 1 : data.num_acquired = 0;
117 : 1 : data.num_lost = 0;
118 : 1 : data.expect_null_connection = TRUE;
119 : 1 : data.main_context = main_context;
120 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
121 : : name,
122 : : G_BUS_NAME_OWNER_FLAGS_NONE,
123 : : bus_acquired_handler,
124 : : name_acquired_handler,
125 : : name_lost_handler,
126 : : &data,
127 : : (GDestroyNotify) own_name_data_free_func);
128 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
129 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
130 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
131 : :
132 [ + + ]: 2 : while (data.num_lost < 1)
133 : 1 : g_main_context_iteration (main_context, TRUE);
134 : :
135 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
136 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
137 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
138 : 1 : g_bus_unown_name (id);
139 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
140 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
141 : 1 : g_assert_cmpint (data.num_free_func, ==, 1);
142 : :
143 : : /*
144 : : * Bring up a bus, then own a name and check bus_acquired_handler() then name_acquired_handler() is invoked.
145 : : */
146 : 1 : session_bus_up ();
147 : 1 : data.num_bus_acquired = 0;
148 : 1 : data.num_acquired = 0;
149 : 1 : data.num_lost = 0;
150 : 1 : data.expect_null_connection = FALSE;
151 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
152 : : name,
153 : : G_BUS_NAME_OWNER_FLAGS_NONE,
154 : : bus_acquired_handler,
155 : : name_acquired_handler,
156 : : name_lost_handler,
157 : : &data,
158 : : (GDestroyNotify) own_name_data_free_func);
159 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
160 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
161 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
162 : :
163 [ + + ]: 3 : while (data.num_bus_acquired < 1)
164 : 2 : g_main_context_iteration (main_context, TRUE);
165 : :
166 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
167 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
168 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
169 : :
170 [ + + ]: 3 : while (data.num_acquired < 1)
171 : 2 : g_main_context_iteration (main_context, TRUE);
172 : :
173 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
174 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
175 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
176 : :
177 : : /*
178 : : * Check that the name was actually acquired.
179 : : */
180 : 1 : c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
181 : 1 : g_assert (c != NULL);
182 : 1 : g_assert (!g_dbus_connection_is_closed (c));
183 : 1 : result = g_dbus_connection_call_sync (c,
184 : : "org.freedesktop.DBus", /* bus name */
185 : : "/org/freedesktop/DBus", /* object path */
186 : : "org.freedesktop.DBus", /* interface name */
187 : : "NameHasOwner", /* method name */
188 : : g_variant_new ("(s)", name),
189 : : G_VARIANT_TYPE ("(b)"),
190 : : G_DBUS_CALL_FLAGS_NONE,
191 : : -1,
192 : : NULL,
193 : : &error);
194 : 1 : g_assert_no_error (error);
195 : 1 : g_assert (result != NULL);
196 : 1 : g_variant_get (result, "(b)", &name_has_owner_reply);
197 : 1 : g_assert (name_has_owner_reply);
198 : 1 : g_variant_unref (result);
199 : :
200 : : /*
201 : : * Stop owning the name - this should invoke our free func
202 : : */
203 : 1 : g_bus_unown_name (id);
204 [ + + ]: 3 : while (data.num_free_func < 2)
205 : 2 : g_main_context_iteration (main_context, TRUE);
206 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
207 : :
208 : : /*
209 : : * Check that the name was actually released.
210 : : */
211 : 1 : result = g_dbus_connection_call_sync (c,
212 : : "org.freedesktop.DBus", /* bus name */
213 : : "/org/freedesktop/DBus", /* object path */
214 : : "org.freedesktop.DBus", /* interface name */
215 : : "NameHasOwner", /* method name */
216 : : g_variant_new ("(s)", name),
217 : : G_VARIANT_TYPE ("(b)"),
218 : : G_DBUS_CALL_FLAGS_NONE,
219 : : -1,
220 : : NULL,
221 : : &error);
222 : 1 : g_assert_no_error (error);
223 : 1 : g_assert (result != NULL);
224 : 1 : g_variant_get (result, "(b)", &name_has_owner_reply);
225 : 1 : g_assert (!name_has_owner_reply);
226 : 1 : g_variant_unref (result);
227 : :
228 : : /* Now try owning the name and then immediately decide to unown the name */
229 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
230 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
231 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
232 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
233 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
234 : : name,
235 : : G_BUS_NAME_OWNER_FLAGS_NONE,
236 : : bus_acquired_handler,
237 : : name_acquired_handler,
238 : : name_lost_handler,
239 : : &data,
240 : : (GDestroyNotify) own_name_data_free_func);
241 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
242 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
243 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
244 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
245 : 1 : g_bus_unown_name (id);
246 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
247 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
248 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
249 : 1 : g_assert_cmpint (data.num_free_func, ==, 2);
250 : :
251 : : /* the GDestroyNotify is called in idle because the bus is acquired in idle */
252 [ + + ]: 3 : while (data.num_free_func < 3)
253 : 2 : g_main_context_iteration (main_context, TRUE);
254 : :
255 : 1 : g_assert_cmpint (data.num_free_func, ==, 3);
256 : :
257 : : /*
258 : : * Own the name again.
259 : : */
260 : 1 : data.num_bus_acquired = 0;
261 : 1 : data.num_acquired = 0;
262 : 1 : data.num_lost = 0;
263 : 1 : data.expect_null_connection = FALSE;
264 : 1 : id = g_bus_own_name_with_closures (G_BUS_TYPE_SESSION,
265 : : name,
266 : : G_BUS_NAME_OWNER_FLAGS_NONE,
267 : : g_cclosure_new (G_CALLBACK (bus_acquired_handler),
268 : : &data,
269 : : NULL),
270 : : g_cclosure_new (G_CALLBACK (name_acquired_handler),
271 : : &data,
272 : : NULL),
273 : : g_cclosure_new (G_CALLBACK (name_lost_handler),
274 : : &data,
275 : : (GClosureNotify) own_name_data_free_func));
276 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
277 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
278 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
279 : :
280 [ + + ]: 3 : while (data.num_bus_acquired < 1)
281 : 2 : g_main_context_iteration (main_context, TRUE);
282 : :
283 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
284 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
285 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
286 : :
287 [ + + ]: 3 : while (data.num_acquired < 1)
288 : 2 : g_main_context_iteration (main_context, TRUE);
289 : :
290 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
291 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
292 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
293 : :
294 : : /*
295 : : * Try owning the name with another object on the same connection - this should
296 : : * fail because we already own the name.
297 : : */
298 : 1 : data2.num_free_func = 0;
299 : 1 : data2.num_bus_acquired = 0;
300 : 1 : data2.num_acquired = 0;
301 : 1 : data2.num_lost = 0;
302 : 1 : data2.expect_null_connection = FALSE;
303 : 1 : data2.main_context = main_context;
304 : 1 : id2 = g_bus_own_name (G_BUS_TYPE_SESSION,
305 : : name,
306 : : G_BUS_NAME_OWNER_FLAGS_NONE,
307 : : bus_acquired_handler,
308 : : name_acquired_handler,
309 : : name_lost_handler,
310 : : &data2,
311 : : (GDestroyNotify) own_name_data_free_func);
312 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
313 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
314 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
315 : :
316 [ + + ]: 3 : while (data2.num_bus_acquired < 1)
317 : 2 : g_main_context_iteration (main_context, TRUE);
318 : :
319 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 1);
320 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
321 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
322 : :
323 [ + + ]: 4 : while (data2.num_lost < 1)
324 : 3 : g_main_context_iteration (main_context, TRUE);
325 : :
326 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 1);
327 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
328 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
329 : :
330 : 1 : g_bus_unown_name (id2);
331 [ + + ]: 2 : while (data2.num_free_func < 1)
332 : 1 : g_main_context_iteration (main_context, TRUE);
333 : :
334 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 1);
335 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
336 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
337 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
338 : :
339 : : /*
340 : : * Create a secondary (e.g. private) connection and try owning the name on that
341 : : * connection. This should fail both with and without _REPLACE because we
342 : : * didn't specify ALLOW_REPLACEMENT.
343 : : */
344 : 1 : c2 = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, NULL);
345 : 1 : g_assert (c2 != NULL);
346 : 1 : g_assert (!g_dbus_connection_is_closed (c2));
347 : : /* first without _REPLACE */
348 : 1 : data2.num_bus_acquired = 0;
349 : 1 : data2.num_acquired = 0;
350 : 1 : data2.num_lost = 0;
351 : 1 : data2.expect_null_connection = FALSE;
352 : 1 : data2.num_free_func = 0;
353 : 1 : id2 = g_bus_own_name_on_connection (c2,
354 : : name,
355 : : G_BUS_NAME_OWNER_FLAGS_NONE,
356 : : name_acquired_handler,
357 : : name_lost_handler,
358 : : &data2,
359 : : (GDestroyNotify) own_name_data_free_func);
360 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
361 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
362 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
363 : :
364 [ + + ]: 3 : while (data2.num_lost < 1)
365 : 2 : g_main_context_iteration (main_context, TRUE);
366 : :
367 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
368 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
369 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
370 : :
371 : 1 : g_bus_unown_name (id2);
372 [ + + ]: 2 : while (data2.num_free_func < 1)
373 : 1 : g_main_context_iteration (main_context, TRUE);
374 : :
375 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
376 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
377 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
378 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
379 : : /* then with _REPLACE */
380 : 1 : data2.num_bus_acquired = 0;
381 : 1 : data2.num_acquired = 0;
382 : 1 : data2.num_lost = 0;
383 : 1 : data2.expect_null_connection = FALSE;
384 : 1 : data2.num_free_func = 0;
385 : 1 : id2 = g_bus_own_name_on_connection (c2,
386 : : name,
387 : : G_BUS_NAME_OWNER_FLAGS_REPLACE,
388 : : name_acquired_handler,
389 : : name_lost_handler,
390 : : &data2,
391 : : (GDestroyNotify) own_name_data_free_func);
392 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
393 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
394 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
395 : :
396 [ + + ]: 3 : while (data2.num_lost < 1)
397 : 2 : g_main_context_iteration (main_context, TRUE);
398 : :
399 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
400 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
401 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
402 : :
403 : 1 : g_bus_unown_name (id2);
404 [ + + ]: 2 : while (data2.num_free_func < 1)
405 : 1 : g_main_context_iteration (main_context, TRUE);
406 : :
407 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
408 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
409 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
410 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
411 : :
412 : : /*
413 : : * Stop owning the name and grab it again with _ALLOW_REPLACEMENT.
414 : : */
415 : 1 : data.expect_null_connection = FALSE;
416 : 1 : g_bus_unown_name (id);
417 [ - + + + ]: 3 : while (data.num_bus_acquired < 1 || data.num_free_func < 4)
418 : 2 : g_main_context_iteration (main_context, TRUE);
419 : :
420 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
421 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
422 : 1 : g_assert_cmpint (data.num_free_func, ==, 4);
423 : : /* grab it again */
424 : 1 : data.num_bus_acquired = 0;
425 : 1 : data.num_acquired = 0;
426 : 1 : data.num_lost = 0;
427 : 1 : data.expect_null_connection = FALSE;
428 : 1 : id = g_bus_own_name (G_BUS_TYPE_SESSION,
429 : : name,
430 : : G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
431 : : bus_acquired_handler,
432 : : name_acquired_handler,
433 : : name_lost_handler,
434 : : &data,
435 : : (GDestroyNotify) own_name_data_free_func);
436 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 0);
437 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
438 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
439 : :
440 [ + + ]: 3 : while (data.num_bus_acquired < 1)
441 : 2 : g_main_context_iteration (main_context, TRUE);
442 : :
443 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
444 : 1 : g_assert_cmpint (data.num_acquired, ==, 0);
445 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
446 : :
447 [ + + ]: 3 : while (data.num_acquired < 1)
448 : 2 : g_main_context_iteration (main_context, TRUE);
449 : :
450 : 1 : g_assert_cmpint (data.num_bus_acquired, ==, 1);
451 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
452 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
453 : :
454 : : /*
455 : : * Now try to grab the name from the secondary connection.
456 : : *
457 : : */
458 : : /* first without _REPLACE - this won't make us acquire the name */
459 : 1 : data2.num_bus_acquired = 0;
460 : 1 : data2.num_acquired = 0;
461 : 1 : data2.num_lost = 0;
462 : 1 : data2.expect_null_connection = FALSE;
463 : 1 : data2.num_free_func = 0;
464 : 1 : id2 = g_bus_own_name_on_connection (c2,
465 : : name,
466 : : G_BUS_NAME_OWNER_FLAGS_NONE,
467 : : name_acquired_handler,
468 : : name_lost_handler,
469 : : &data2,
470 : : (GDestroyNotify) own_name_data_free_func);
471 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
472 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
473 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
474 : :
475 [ + + ]: 3 : while (data2.num_lost < 1)
476 : 2 : g_main_context_iteration (main_context, TRUE);
477 : :
478 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
479 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
480 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
481 : :
482 : 1 : g_bus_unown_name (id2);
483 [ + + ]: 2 : while (data2.num_free_func < 1)
484 : 1 : g_main_context_iteration (main_context, TRUE);
485 : :
486 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
487 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
488 : 1 : g_assert_cmpint (data2.num_lost, ==, 1);
489 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
490 : : /* then with _REPLACE - here we should acquire the name - e.g. owner should lose it
491 : : * and owner2 should acquire it */
492 : 1 : data2.num_bus_acquired = 0;
493 : 1 : data2.num_acquired = 0;
494 : 1 : data2.num_lost = 0;
495 : 1 : data2.expect_null_connection = FALSE;
496 : 1 : data2.num_free_func = 0;
497 : 1 : id2 = g_bus_own_name_on_connection (c2,
498 : : name,
499 : : G_BUS_NAME_OWNER_FLAGS_REPLACE,
500 : : name_acquired_handler,
501 : : name_lost_handler,
502 : : &data2,
503 : : (GDestroyNotify) own_name_data_free_func);
504 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
505 : 1 : g_assert_cmpint (data.num_lost, ==, 0);
506 : 1 : g_assert_cmpint (data2.num_acquired, ==, 0);
507 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
508 : :
509 : : /* wait for handlers for both owner and owner2 to fire */
510 [ + + + + ]: 5 : while (data.num_lost == 0 || data2.num_acquired == 0)
511 : 4 : g_main_context_iteration (main_context, TRUE);
512 : :
513 : 1 : g_assert_cmpint (data.num_acquired, ==, 1);
514 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
515 : 1 : g_assert_cmpint (data2.num_acquired, ==, 1);
516 : 1 : g_assert_cmpint (data2.num_lost, ==, 0);
517 : 1 : g_assert_cmpint (data2.num_bus_acquired, ==, 0);
518 : :
519 : : /* ok, make owner2 release the name - then wait for owner to automagically reacquire it */
520 : 1 : g_bus_unown_name (id2);
521 [ + + + + ]: 3 : while (data.num_acquired < 2 || data2.num_free_func < 1)
522 : 2 : g_main_context_iteration (main_context, TRUE);
523 : :
524 : 1 : g_assert_cmpint (data2.num_free_func, ==, 1);
525 : 1 : g_assert_cmpint (data.num_acquired, ==, 2);
526 : 1 : g_assert_cmpint (data.num_lost, ==, 1);
527 : :
528 : : /*
529 : : * Finally, nuke the bus and check name_lost_handler() is invoked.
530 : : *
531 : : */
532 : 1 : data.expect_null_connection = TRUE;
533 : 1 : session_bus_stop ();
534 [ + + ]: 3 : while (data.num_lost != 2)
535 : 2 : g_main_context_iteration (main_context, TRUE);
536 : :
537 : 1 : g_assert_cmpint (data.num_acquired, ==, 2);
538 : 1 : g_assert_cmpint (data.num_lost, ==, 2);
539 : :
540 : 1 : g_bus_unown_name (id);
541 [ + + ]: 2 : while (data.num_free_func < 5)
542 : 1 : g_main_context_iteration (main_context, TRUE);
543 : :
544 : 1 : g_assert_cmpint (data.num_free_func, ==, 5);
545 : :
546 : 1 : g_object_unref (c);
547 : 1 : g_object_unref (c2);
548 : :
549 : 1 : session_bus_down ();
550 : 1 : }
551 : :
552 : : /* ---------------------------------------------------------------------------------------------------- */
553 : : /* Test that g_bus_watch_name() works correctly */
554 : : /* ---------------------------------------------------------------------------------------------------- */
555 : :
556 : : typedef struct
557 : : {
558 : : gboolean expect_null_connection;
559 : : guint num_acquired;
560 : : guint num_lost;
561 : : guint num_appeared;
562 : : guint num_vanished;
563 : : guint num_free_func;
564 : : GMainContext *main_context; /* (unowned), for the main test thread */
565 : : } WatchNameData;
566 : :
567 : : typedef struct
568 : : {
569 : : WatchNameData data;
570 : : GDBusConnection *connection;
571 : : GMutex cond_mutex;
572 : : GCond cond;
573 : : gboolean started;
574 : : gboolean name_acquired;
575 : : gboolean ended;
576 : : gboolean unwatch_early;
577 : : GMutex mutex;
578 : : guint watch_id;
579 : : GMainContext *thread_context; /* (unowned), only accessed from watcher_thread() */
580 : : } WatchNameThreadData;
581 : :
582 : : static void
583 : 15 : watch_name_data_free_func (WatchNameData *data)
584 : : {
585 : 15 : data->num_free_func++;
586 : 15 : g_main_context_wakeup (data->main_context);
587 : 15 : }
588 : :
589 : : static void
590 : 9 : w_bus_acquired_handler (GDBusConnection *connection,
591 : : const gchar *name,
592 : : gpointer user_data)
593 : : {
594 : 9 : }
595 : :
596 : : static void
597 : 11 : w_name_acquired_handler (GDBusConnection *connection,
598 : : const gchar *name,
599 : : gpointer user_data)
600 : : {
601 : 11 : OwnNameData *data = user_data;
602 : 11 : data->num_acquired += 1;
603 : 11 : g_main_context_wakeup (data->main_context);
604 : 11 : }
605 : :
606 : : static void
607 : 6 : w_name_lost_handler (GDBusConnection *connection,
608 : : const gchar *name,
609 : : gpointer user_data)
610 : : {
611 : 6 : OwnNameData *data = user_data;
612 : 6 : data->num_lost += 1;
613 : 6 : g_main_context_wakeup (data->main_context);
614 : 6 : }
615 : :
616 : : static void
617 : 10 : name_appeared_handler (GDBusConnection *connection,
618 : : const gchar *name,
619 : : const gchar *name_owner,
620 : : gpointer user_data)
621 : : {
622 : 10 : WatchNameData *data = user_data;
623 : :
624 [ - + ]: 10 : if (data->expect_null_connection)
625 : : {
626 : 0 : g_assert (connection == NULL);
627 : : }
628 : : else
629 : : {
630 : 10 : g_assert (connection != NULL);
631 : 10 : g_dbus_connection_set_exit_on_close (connection, FALSE);
632 : : }
633 : 10 : data->num_appeared += 1;
634 : 10 : g_main_context_wakeup (data->main_context);
635 : 10 : }
636 : :
637 : : static void
638 : 14 : name_vanished_handler (GDBusConnection *connection,
639 : : const gchar *name,
640 : : gpointer user_data)
641 : : {
642 : 14 : WatchNameData *data = user_data;
643 : :
644 [ + + ]: 14 : if (data->expect_null_connection)
645 : : {
646 : 9 : g_assert (connection == NULL);
647 : : }
648 : : else
649 : : {
650 : 5 : g_assert (connection != NULL);
651 : 5 : g_dbus_connection_set_exit_on_close (connection, FALSE);
652 : : }
653 : 14 : data->num_vanished += 1;
654 : 14 : g_main_context_wakeup (data->main_context);
655 : 14 : }
656 : :
657 : : typedef struct
658 : : {
659 : : guint watcher_flags;
660 : : gboolean watch_with_closures;
661 : : gboolean existing_service;
662 : : } WatchNameTest;
663 : :
664 : : static const WatchNameTest watch_no_closures_no_flags = {
665 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
666 : : .watch_with_closures = FALSE,
667 : : .existing_service = FALSE
668 : : };
669 : :
670 : : static const WatchNameTest watch_no_closures_flags_auto_start = {
671 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
672 : : .watch_with_closures = FALSE,
673 : : .existing_service = FALSE
674 : : };
675 : :
676 : : static const WatchNameTest watch_no_closures_flags_auto_start_service_exist = {
677 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
678 : : .watch_with_closures = FALSE,
679 : : .existing_service = TRUE
680 : : };
681 : :
682 : : static const WatchNameTest watch_closures_no_flags = {
683 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_NONE,
684 : : .watch_with_closures = TRUE,
685 : : .existing_service = FALSE
686 : : };
687 : :
688 : : static const WatchNameTest watch_closures_flags_auto_start = {
689 : : .watcher_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
690 : : .watch_with_closures = TRUE,
691 : : .existing_service = FALSE
692 : : };
693 : :
694 : : static void
695 : 1 : stop_service (GDBusConnection *connection,
696 : : WatchNameData *data)
697 : : {
698 : 1 : GError *error = NULL;
699 : 1 : GDBusProxy *proxy = NULL;
700 : 1 : GVariant *result = NULL;
701 : 1 : GMainContext *main_context = NULL; /* use the global default for now */
702 : :
703 : 1 : data->num_vanished = 0;
704 : :
705 : 1 : proxy = g_dbus_proxy_new_sync (connection,
706 : : G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
707 : : NULL,
708 : : "org.gtk.GDBus.FakeService",
709 : : "/org/gtk/GDBus/FakeService",
710 : : "org.gtk.GDBus.FakeService",
711 : : NULL,
712 : : &error);
713 : 1 : g_assert_no_error (error);
714 : :
715 : 1 : result = g_dbus_proxy_call_sync (proxy,
716 : : "Quit",
717 : : NULL,
718 : : G_DBUS_CALL_FLAGS_NO_AUTO_START,
719 : : 100,
720 : : NULL,
721 : : &error);
722 : 1 : g_assert_no_error (error);
723 : 1 : g_object_unref (proxy);
724 [ + - ]: 1 : if (result)
725 : 1 : g_variant_unref (result);
726 [ + + ]: 3 : while (data->num_vanished == 0)
727 : 2 : g_main_context_iteration (main_context, TRUE);
728 : 1 : }
729 : :
730 : : static void
731 : 5 : test_bus_watch_name (gconstpointer d)
732 : : {
733 : : WatchNameData data;
734 : : OwnNameData own_data;
735 : : guint id;
736 : : guint owner_id;
737 : : GDBusConnection *connection;
738 : : const WatchNameTest *watch_name_test;
739 : : const gchar *name;
740 : 5 : GMainContext *main_context = NULL; /* use the global default for now */
741 : :
742 : 5 : watch_name_test = (WatchNameTest *) d;
743 : :
744 [ + + ]: 5 : if (watch_name_test->existing_service)
745 : : {
746 : 1 : name = "org.gtk.GDBus.FakeService";
747 : : }
748 : : else
749 : : {
750 : 4 : name = "org.gtk.GDBus.Name1";
751 : : }
752 : :
753 : : /*
754 : : * First check that name_vanished_handler() is invoked if there is no bus.
755 : : *
756 : : * Also make sure name_vanished_handler() isn't invoked when unwatching the name.
757 : : */
758 : 5 : data.num_free_func = 0;
759 : 5 : data.num_appeared = 0;
760 : 5 : data.num_vanished = 0;
761 : 5 : data.expect_null_connection = TRUE;
762 : 5 : data.main_context = main_context;
763 : 5 : id = g_bus_watch_name (G_BUS_TYPE_SESSION,
764 : : name,
765 : 5 : watch_name_test->watcher_flags,
766 : : name_appeared_handler,
767 : : name_vanished_handler,
768 : : &data,
769 : : (GDestroyNotify) watch_name_data_free_func);
770 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
771 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
772 : :
773 [ + + ]: 10 : while (data.num_vanished < 1)
774 : 5 : g_main_context_iteration (main_context, TRUE);
775 : :
776 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
777 : 5 : g_assert_cmpint (data.num_vanished, ==, 1);
778 : :
779 : 5 : g_bus_unwatch_name (id);
780 [ + + ]: 10 : while (data.num_free_func < 1)
781 : 5 : g_main_context_iteration (main_context, TRUE);
782 : :
783 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
784 : 5 : g_assert_cmpint (data.num_vanished, ==, 1);
785 : 5 : g_assert_cmpint (data.num_free_func, ==, 1);
786 : 5 : data.num_free_func = 0;
787 : :
788 : : /*
789 : : * Now bring up a bus, own a name, and then start watching it.
790 : : */
791 : 5 : session_bus_up ();
792 : : /* own the name */
793 : 5 : own_data.num_free_func = 0;
794 : 5 : own_data.num_acquired = 0;
795 : 5 : own_data.num_lost = 0;
796 : 5 : data.expect_null_connection = FALSE;
797 : 5 : own_data.main_context = main_context;
798 : 5 : owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
799 : : name,
800 : : G_BUS_NAME_OWNER_FLAGS_NONE,
801 : : w_bus_acquired_handler,
802 : : w_name_acquired_handler,
803 : : w_name_lost_handler,
804 : : &own_data,
805 : : (GDestroyNotify) own_name_data_free_func);
806 : :
807 [ + + ]: 20 : while (own_data.num_acquired < 1)
808 : 15 : g_main_context_iteration (main_context, TRUE);
809 : :
810 : 5 : g_assert_cmpint (own_data.num_acquired, ==, 1);
811 : 5 : g_assert_cmpint (own_data.num_lost, ==, 0);
812 : :
813 : 5 : connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
814 : 5 : g_assert (connection != NULL);
815 : :
816 : : /* now watch the name */
817 : 5 : data.num_appeared = 0;
818 : 5 : data.num_vanished = 0;
819 [ + + ]: 5 : if (watch_name_test->watch_with_closures)
820 : : {
821 : 2 : id = g_bus_watch_name_on_connection_with_closures (connection,
822 : : name,
823 : 2 : watch_name_test->watcher_flags,
824 : : g_cclosure_new (G_CALLBACK (name_appeared_handler),
825 : : &data,
826 : : NULL),
827 : : g_cclosure_new (G_CALLBACK (name_vanished_handler),
828 : : &data,
829 : : (GClosureNotify) watch_name_data_free_func));
830 : : }
831 : : else
832 : : {
833 : 3 : id = g_bus_watch_name_on_connection (connection,
834 : : name,
835 : 3 : watch_name_test->watcher_flags,
836 : : name_appeared_handler,
837 : : name_vanished_handler,
838 : : &data,
839 : : (GDestroyNotify) watch_name_data_free_func);
840 : : }
841 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
842 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
843 : :
844 [ + + ]: 21 : while (data.num_appeared < 1)
845 : 16 : g_main_context_iteration (main_context, TRUE);
846 : :
847 : 5 : g_assert_cmpint (data.num_appeared, ==, 1);
848 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
849 : :
850 : : /*
851 : : * Unwatch the name.
852 : : */
853 : 5 : g_bus_unwatch_name (id);
854 [ + + ]: 10 : while (data.num_free_func < 1)
855 : 5 : g_main_context_iteration (main_context, TRUE);
856 : :
857 : 5 : g_assert_cmpint (data.num_free_func, ==, 1);
858 : :
859 : : /* unown the name */
860 : 5 : g_bus_unown_name (owner_id);
861 [ + + ]: 15 : while (own_data.num_free_func < 1)
862 : 10 : g_main_context_iteration (main_context, TRUE);
863 : :
864 : 5 : g_assert_cmpint (own_data.num_acquired, ==, 1);
865 : 5 : g_assert_cmpint (own_data.num_free_func, ==, 1);
866 : 5 : own_data.num_free_func = 0;
867 : : /*
868 : : * Create a watcher and then make a name be owned.
869 : : *
870 : : * This should trigger name_appeared_handler() ...
871 : : */
872 : : /* watch the name */
873 : 5 : data.num_appeared = 0;
874 : 5 : data.num_vanished = 0;
875 : 5 : data.num_free_func = 0;
876 [ + + ]: 5 : if (watch_name_test->watch_with_closures)
877 : : {
878 : 2 : id = g_bus_watch_name_with_closures (G_BUS_TYPE_SESSION,
879 : : name,
880 : 2 : watch_name_test->watcher_flags,
881 : : g_cclosure_new (G_CALLBACK (name_appeared_handler),
882 : : &data,
883 : : NULL),
884 : : g_cclosure_new (G_CALLBACK (name_vanished_handler),
885 : : &data,
886 : : (GClosureNotify) watch_name_data_free_func));
887 : : }
888 : : else
889 : : {
890 : 3 : id = g_bus_watch_name (G_BUS_TYPE_SESSION,
891 : : name,
892 : 3 : watch_name_test->watcher_flags,
893 : : name_appeared_handler,
894 : : name_vanished_handler,
895 : : &data,
896 : : (GDestroyNotify) watch_name_data_free_func);
897 : : }
898 : :
899 : 5 : g_assert_cmpint (data.num_appeared, ==, 0);
900 : 5 : g_assert_cmpint (data.num_vanished, ==, 0);
901 : :
902 [ + + + + ]: 24 : while (data.num_appeared == 0 && data.num_vanished == 0)
903 : 19 : g_main_context_iteration (main_context, TRUE);
904 : :
905 [ + + ]: 5 : if (watch_name_test->existing_service)
906 : : {
907 : 1 : g_assert_cmpint (data.num_appeared, ==, 1);
908 : 1 : g_assert_cmpint (data.num_vanished, ==, 0);
909 : : }
910 : : else
911 : : {
912 : 4 : g_assert_cmpint (data.num_appeared, ==, 0);
913 : 4 : g_assert_cmpint (data.num_vanished, ==, 1);
914 : : }
915 : :
916 [ + + ]: 5 : if (!watch_name_test->existing_service)
917 : : {
918 : : /* own the name */
919 : 4 : own_data.num_acquired = 0;
920 : 4 : own_data.num_lost = 0;
921 : 4 : own_data.expect_null_connection = FALSE;
922 : 4 : own_data.main_context = main_context;
923 : 4 : owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
924 : : name,
925 : : G_BUS_NAME_OWNER_FLAGS_NONE,
926 : : w_bus_acquired_handler,
927 : : w_name_acquired_handler,
928 : : w_name_lost_handler,
929 : : &own_data,
930 : : (GDestroyNotify) own_name_data_free_func);
931 : :
932 [ + + - + ]: 23 : while (own_data.num_acquired == 0 || data.num_appeared == 0)
933 : 19 : g_main_context_iteration (main_context, TRUE);
934 : :
935 : 4 : g_assert_cmpint (own_data.num_acquired, ==, 1);
936 : 4 : g_assert_cmpint (own_data.num_lost, ==, 0);
937 : 4 : g_assert_cmpint (data.num_appeared, ==, 1);
938 : 4 : g_assert_cmpint (data.num_vanished, ==, 1);
939 : : }
940 : :
941 : 5 : data.expect_null_connection = TRUE;
942 [ + + ]: 5 : if (watch_name_test->existing_service)
943 : : {
944 : 1 : data.expect_null_connection = FALSE;
945 : 1 : stop_service (connection, &data);
946 : : }
947 : 5 : g_object_unref (connection);
948 : : /*
949 : : * Nuke the bus and check that the name vanishes and is lost.
950 : : */
951 : 5 : session_bus_stop ();
952 [ + + ]: 5 : if (!watch_name_test->existing_service)
953 : : {
954 [ + + - + ]: 16 : while (own_data.num_lost < 1 || data.num_vanished < 2)
955 : 12 : g_main_context_iteration (main_context, TRUE);
956 : 4 : g_assert_cmpint (own_data.num_lost, ==, 1);
957 : 4 : g_assert_cmpint (data.num_vanished, ==, 2);
958 : : }
959 : : else
960 : : {
961 : 1 : g_assert_cmpint (own_data.num_lost, ==, 0);
962 : 1 : g_assert_cmpint (data.num_vanished, ==, 1);
963 : : }
964 : :
965 : 5 : g_bus_unwatch_name (id);
966 [ + + ]: 14 : while (data.num_free_func < 1)
967 : 9 : g_main_context_iteration (main_context, TRUE);
968 : :
969 : 5 : g_assert_cmpint (data.num_free_func, ==, 1);
970 : :
971 [ + + ]: 5 : if (!watch_name_test->existing_service)
972 : : {
973 : 4 : g_bus_unown_name (owner_id);
974 [ - + ]: 4 : while (own_data.num_free_func < 1)
975 : 0 : g_main_context_iteration (main_context, TRUE);
976 : :
977 : 4 : g_assert_cmpint (own_data.num_free_func, ==, 1);
978 : : }
979 : 5 : session_bus_down ();
980 : 5 : }
981 : :
982 : : /* ---------------------------------------------------------------------------------------------------- */
983 : :
984 : : /* Called in the same thread as watcher_thread() */
985 : : static void
986 : 2 : t_watch_name_data_free_func (WatchNameThreadData *thread_data)
987 : : {
988 : 2 : thread_data->data.num_free_func++;
989 : :
990 : 2 : g_assert_true (g_main_context_is_owner (thread_data->thread_context));
991 : 2 : g_main_context_wakeup (thread_data->thread_context);
992 : 2 : }
993 : :
994 : : /* Called in the same thread as watcher_thread() */
995 : : static void
996 : 2 : t_name_appeared_handler (GDBusConnection *connection,
997 : : const gchar *name,
998 : : const gchar *name_owner,
999 : : gpointer user_data)
1000 : : {
1001 : 2 : WatchNameThreadData *thread_data = user_data;
1002 : 2 : thread_data->data.num_appeared += 1;
1003 : :
1004 : 2 : g_assert_true (g_main_context_is_owner (thread_data->thread_context));
1005 : 2 : g_main_context_wakeup (thread_data->thread_context);
1006 : 2 : }
1007 : :
1008 : : /* Called in the same thread as watcher_thread() */
1009 : : static void
1010 : 1 : t_name_vanished_handler (GDBusConnection *connection,
1011 : : const gchar *name,
1012 : : gpointer user_data)
1013 : : {
1014 : 1 : WatchNameThreadData *thread_data = user_data;
1015 : 1 : thread_data->data.num_vanished += 1;
1016 : :
1017 : 1 : g_assert_true (g_main_context_is_owner (thread_data->thread_context));
1018 : 1 : g_main_context_wakeup (thread_data->thread_context);
1019 : 1 : }
1020 : :
1021 : : /* Called in the thread which constructed the GDBusConnection */
1022 : : static void
1023 : 2 : connection_closed_cb (GDBusConnection *connection,
1024 : : gboolean remote_peer_vanished,
1025 : : GError *error,
1026 : : gpointer user_data)
1027 : : {
1028 : 2 : WatchNameThreadData *thread_data = (WatchNameThreadData *) user_data;
1029 [ + + ]: 2 : if (thread_data->unwatch_early)
1030 : : {
1031 : 1 : g_mutex_lock (&thread_data->mutex);
1032 : 1 : g_bus_unwatch_name (g_atomic_int_get (&thread_data->watch_id));
1033 : 1 : g_atomic_int_set (&thread_data->watch_id, 0);
1034 : 1 : g_cond_signal (&thread_data->cond);
1035 : 1 : g_mutex_unlock (&thread_data->mutex);
1036 : : }
1037 : 2 : }
1038 : :
1039 : : static gpointer
1040 : 2 : watcher_thread (gpointer user_data)
1041 : : {
1042 : 2 : WatchNameThreadData *thread_data = user_data;
1043 : : GMainContext *thread_context;
1044 : :
1045 : 2 : thread_context = g_main_context_new ();
1046 : 2 : thread_data->thread_context = thread_context;
1047 : 2 : g_main_context_push_thread_default (thread_context);
1048 : :
1049 : : // Notify that the thread has started
1050 : 2 : g_mutex_lock (&thread_data->cond_mutex);
1051 : 2 : g_atomic_int_set (&thread_data->started, TRUE);
1052 : 2 : g_cond_signal (&thread_data->cond);
1053 : 2 : g_mutex_unlock (&thread_data->cond_mutex);
1054 : :
1055 : : // Wait for the main thread to own the name before watching it
1056 : 2 : g_mutex_lock (&thread_data->cond_mutex);
1057 [ + + ]: 4 : while (!g_atomic_int_get (&thread_data->name_acquired))
1058 : 2 : g_cond_wait (&thread_data->cond, &thread_data->cond_mutex);
1059 : 2 : g_mutex_unlock (&thread_data->cond_mutex);
1060 : :
1061 : 2 : thread_data->data.num_appeared = 0;
1062 : 2 : thread_data->data.num_vanished = 0;
1063 : 2 : thread_data->data.num_free_func = 0;
1064 : : // g_signal_connect_after is important to have default handler be called before our code
1065 : 2 : g_signal_connect_after (thread_data->connection, "closed", G_CALLBACK (connection_closed_cb), thread_data);
1066 : :
1067 : 2 : g_mutex_lock (&thread_data->mutex);
1068 : 2 : thread_data->watch_id = g_bus_watch_name_on_connection (thread_data->connection,
1069 : : "org.gtk.GDBus.Name1",
1070 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
1071 : : t_name_appeared_handler,
1072 : : t_name_vanished_handler,
1073 : : thread_data,
1074 : : (GDestroyNotify) t_watch_name_data_free_func);
1075 : 2 : g_mutex_unlock (&thread_data->mutex);
1076 : :
1077 : 2 : g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1078 : 2 : g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1079 [ + + ]: 4 : while (thread_data->data.num_appeared == 0)
1080 : 2 : g_main_context_iteration (thread_context, TRUE);
1081 : 2 : g_assert_cmpint (thread_data->data.num_appeared, ==, 1);
1082 : 2 : g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1083 : 2 : thread_data->data.num_appeared = 0;
1084 : :
1085 : : /* Close the connection and:
1086 : : * - check that we had received a vanished event even begin in different thread
1087 : : * - or check that unwatching the bus when a vanished had been scheduled
1088 : : * make it correctly unscheduled (unwatch_early condition)
1089 : : */
1090 : 2 : g_dbus_connection_close_sync (thread_data->connection, NULL, NULL);
1091 [ + + ]: 2 : if (thread_data->unwatch_early)
1092 : : {
1093 : : // Wait for the main thread to iterate in order to have close connection handled
1094 : 1 : g_mutex_lock (&thread_data->mutex);
1095 [ - + ]: 1 : while (g_atomic_int_get (&thread_data->watch_id) != 0)
1096 : 0 : g_cond_wait (&thread_data->cond, &thread_data->mutex);
1097 : 1 : g_mutex_unlock (&thread_data->mutex);
1098 : :
1099 [ + + ]: 2 : while (thread_data->data.num_free_func == 0)
1100 : 1 : g_main_context_iteration (thread_context, TRUE);
1101 : 1 : g_assert_cmpint (thread_data->data.num_vanished, ==, 0);
1102 : 1 : g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1103 : 1 : g_assert_cmpint (thread_data->data.num_free_func, ==, 1);
1104 : : }
1105 : : else
1106 : : {
1107 [ + + ]: 2 : while (thread_data->data.num_vanished == 0)
1108 : : {
1109 : : /*
1110 : : * Close of connection is treated in the context of the thread which
1111 : : * creates the connection. We must run iteration on it (to have the 'closed'
1112 : : * signal handled) and also run current thread loop to have name_vanished
1113 : : * callback handled.
1114 : : */
1115 : 1 : g_main_context_iteration (thread_context, TRUE);
1116 : : }
1117 : 1 : g_assert_cmpint (thread_data->data.num_vanished, ==, 1);
1118 : 1 : g_assert_cmpint (thread_data->data.num_appeared, ==, 0);
1119 : 1 : g_mutex_lock (&thread_data->mutex);
1120 : 1 : g_bus_unwatch_name (g_atomic_int_get (&thread_data->watch_id));
1121 : 1 : g_atomic_int_set (&thread_data->watch_id, 0);
1122 : 1 : g_mutex_unlock (&thread_data->mutex);
1123 [ - + ]: 1 : while (thread_data->data.num_free_func == 0)
1124 : 0 : g_main_context_iteration (thread_context, TRUE);
1125 : 1 : g_assert_cmpint (thread_data->data.num_free_func, ==, 1);
1126 : : }
1127 : :
1128 : 2 : g_mutex_lock (&thread_data->cond_mutex);
1129 : 2 : thread_data->ended = TRUE;
1130 : 2 : g_main_context_wakeup (NULL);
1131 : 2 : g_cond_signal (&thread_data->cond);
1132 : 2 : g_mutex_unlock (&thread_data->cond_mutex);
1133 : :
1134 : 2 : g_signal_handlers_disconnect_by_func (thread_data->connection, connection_closed_cb, thread_data);
1135 : 2 : g_object_unref (thread_data->connection);
1136 : 2 : g_main_context_pop_thread_default (thread_context);
1137 : 2 : g_main_context_unref (thread_context);
1138 : :
1139 : 2 : g_mutex_lock (&thread_data->mutex);
1140 : 2 : g_assert_cmpint (thread_data->watch_id, ==, 0);
1141 : 2 : g_mutex_unlock (&thread_data->mutex);
1142 : 2 : return NULL;
1143 : : }
1144 : :
1145 : : static void
1146 : 2 : watch_with_different_context (gboolean unwatch_early)
1147 : : {
1148 : : OwnNameData own_data;
1149 : : WatchNameThreadData thread_data;
1150 : : GDBusConnection *connection;
1151 : : GThread *watcher;
1152 : : guint id;
1153 : 2 : GMainContext *main_context = NULL; /* use the global default for now */
1154 : :
1155 : 2 : session_bus_up ();
1156 : :
1157 : 2 : connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
1158 : 2 : g_assert (connection != NULL);
1159 : :
1160 : 2 : g_mutex_init (&thread_data.mutex);
1161 : 2 : g_mutex_init (&thread_data.cond_mutex);
1162 : 2 : g_cond_init (&thread_data.cond);
1163 : 2 : thread_data.started = FALSE;
1164 : 2 : thread_data.name_acquired = FALSE;
1165 : 2 : thread_data.ended = FALSE;
1166 : 2 : thread_data.connection = g_object_ref (connection);
1167 : 2 : thread_data.unwatch_early = unwatch_early;
1168 : :
1169 : : // Create a thread which will watch a name and wait for it to be ready
1170 : 2 : g_mutex_lock (&thread_data.cond_mutex);
1171 : 2 : watcher = g_thread_new ("watcher", watcher_thread, &thread_data);
1172 [ + + ]: 4 : while (!g_atomic_int_get (&thread_data.started))
1173 : 2 : g_cond_wait (&thread_data.cond, &thread_data.cond_mutex);
1174 : 2 : g_mutex_unlock (&thread_data.cond_mutex);
1175 : :
1176 : 2 : own_data.num_acquired = 0;
1177 : 2 : own_data.num_lost = 0;
1178 : 2 : own_data.num_free_func = 0;
1179 : 2 : own_data.expect_null_connection = FALSE;
1180 : 2 : own_data.main_context = main_context;
1181 : : // Own the name to avoid direct name vanished in watcher thread
1182 : 2 : id = g_bus_own_name_on_connection (connection,
1183 : : "org.gtk.GDBus.Name1",
1184 : : G_BUS_NAME_OWNER_FLAGS_REPLACE,
1185 : : w_name_acquired_handler,
1186 : : w_name_lost_handler,
1187 : : &own_data,
1188 : : (GDestroyNotify) own_name_data_free_func);
1189 [ + + ]: 6 : while (own_data.num_acquired == 0)
1190 : 4 : g_main_context_iteration (main_context, TRUE);
1191 : 2 : g_assert_cmpint (own_data.num_acquired, ==, 1);
1192 : 2 : g_assert_cmpint (own_data.num_lost, ==, 0);
1193 : :
1194 : : // Wake the thread for it to begin watch
1195 : 2 : g_mutex_lock (&thread_data.cond_mutex);
1196 : 2 : g_atomic_int_set (&thread_data.name_acquired, TRUE);
1197 : 2 : g_cond_signal (&thread_data.cond);
1198 : 2 : g_mutex_unlock (&thread_data.cond_mutex);
1199 : :
1200 : : // Iterate the loop until thread is waking us up
1201 [ + + ]: 10 : while (!thread_data.ended)
1202 : 8 : g_main_context_iteration (main_context, TRUE);
1203 : :
1204 : 2 : g_thread_join (watcher);
1205 : :
1206 : 2 : g_bus_unown_name (id);
1207 [ - + ]: 2 : while (own_data.num_free_func == 0)
1208 : 0 : g_main_context_iteration (main_context, TRUE);
1209 : 2 : g_assert_cmpint (own_data.num_free_func, ==, 1);
1210 : :
1211 : 2 : g_mutex_clear (&thread_data.mutex);
1212 : 2 : g_mutex_clear (&thread_data.cond_mutex);
1213 : 2 : g_cond_clear (&thread_data.cond);
1214 : :
1215 : 2 : session_bus_stop ();
1216 : 2 : g_assert_true (g_dbus_connection_is_closed (connection));
1217 : 2 : g_object_unref (connection);
1218 : 2 : session_bus_down ();
1219 : 2 : }
1220 : :
1221 : : static void
1222 : 1 : test_bus_watch_different_context (void)
1223 : : {
1224 : 1 : watch_with_different_context (FALSE);
1225 : 1 : }
1226 : :
1227 : : /* ---------------------------------------------------------------------------------------------------- */
1228 : :
1229 : : static void
1230 : 1 : test_bus_unwatch_early (void)
1231 : : {
1232 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/604");
1233 : 1 : watch_with_different_context (TRUE);
1234 : 1 : }
1235 : :
1236 : : /* ---------------------------------------------------------------------------------------------------- */
1237 : :
1238 : : static void
1239 : 1 : test_validate_names (void)
1240 : : {
1241 : : guint n;
1242 : : static const struct
1243 : : {
1244 : : gboolean name;
1245 : : gboolean unique;
1246 : : gboolean interface;
1247 : : const gchar *string;
1248 : : } names[] = {
1249 : : { 1, 0, 1, "valid.well_known.name"},
1250 : : { 1, 0, 0, "valid.well-known.name"},
1251 : : { 1, 1, 0, ":valid.unique.name"},
1252 : : { 0, 0, 0, "invalid.5well_known.name"},
1253 : : { 0, 0, 0, "4invalid.5well_known.name"},
1254 : : { 1, 1, 0, ":4valid.5unique.name"},
1255 : : { 0, 0, 0, ""},
1256 : : { 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 */
1257 : : { 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! */
1258 : : { 0, 0, 0, ".starts.with.a.dot"},
1259 : : { 0, 0, 0, "contains.invalid;.characters"},
1260 : : { 0, 0, 0, "contains.inva/lid.characters"},
1261 : : { 0, 0, 0, "contains.inva[lid.characters"},
1262 : : { 0, 0, 0, "contains.inva]lid.characters"},
1263 : : { 0, 0, 0, "contains.inva_æøå_lid.characters"},
1264 : : { 1, 1, 0, ":1.1"},
1265 : : };
1266 : :
1267 [ + + ]: 17 : for (n = 0; n < G_N_ELEMENTS (names); n++)
1268 : : {
1269 [ + + ]: 16 : if (names[n].name)
1270 : 6 : g_assert (g_dbus_is_name (names[n].string));
1271 : : else
1272 : 10 : g_assert (!g_dbus_is_name (names[n].string));
1273 : :
1274 [ + + ]: 16 : if (names[n].unique)
1275 : 3 : g_assert (g_dbus_is_unique_name (names[n].string));
1276 : : else
1277 : 13 : g_assert (!g_dbus_is_unique_name (names[n].string));
1278 : :
1279 [ + + ]: 16 : if (names[n].interface)
1280 : : {
1281 : 2 : g_assert (g_dbus_is_interface_name (names[n].string));
1282 : 2 : g_assert (g_dbus_is_error_name (names[n].string));
1283 : : }
1284 : : else
1285 : : {
1286 : 14 : g_assert (!g_dbus_is_interface_name (names[n].string));
1287 : 14 : g_assert (!g_dbus_is_error_name (names[n].string));
1288 : : }
1289 : : }
1290 : 1 : }
1291 : :
1292 : : static void
1293 : 10 : assert_cmp_escaped_object_path (const gchar *s,
1294 : : const gchar *correct_escaped)
1295 : : {
1296 : : gchar *escaped;
1297 : : guint8 *unescaped;
1298 : :
1299 : 10 : escaped = g_dbus_escape_object_path (s);
1300 : 10 : g_assert_cmpstr (escaped, ==, correct_escaped);
1301 : :
1302 : 10 : g_free (escaped);
1303 : 10 : escaped = g_dbus_escape_object_path_bytestring ((const guint8 *) s);
1304 : 10 : g_assert_cmpstr (escaped, ==, correct_escaped);
1305 : :
1306 : 10 : unescaped = g_dbus_unescape_object_path (escaped);
1307 : 10 : g_assert_cmpstr ((const gchar *) unescaped, ==, s);
1308 : :
1309 : 10 : g_free (escaped);
1310 : 10 : g_free (unescaped);
1311 : 10 : }
1312 : :
1313 : : static void
1314 : 1 : test_escape_object_path (void)
1315 : : {
1316 : 1 : assert_cmp_escaped_object_path ("Foo42", "Foo42");
1317 : 1 : assert_cmp_escaped_object_path ("foo.bar.baz", "foo_2ebar_2ebaz");
1318 : 1 : assert_cmp_escaped_object_path ("foo_bar_baz", "foo_5fbar_5fbaz");
1319 : 1 : assert_cmp_escaped_object_path ("_", "_5f");
1320 : 1 : assert_cmp_escaped_object_path ("__", "_5f_5f");
1321 : 1 : assert_cmp_escaped_object_path ("", "_");
1322 : 1 : assert_cmp_escaped_object_path (":1.42", "_3a1_2e42");
1323 : 1 : assert_cmp_escaped_object_path ("a/b", "a_2fb");
1324 : 1 : assert_cmp_escaped_object_path (" ", "_20");
1325 : 1 : assert_cmp_escaped_object_path ("\n", "_0a");
1326 : :
1327 : 1 : g_assert_null (g_dbus_unescape_object_path ("_ii"));
1328 : 1 : g_assert_null (g_dbus_unescape_object_path ("döner"));
1329 : 1 : g_assert_null (g_dbus_unescape_object_path ("_00"));
1330 : 1 : g_assert_null (g_dbus_unescape_object_path ("_61"));
1331 : 1 : g_assert_null (g_dbus_unescape_object_path ("_ga"));
1332 : 1 : g_assert_null (g_dbus_unescape_object_path ("_ag"));
1333 : 1 : }
1334 : :
1335 : : /* ---------------------------------------------------------------------------------------------------- */
1336 : :
1337 : : int
1338 : 1 : main (int argc,
1339 : : char *argv[])
1340 : : {
1341 : : gint ret;
1342 : :
1343 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
1344 : :
1345 : 1 : g_test_dbus_unset ();
1346 : :
1347 : 1 : g_test_add_func ("/gdbus/validate-names", test_validate_names);
1348 : 1 : g_test_add_func ("/gdbus/bus-own-name", test_bus_own_name);
1349 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name",
1350 : : &watch_no_closures_no_flags,
1351 : : test_bus_watch_name);
1352 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-auto-start",
1353 : : &watch_no_closures_flags_auto_start,
1354 : : test_bus_watch_name);
1355 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-auto-start-service-exist",
1356 : : &watch_no_closures_flags_auto_start_service_exist,
1357 : : test_bus_watch_name);
1358 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-closures",
1359 : : &watch_closures_no_flags,
1360 : : test_bus_watch_name);
1361 : 1 : g_test_add_data_func ("/gdbus/bus-watch-name-closures-auto-start",
1362 : : &watch_closures_flags_auto_start,
1363 : : test_bus_watch_name);
1364 : 1 : g_test_add_func ("/gdbus/bus-watch-different-context", test_bus_watch_different_context);
1365 : 1 : g_test_add_func ("/gdbus/bus-unwatch-early", test_bus_unwatch_early);
1366 : 1 : g_test_add_func ("/gdbus/escape-object-path", test_escape_object_path);
1367 : 1 : ret = g_test_run();
1368 : :
1369 : 1 : return ret;
1370 : : }
|