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