Fix getauxval error at qemu
[platform/upstream/glib.git] / gio / gtestdbus.c
1 /* GIO testing utilities
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
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  * Authors: David Zeuthen <davidz@redhat.com>
22  *          Xavier Claessens <xavier.claessens@collabora.co.uk>
23  */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <gstdio.h>
32 #ifdef G_OS_UNIX
33 #include <unistd.h>
34 #endif
35 #ifdef G_OS_WIN32
36 #include <io.h>
37 #include <fcntl.h>
38 #include <windows.h>
39 #endif
40
41 #include <glib.h>
42
43 #include "gdbusconnection.h"
44 #include "gdbusprivate.h"
45 #include "gfile.h"
46 #include "gioenumtypes.h"
47 #include "gtestdbus.h"
48
49 #include "glibintl.h"
50
51 #ifdef G_OS_UNIX
52 #include "glib-unix.h"
53 #include "glib-unixprivate.h"
54 #endif
55
56 /* -------------------------------------------------------------------------- */
57 /* Utility: Wait until object has a single ref  */
58
59 typedef struct
60 {
61   GMainLoop *loop;
62   gboolean   timed_out;
63 } WeakNotifyData;
64
65 static void
66 on_weak_notify_timeout (gpointer user_data)
67 {
68   WeakNotifyData *data = user_data;
69   data->timed_out = TRUE;
70   g_main_loop_quit (data->loop);
71 }
72
73 static gboolean
74 unref_on_idle (gpointer object)
75 {
76   g_object_unref (object);
77   return FALSE;
78 }
79
80 static gboolean
81 _g_object_unref_and_wait_weak_notify (gpointer object)
82 {
83   WeakNotifyData data;
84   guint timeout_id;
85
86   data.loop = g_main_loop_new (NULL, FALSE);
87   data.timed_out = FALSE;
88
89   g_object_weak_ref (object, (GWeakNotify) g_main_loop_quit, data.loop);
90
91   /* Drop the strong ref held by the caller in an idle callback. This is to
92    * make sure the mainloop is already running when weak notify happens (when
93    * all other strong ref holders have dropped theirs). */
94   g_idle_add (unref_on_idle, object);
95
96   /* Make sure we don't block forever */
97   timeout_id = g_timeout_add_seconds_once (30, on_weak_notify_timeout, &data);
98
99   g_main_loop_run (data.loop);
100
101   if (data.timed_out)
102     {
103       g_warning ("Weak notify timeout, object ref_count=%d",
104           G_OBJECT (object)->ref_count);
105     }
106   else
107     {
108       g_source_remove (timeout_id);
109     }
110
111   g_main_loop_unref (data.loop);
112   return data.timed_out;
113 }
114
115 /* -------------------------------------------------------------------------- */
116 /* Utilities to cleanup the mess in the case unit test process crash */
117
118 #ifdef G_OS_WIN32
119
120 /* This could be interesting to expose in public API */
121 static void
122 _g_test_watcher_add_pid (GPid pid)
123 {
124   static gsize started = 0;
125   HANDLE job;
126
127   if (g_once_init_enter (&started))
128     {
129       JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
130
131       job = CreateJobObjectW (NULL, NULL);
132       memset (&info, 0, sizeof (info));
133       info.BasicLimitInformation.LimitFlags = 0x2000 /* JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE */;
134
135       if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof (info)))
136         g_warning ("Can't enable JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: %s", g_win32_error_message (GetLastError()));
137
138       g_once_init_leave (&started,(gsize)job);
139     }
140
141   job = (HANDLE)started;
142
143   if (!AssignProcessToJobObject(job, pid))
144     g_warning ("Can't assign process to job: %s", g_win32_error_message (GetLastError()));
145 }
146
147 static void
148 _g_test_watcher_remove_pid (GPid pid)
149 {
150   /* No need to unassign the process from the job object as the process
151      will be killed anyway */
152 }
153
154 #else
155
156 #define ADD_PID_FORMAT "add pid %d\n"
157 #define REMOVE_PID_FORMAT "remove pid %d\n"
158
159 static void
160 watch_parent (gint fd)
161 {
162   GIOChannel *channel;
163   GPollFD fds[1];
164   GArray *pids_to_kill;
165
166   channel = g_io_channel_unix_new (fd);
167
168   fds[0].fd = fd;
169   fds[0].events = G_IO_HUP | G_IO_IN;
170   fds[0].revents = 0;
171
172   pids_to_kill = g_array_new (FALSE, FALSE, sizeof (guint));
173
174   do
175     {
176       gint num_events;
177       gchar *command = NULL;
178       guint pid;
179       guint n;
180       GError *error = NULL;
181
182       num_events = g_poll (fds, 1, -1);
183       if (num_events == 0)
184         continue;
185
186       if (fds[0].revents & G_IO_HUP)
187         {
188           /* Parent quit, cleanup the mess and exit */
189           for (n = 0; n < pids_to_kill->len; n++)
190             {
191               pid = g_array_index (pids_to_kill, guint, n);
192               g_printerr ("cleaning up pid %d\n", pid);
193               kill (pid, SIGTERM);
194             }
195
196           g_array_unref (pids_to_kill);
197           g_io_channel_shutdown (channel, FALSE, &error);
198           g_assert_no_error (error);
199           g_io_channel_unref (channel);
200
201           exit (0);
202         }
203
204       /* Read the command from the input */
205       g_io_channel_read_line (channel, &command, NULL, NULL, &error);
206       g_assert_no_error (error);
207
208       /* Check for known commands */
209       if (sscanf (command, ADD_PID_FORMAT, &pid) == 1)
210         {
211           g_array_append_val (pids_to_kill, pid);
212         }
213       else if (sscanf (command, REMOVE_PID_FORMAT, &pid) == 1)
214         {
215           for (n = 0; n < pids_to_kill->len; n++)
216             {
217               if (g_array_index (pids_to_kill, guint, n) == pid)
218                 {
219                   g_array_remove_index (pids_to_kill, n);
220                   pid = 0;
221                   break;
222                 }
223             }
224           if (pid != 0)
225             {
226               g_warning ("unknown pid %d to remove", pid);
227             }
228         }
229       else
230         {
231           g_warning ("unknown command from parent '%s'", command);
232         }
233
234       g_free (command);
235     }
236   while (TRUE);
237 }
238
239 static GIOChannel *
240 watcher_init (void)
241 {
242   static gsize started = 0;
243   static GIOChannel *channel = NULL;
244   int errsv;
245
246   if (g_once_init_enter (&started))
247     {
248       gint pipe_fds[2];
249
250       /* fork a child to clean up when we are killed */
251       if (!g_unix_open_pipe_internal (pipe_fds, TRUE, FALSE))
252         {
253           errsv = errno;
254           g_warning ("pipe() failed: %s", g_strerror (errsv));
255           g_assert_not_reached ();
256         }
257
258       /* flush streams to avoid buffers being duplicated in the child and
259        * flushed by both the child and parent later
260        *
261        * FIXME: This is a workaround for the fact that watch_parent() uses
262        * non-async-signal-safe API. See
263        * https://gitlab.gnome.org/GNOME/glib/-/issues/2322#note_1034330
264        */
265       fflush (stdout);
266       fflush (stderr);
267
268       switch (fork ())
269         {
270         case -1:
271           errsv = errno;
272           g_warning ("fork() failed: %s", g_strerror (errsv));
273           g_assert_not_reached ();
274           break;
275
276         case 0:
277           /* child */
278           close (pipe_fds[1]);
279           watch_parent (pipe_fds[0]);
280           break;
281
282         default:
283           /* parent */
284           close (pipe_fds[0]);
285           channel = g_io_channel_unix_new (pipe_fds[1]);
286         }
287
288       g_once_init_leave (&started, 1);
289     }
290
291   return channel;
292 }
293
294 static void
295 watcher_send_command (const gchar *command)
296 {
297   GIOChannel *channel;
298   GError *error = NULL;
299   GIOStatus status;
300
301   channel = watcher_init ();
302
303   do
304    status = g_io_channel_write_chars (channel, command, -1, NULL, &error);
305   while (status == G_IO_STATUS_AGAIN);
306   g_assert_no_error (error);
307
308   g_io_channel_flush (channel, &error);
309   g_assert_no_error (error);
310 }
311
312 /* This could be interesting to expose in public API */
313 static void
314 _g_test_watcher_add_pid (GPid pid)
315 {
316   gchar *command;
317
318   command = g_strdup_printf (ADD_PID_FORMAT, (guint) pid);
319   watcher_send_command (command);
320   g_free (command);
321 }
322
323 static void
324 _g_test_watcher_remove_pid (GPid pid)
325 {
326   gchar *command;
327
328   command = g_strdup_printf (REMOVE_PID_FORMAT, (guint) pid);
329   watcher_send_command (command);
330   g_free (command);
331 }
332
333 #endif
334
335 /* -------------------------------------------------------------------------- */
336 /* GTestDBus object implementation */
337
338 /**
339  * SECTION:gtestdbus
340  * @short_description: D-Bus testing helper
341  * @include: gio/gio.h
342  *
343  * A helper class for testing code which uses D-Bus without touching the user's
344  * session bus.
345  *
346  * Note that #GTestDBus modifies the user’s environment, calling setenv().
347  * This is not thread-safe, so all #GTestDBus calls should be completed before
348  * threads are spawned, or should have appropriate locking to ensure no access
349  * conflicts to environment variables shared between #GTestDBus and other
350  * threads.
351  *
352  * ## Creating unit tests using GTestDBus
353  * 
354  * Testing of D-Bus services can be tricky because normally we only ever run
355  * D-Bus services over an existing instance of the D-Bus daemon thus we
356  * usually don't activate D-Bus services that are not yet installed into the
357  * target system. The #GTestDBus object makes this easier for us by taking care
358  * of the lower level tasks such as running a private D-Bus daemon and looking
359  * up uninstalled services in customizable locations, typically in your source
360  * code tree.
361  *
362  * The first thing you will need is a separate service description file for the
363  * D-Bus daemon. Typically a `services` subdirectory of your `tests` directory
364  * is a good place to put this file.
365  *
366  * The service file should list your service along with an absolute path to the
367  * uninstalled service executable in your source tree. Using autotools we would
368  * achieve this by adding a file such as `my-server.service.in` in the services
369  * directory and have it processed by configure.
370  * |[
371  *     [D-BUS Service]
372  *     Name=org.gtk.GDBus.Examples.ObjectManager
373  *     Exec=@abs_top_builddir@/gio/tests/gdbus-example-objectmanager-server
374  * ]|
375  * You will also need to indicate this service directory in your test
376  * fixtures, so you will need to pass the path while compiling your
377  * test cases. Typically this is done with autotools with an added
378  * preprocessor flag specified to compile your tests such as:
379  * |[
380  *     -DTEST_SERVICES=\""$(abs_top_builddir)/tests/services"\"
381  * ]|
382  *     Once you have a service definition file which is local to your source tree,
383  * you can proceed to set up a GTest fixture using the #GTestDBus scaffolding.
384  *
385  * An example of a test fixture for D-Bus services can be found
386  * here:
387  * [gdbus-test-fixture.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-test-fixture.c)
388  *
389  * Note that these examples only deal with isolating the D-Bus aspect of your
390  * service. To successfully run isolated unit tests on your service you may need
391  * some additional modifications to your test case fixture. For example; if your
392  * service uses GSettings and installs a schema then it is important that your test service
393  * not load the schema in the ordinary installed location (chances are that your service
394  * and schema files are not yet installed, or worse; there is an older version of the
395  * schema file sitting in the install location).
396  *
397  * Most of the time we can work around these obstacles using the
398  * environment. Since the environment is inherited by the D-Bus daemon
399  * created by #GTestDBus and then in turn inherited by any services the
400  * D-Bus daemon activates, using the setup routine for your fixture is
401  * a practical place to help sandbox your runtime environment. For the
402  * rather typical GSettings case we can work around this by setting
403  * `GSETTINGS_SCHEMA_DIR` to the in tree directory holding your schemas
404  * in the above fixture_setup() routine.
405  *
406  * The GSettings schemas need to be locally pre-compiled for this to work. This can be achieved
407  * by compiling the schemas locally as a step before running test cases, an autotools setup might
408  * do the following in the directory holding schemas:
409  * |[
410  *     all-am:
411  *             $(GLIB_COMPILE_SCHEMAS) .
412  *
413  *     CLEANFILES += gschemas.compiled
414  * ]|
415  */
416
417 typedef struct _GTestDBusClass   GTestDBusClass;
418 typedef struct _GTestDBusPrivate GTestDBusPrivate;
419
420 /**
421  * GTestDBus:
422  *
423  * The #GTestDBus structure contains only private data and
424  * should only be accessed using the provided API.
425  *
426  * Since: 2.34
427  */
428 struct _GTestDBus {
429   GObject parent;
430
431   GTestDBusPrivate *priv;
432 };
433
434 struct _GTestDBusClass {
435   GObjectClass parent_class;
436 };
437
438 struct _GTestDBusPrivate
439 {
440   GTestDBusFlags flags;
441   GPtrArray *service_dirs;
442   GPid bus_pid;
443   gchar *bus_address;
444   gboolean up;
445 };
446
447 enum
448 {
449   PROP_0,
450   PROP_FLAGS,
451 };
452
453 G_DEFINE_TYPE_WITH_PRIVATE (GTestDBus, g_test_dbus, G_TYPE_OBJECT)
454
455 static void
456 g_test_dbus_init (GTestDBus *self)
457 {
458   self->priv = g_test_dbus_get_instance_private (self);
459   self->priv->service_dirs = g_ptr_array_new_with_free_func (g_free);
460 }
461
462 static void
463 g_test_dbus_dispose (GObject *object)
464 {
465   GTestDBus *self = (GTestDBus *) object;
466
467   if (self->priv->up)
468     g_test_dbus_down (self);
469
470   G_OBJECT_CLASS (g_test_dbus_parent_class)->dispose (object);
471 }
472
473 static void
474 g_test_dbus_finalize (GObject *object)
475 {
476   GTestDBus *self = (GTestDBus *) object;
477
478   g_ptr_array_unref (self->priv->service_dirs);
479   g_free (self->priv->bus_address);
480
481   G_OBJECT_CLASS (g_test_dbus_parent_class)->finalize (object);
482 }
483
484 static void
485 g_test_dbus_get_property (GObject *object,
486     guint property_id,
487     GValue *value,
488     GParamSpec *pspec)
489 {
490   GTestDBus *self = (GTestDBus *) object;
491
492   switch (property_id)
493     {
494       case PROP_FLAGS:
495         g_value_set_flags (value, g_test_dbus_get_flags (self));
496         break;
497       default:
498         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
499         break;
500     }
501 }
502
503 static void
504 g_test_dbus_set_property (GObject *object,
505     guint property_id,
506     const GValue *value,
507     GParamSpec *pspec)
508 {
509   GTestDBus *self = (GTestDBus *) object;
510
511   switch (property_id)
512     {
513       case PROP_FLAGS:
514         self->priv->flags = g_value_get_flags (value);
515         break;
516       default:
517         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
518         break;
519     }
520 }
521
522 static void
523 g_test_dbus_class_init (GTestDBusClass *klass)
524 {
525   GObjectClass *object_class = G_OBJECT_CLASS (klass);
526
527   object_class->dispose = g_test_dbus_dispose;
528   object_class->finalize = g_test_dbus_finalize;
529   object_class->get_property = g_test_dbus_get_property;
530   object_class->set_property = g_test_dbus_set_property;
531
532   /**
533    * GTestDBus:flags:
534    *
535    * #GTestDBusFlags specifying the behaviour of the D-Bus session.
536    *
537    * Since: 2.34
538    */
539   g_object_class_install_property (object_class, PROP_FLAGS,
540     g_param_spec_flags ("flags",
541                         P_("D-Bus session flags"),
542                         P_("Flags specifying the behaviour of the D-Bus session"),
543                         G_TYPE_TEST_DBUS_FLAGS, G_TEST_DBUS_NONE,
544                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
545                         G_PARAM_STATIC_STRINGS));
546
547 }
548
549 static gchar *
550 write_config_file (GTestDBus *self)
551 {
552   GString *contents;
553   gint fd;
554   guint i;
555   GError *error = NULL;
556   gchar *path = NULL;
557
558   fd = g_file_open_tmp ("g-test-dbus-XXXXXX", &path, &error);
559   g_assert_no_error (error);
560
561   contents = g_string_new (NULL);
562   g_string_append (contents,
563       "<busconfig>\n"
564       "  <type>session</type>\n"
565 #ifdef G_OS_WIN32
566       "  <listen>nonce-tcp:</listen>\n"
567 #else
568       "  <listen>unix:tmpdir=/tmp</listen>\n"
569 #endif
570                    );
571
572   for (i = 0; i < self->priv->service_dirs->len; i++)
573     {
574       const gchar *dir_path = g_ptr_array_index (self->priv->service_dirs, i);
575
576       g_string_append_printf (contents,
577           "  <servicedir>%s</servicedir>\n", dir_path);
578     }
579
580   g_string_append (contents,
581       "  <policy context=\"default\">\n"
582       "    <!-- Allow everything to be sent -->\n"
583       "    <allow send_destination=\"*\" eavesdrop=\"true\"/>\n"
584       "    <!-- Allow everything to be received -->\n"
585       "    <allow eavesdrop=\"true\"/>\n"
586       "    <!-- Allow anyone to own anything -->\n"
587       "    <allow own=\"*\"/>\n"
588       "  </policy>\n"
589       "</busconfig>\n");
590
591   close (fd);
592   g_file_set_contents_full (path, contents->str, contents->len,
593                             G_FILE_SET_CONTENTS_NONE,
594                             0600, &error);
595   g_assert_no_error (error);
596
597   g_string_free (contents, TRUE);
598
599   return path;
600 }
601
602 static gboolean
603 make_pipe (gint     pipe_fds[2],
604            GError **error)
605 {
606 #if defined(G_OS_UNIX)
607   return g_unix_open_pipe (pipe_fds, O_CLOEXEC, error);
608 #elif defined(G_OS_WIN32)
609   if (_pipe (pipe_fds, 4096, _O_BINARY) < 0)
610     {
611       int errsv = errno;
612
613       g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
614                    _("Failed to create pipe for communicating with child process (%s)"),
615                    g_strerror (errsv));
616       return FALSE;
617     }
618   return TRUE;
619 #else
620   g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
621                _("Pipes are not supported in this platform"));
622   return FALSE;
623 #endif
624 }
625
626 static void
627 start_daemon (GTestDBus *self)
628 {
629   const gchar *argv[] = {"dbus-daemon", "--print-address", "--config-file=foo", NULL};
630   gint pipe_fds[2] = {-1, -1};
631   gchar *config_path;
632   gchar *config_arg;
633   gchar *print_address;
634   GIOChannel *channel;
635   gsize termpos;
636   GError *error = NULL;
637
638   if (g_getenv ("G_TEST_DBUS_DAEMON") != NULL)
639     argv[0] = (gchar *)g_getenv ("G_TEST_DBUS_DAEMON");
640
641   make_pipe (pipe_fds, &error);
642   g_assert_no_error (error);
643
644   print_address = g_strdup_printf ("--print-address=%d", pipe_fds[1]);
645   argv[1] = print_address;
646   g_assert_no_error (error);
647
648   /* Write config file and set its path in argv */
649   config_path = write_config_file (self);
650   config_arg = g_strdup_printf ("--config-file=%s", config_path);
651   argv[2] = config_arg;
652
653   /* Spawn dbus-daemon */
654   g_spawn_async_with_pipes_and_fds (NULL,
655                                     argv,
656                                     NULL,
657                                     /* We Need this to get the pid returned on win32 */
658                                     G_SPAWN_DO_NOT_REAP_CHILD |
659                                     G_SPAWN_SEARCH_PATH |
660                                     /* dbus-daemon will not abuse our descriptors, and
661                                      * passing this means we can use posix_spawn() for speed */
662                                     G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
663                                     NULL, NULL,
664                                     -1, -1, -1,
665                                     &pipe_fds[1], &pipe_fds[1], 1,
666                                     &self->priv->bus_pid,
667                                     NULL, NULL, NULL,
668                                     &error);
669   g_assert_no_error (error);
670
671   _g_test_watcher_add_pid (self->priv->bus_pid);
672
673   /* Read bus address from pipe */
674   channel = g_io_channel_unix_new (pipe_fds[0]);
675   pipe_fds[0] = -1;
676   g_io_channel_set_close_on_unref (channel, TRUE);
677   g_io_channel_read_line (channel, &self->priv->bus_address, NULL,
678       &termpos, &error);
679   g_assert_no_error (error);
680   self->priv->bus_address[termpos] = '\0';
681   close (pipe_fds[1]);
682   pipe_fds[1] = -1;
683
684   /* start dbus-monitor */
685   if (g_getenv ("G_DBUS_MONITOR") != NULL)
686     {
687       gchar *command;
688
689       command = g_strdup_printf ("dbus-monitor --address %s",
690           self->priv->bus_address);
691       g_spawn_command_line_async (command, NULL);
692       g_free (command);
693
694       g_usleep (500 * 1000);
695     }
696
697   /* Cleanup */
698   g_io_channel_shutdown (channel, FALSE, &error);
699   g_assert_no_error (error);
700   g_io_channel_unref (channel);
701
702   /* Don't use g_file_delete since it calls into gvfs */
703   if (g_unlink (config_path) != 0)
704     g_assert_not_reached ();
705
706   g_free (print_address);
707   g_free (config_path);
708   g_free (config_arg);
709 }
710
711 static void
712 stop_daemon (GTestDBus *self)
713 {
714 #ifdef G_OS_WIN32
715   if (!TerminateProcess (self->priv->bus_pid, 0))
716     g_warning ("Can't terminate process: %s", g_win32_error_message (GetLastError()));
717 #else
718   kill (self->priv->bus_pid, SIGTERM);
719 #endif
720   _g_test_watcher_remove_pid (self->priv->bus_pid);
721   g_spawn_close_pid (self->priv->bus_pid);
722   self->priv->bus_pid = 0;
723
724   g_free (self->priv->bus_address);
725   self->priv->bus_address = NULL;
726 }
727
728 /**
729  * g_test_dbus_new:
730  * @flags: a #GTestDBusFlags
731  *
732  * Create a new #GTestDBus object.
733  *
734  * Returns: (transfer full): a new #GTestDBus.
735  */
736 GTestDBus *
737 g_test_dbus_new (GTestDBusFlags flags)
738 {
739   return g_object_new (G_TYPE_TEST_DBUS,
740       "flags", flags,
741       NULL);
742 }
743
744 /**
745  * g_test_dbus_get_flags:
746  * @self: a #GTestDBus
747  *
748  * Get the flags of the #GTestDBus object.
749  *
750  * Returns: the value of #GTestDBus:flags property
751  */
752 GTestDBusFlags
753 g_test_dbus_get_flags (GTestDBus *self)
754 {
755   g_return_val_if_fail (G_IS_TEST_DBUS (self), G_TEST_DBUS_NONE);
756
757   return self->priv->flags;
758 }
759
760 /**
761  * g_test_dbus_get_bus_address:
762  * @self: a #GTestDBus
763  *
764  * Get the address on which dbus-daemon is running. If g_test_dbus_up() has not
765  * been called yet, %NULL is returned. This can be used with
766  * g_dbus_connection_new_for_address().
767  *
768  * Returns: (nullable): the address of the bus, or %NULL.
769  */
770 const gchar *
771 g_test_dbus_get_bus_address (GTestDBus *self)
772 {
773   g_return_val_if_fail (G_IS_TEST_DBUS (self), NULL);
774
775   return self->priv->bus_address;
776 }
777
778 /**
779  * g_test_dbus_add_service_dir:
780  * @self: a #GTestDBus
781  * @path: path to a directory containing .service files
782  *
783  * Add a path where dbus-daemon will look up .service files. This can't be
784  * called after g_test_dbus_up().
785  */
786 void
787 g_test_dbus_add_service_dir (GTestDBus *self,
788     const gchar *path)
789 {
790   g_return_if_fail (G_IS_TEST_DBUS (self));
791   g_return_if_fail (self->priv->bus_address == NULL);
792
793   g_ptr_array_add (self->priv->service_dirs, g_strdup (path));
794 }
795
796 /**
797  * g_test_dbus_up:
798  * @self: a #GTestDBus
799  *
800  * Start a dbus-daemon instance and set DBUS_SESSION_BUS_ADDRESS. After this
801  * call, it is safe for unit tests to start sending messages on the session bus.
802  *
803  * If this function is called from setup callback of g_test_add(),
804  * g_test_dbus_down() must be called in its teardown callback.
805  *
806  * If this function is called from unit test's main(), then g_test_dbus_down()
807  * must be called after g_test_run().
808  */
809 void
810 g_test_dbus_up (GTestDBus *self)
811 {
812   g_return_if_fail (G_IS_TEST_DBUS (self));
813   g_return_if_fail (self->priv->bus_address == NULL);
814   g_return_if_fail (!self->priv->up);
815
816   start_daemon (self);
817
818   g_test_dbus_unset ();
819   g_setenv ("DBUS_SESSION_BUS_ADDRESS", self->priv->bus_address, TRUE);
820   self->priv->up = TRUE;
821 }
822
823
824 /**
825  * g_test_dbus_stop:
826  * @self: a #GTestDBus
827  *
828  * Stop the session bus started by g_test_dbus_up().
829  *
830  * Unlike g_test_dbus_down(), this won't verify the #GDBusConnection
831  * singleton returned by g_bus_get() or g_bus_get_sync() is destroyed. Unit
832  * tests wanting to verify behaviour after the session bus has been stopped
833  * can use this function but should still call g_test_dbus_down() when done.
834  */
835 void
836 g_test_dbus_stop (GTestDBus *self)
837 {
838   g_return_if_fail (G_IS_TEST_DBUS (self));
839   g_return_if_fail (self->priv->bus_address != NULL);
840
841   stop_daemon (self);
842 }
843
844 /**
845  * g_test_dbus_down:
846  * @self: a #GTestDBus
847  *
848  * Stop the session bus started by g_test_dbus_up().
849  *
850  * This will wait for the singleton returned by g_bus_get() or g_bus_get_sync()
851  * to be destroyed. This is done to ensure that the next unit test won't get a
852  * leaked singleton from this test.
853  */
854 void
855 g_test_dbus_down (GTestDBus *self)
856 {
857   GDBusConnection *connection;
858
859   g_return_if_fail (G_IS_TEST_DBUS (self));
860   g_return_if_fail (self->priv->up);
861
862   connection = _g_bus_get_singleton_if_exists (G_BUS_TYPE_SESSION);
863   if (connection != NULL)
864     g_dbus_connection_set_exit_on_close (connection, FALSE);
865
866   if (self->priv->bus_address != NULL)
867     stop_daemon (self);
868
869   if (connection != NULL)
870     _g_object_unref_and_wait_weak_notify (connection);
871
872   g_test_dbus_unset ();
873   _g_bus_forget_singleton (G_BUS_TYPE_SESSION);
874   self->priv->up = FALSE;
875 }
876
877 /**
878  * g_test_dbus_unset:
879  *
880  * Unset DISPLAY and DBUS_SESSION_BUS_ADDRESS env variables to ensure the test
881  * won't use user's session bus.
882  *
883  * This is useful for unit tests that want to verify behaviour when no session
884  * bus is running. It is not necessary to call this if unit test already calls
885  * g_test_dbus_up() before acquiring the session bus.
886  */
887 void
888 g_test_dbus_unset (void)
889 {
890   g_unsetenv ("DISPLAY");
891   g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
892   g_unsetenv ("DBUS_STARTER_ADDRESS");
893   g_unsetenv ("DBUS_STARTER_BUS_TYPE");
894   /* avoid using XDG_RUNTIME_DIR/bus */
895   g_unsetenv ("XDG_RUNTIME_DIR");
896 }