dec92fa1f58d6e6568a7af381e8be0f316a49b38
[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  * 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 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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19  * Boston, MA 02111-1307, USA.
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 <unistd.h>
30
31 #include <glib.h>
32
33 #include "gdbusconnection.h"
34 #include "gdbusprivate.h"
35 #include "gfile.h"
36 #include "gioenumtypes.h"
37 #include "gtestdbus.h"
38
39 #include "glibintl.h"
40
41 /* -------------------------------------------------------------------------- */
42 /* Utility: Wait until object has a single ref  */
43
44 typedef struct
45 {
46   GMainLoop *loop;
47   gboolean   timed_out;
48 } WeakNotifyData;
49
50 static gboolean
51 on_weak_notify_timeout (gpointer user_data)
52 {
53   WeakNotifyData *data = user_data;
54   data->timed_out = TRUE;
55   g_main_loop_quit (data->loop);
56   return FALSE;
57 }
58
59 static gboolean
60 unref_on_idle (gpointer object)
61 {
62   g_object_unref (object);
63   return FALSE;
64 }
65
66 gboolean
67 _g_object_unref_and_wait_weak_notify (gpointer object)
68 {
69   WeakNotifyData data;
70   guint timeout_id;
71
72   data.loop = g_main_loop_new (NULL, FALSE);
73   data.timed_out = FALSE;
74
75   g_object_weak_ref (object, (GWeakNotify) g_main_loop_quit, data.loop);
76
77   /* Drop the ref in an idle callback, this is to make sure the mainloop
78    * is already running when weak notify happens */
79   g_idle_add (unref_on_idle, object);
80
81   /* Make sure we don't block forever */
82   timeout_id = g_timeout_add (30 * 1000, on_weak_notify_timeout, &data);
83
84   g_main_loop_run (data.loop);
85
86   g_source_remove (timeout_id);
87
88   if (data.timed_out)
89     {
90       g_warning ("Weak notify timeout, object ref_count=%d\n",
91           G_OBJECT (object)->ref_count);
92     }
93
94   return data.timed_out;
95 }
96
97 /* -------------------------------------------------------------------------- */
98 /* Utilities to cleanup the mess in the case unit test process crash */
99
100 #define ADD_PID_FORMAT "add pid %d\n"
101 #define REMOVE_PID_FORMAT "remove pid %d\n"
102
103 static void
104 watch_parent (gint fd)
105 {
106   GIOChannel *channel;
107   GPollFD fds[1];
108   GArray *pids_to_kill;
109
110   channel = g_io_channel_unix_new (fd);
111
112   fds[0].fd = fd;
113   fds[0].events = G_IO_HUP | G_IO_IN;
114   fds[0].revents = 0;
115
116   pids_to_kill = g_array_new (FALSE, FALSE, sizeof (guint));
117
118   do
119     {
120       gint num_events;
121       gchar *command = NULL;
122       guint pid;
123       guint n;
124       GError *error = NULL;
125
126       num_events = g_poll (fds, 1, -1);
127       if (num_events == 0)
128         continue;
129
130       if (fds[0].revents == G_IO_HUP)
131         {
132           /* Parent quit, cleanup the mess and exit */
133           for (n = 0; n < pids_to_kill->len; n++)
134             {
135               pid = g_array_index (pids_to_kill, guint, n);
136               g_print ("cleaning up pid %d\n", pid);
137               kill (pid, SIGTERM);
138             }
139
140           g_array_unref (pids_to_kill);
141           g_io_channel_shutdown (channel, FALSE, &error);
142           g_assert_no_error (error);
143           g_io_channel_unref (channel);
144
145           exit (0);
146         }
147
148       /* Read the command from the input */
149       g_io_channel_read_line (channel, &command, NULL, NULL, &error);
150       g_assert_no_error (error);
151
152       /* Check for known commands */
153       if (sscanf (command, ADD_PID_FORMAT, &pid) == 1)
154         {
155           g_array_append_val (pids_to_kill, pid);
156         }
157       else if (sscanf (command, REMOVE_PID_FORMAT, &pid) == 1)
158         {
159           for (n = 0; n < pids_to_kill->len; n++)
160             {
161               if (g_array_index (pids_to_kill, guint, n) == pid)
162                 {
163                   g_array_remove_index (pids_to_kill, n);
164                   pid = 0;
165                   break;
166                 }
167             }
168           if (pid != 0)
169             {
170               g_warning ("unknown pid %d to remove", pid);
171             }
172         }
173       else
174         {
175           g_warning ("unknown command from parent '%s'", command);
176         }
177
178       g_free (command);
179     }
180   while (TRUE);
181 }
182
183 static GIOChannel *
184 watcher_init (void)
185 {
186   static gsize started = 0;
187   static GIOChannel *channel = NULL;
188
189   if (g_once_init_enter (&started))
190     {
191       gint pipe_fds[2];
192
193       /* fork a child to clean up when we are killed */
194       if (pipe (pipe_fds) != 0)
195         {
196           g_warning ("pipe() failed: %m");
197           g_assert_not_reached ();
198         }
199
200       switch (fork ())
201         {
202         case -1:
203           g_warning ("fork() failed: %m");
204           g_assert_not_reached ();
205           break;
206
207         case 0:
208           /* child */
209           close (pipe_fds[1]);
210           watch_parent (pipe_fds[0]);
211           break;
212
213         default:
214           /* parent */
215           close (pipe_fds[0]);
216           channel = g_io_channel_unix_new (pipe_fds[1]);
217         }
218
219       g_once_init_leave (&started, 1);
220     }
221
222   return channel;
223 }
224
225 static void
226 watcher_send_command (const gchar *command)
227 {
228   GIOChannel *channel;
229   GError *error = NULL;
230
231   channel = watcher_init ();
232
233   g_io_channel_write_chars (channel, command, -1, NULL, &error);
234   g_assert_no_error (error);
235
236   g_io_channel_flush (channel, &error);
237   g_assert_no_error (error);
238 }
239
240 /* This could be interesting to expose in public API */
241 static void
242 _g_test_watcher_add_pid (GPid pid)
243 {
244   gchar *command;
245
246   command = g_strdup_printf (ADD_PID_FORMAT, (guint) pid);
247   watcher_send_command (command);
248   g_free (command);
249 }
250
251 static void
252 _g_test_watcher_remove_pid (GPid pid)
253 {
254   gchar *command;
255
256   command = g_strdup_printf (REMOVE_PID_FORMAT, (guint) pid);
257   watcher_send_command (command);
258   g_free (command);
259 }
260
261 /* -------------------------------------------------------------------------- */
262 /* GTestDBus object implementation */
263
264 /**
265  * SECTION:gtestdbus
266  * @short_description: D-Bus testing helper
267  * @include: gio/gio.h
268  *
269  * Helper to test D-Bus code wihtout messing up with user' session bus.
270  */
271
272 typedef struct _GTestDBusClass   GTestDBusClass;
273 typedef struct _GTestDBusPrivate GTestDBusPrivate;
274
275 /**
276  * GTestDBus:
277  *
278  * The #GTestDBus structure contains only private data and
279  * should only be accessed using the provided API.
280  *
281  * Since: 2.34
282  */
283 struct _GTestDBus {
284   GObject parent;
285
286   GTestDBusPrivate *priv;
287 };
288
289 struct _GTestDBusClass {
290   GObjectClass parent_class;
291 };
292
293 struct _GTestDBusPrivate
294 {
295   GTestDBusFlags flags;
296   GPtrArray *service_dirs;
297   GPid bus_pid;
298   gchar *bus_address;
299   gboolean up;
300 };
301
302 enum
303 {
304   PROP_0,
305   PROP_FLAGS,
306 };
307
308 G_DEFINE_TYPE (GTestDBus, g_test_dbus, G_TYPE_OBJECT)
309
310 static void
311 g_test_dbus_init (GTestDBus *self)
312 {
313   self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), G_TYPE_TEST_DBUS,
314       GTestDBusPrivate);
315
316   self->priv->service_dirs = g_ptr_array_new_with_free_func (g_free);
317 }
318
319 static void
320 g_test_dbus_dispose (GObject *object)
321 {
322   GTestDBus *self = (GTestDBus *) object;
323
324   if (self->priv->up)
325     g_test_dbus_down (self);
326
327   G_OBJECT_CLASS (g_test_dbus_parent_class)->dispose (object);
328 }
329
330 static void
331 g_test_dbus_finalize (GObject *object)
332 {
333   GTestDBus *self = (GTestDBus *) object;
334
335   g_ptr_array_unref (self->priv->service_dirs);
336   g_free (self->priv->bus_address);
337
338   G_OBJECT_CLASS (g_test_dbus_parent_class)->finalize (object);
339 }
340
341 static void
342 g_test_dbus_get_property (GObject *object,
343     guint property_id,
344     GValue *value,
345     GParamSpec *pspec)
346 {
347   GTestDBus *self = (GTestDBus *) object;
348
349   switch (property_id)
350     {
351       case PROP_FLAGS:
352         g_value_set_flags (value, g_test_dbus_get_flags (self));
353         break;
354       default:
355         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
356         break;
357     }
358 }
359
360 static void
361 g_test_dbus_set_property (GObject *object,
362     guint property_id,
363     const GValue *value,
364     GParamSpec *pspec)
365 {
366   GTestDBus *self = (GTestDBus *) object;
367
368   switch (property_id)
369     {
370       case PROP_FLAGS:
371         self->priv->flags = g_value_get_flags (value);
372         break;
373       default:
374         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
375         break;
376     }
377 }
378
379 static void
380 g_test_dbus_class_init (GTestDBusClass *klass)
381 {
382   GObjectClass *object_class = G_OBJECT_CLASS (klass);
383
384   object_class->dispose = g_test_dbus_dispose;
385   object_class->finalize = g_test_dbus_finalize;
386   object_class->get_property = g_test_dbus_get_property;
387   object_class->set_property = g_test_dbus_set_property;
388
389   g_type_class_add_private (object_class, sizeof (GTestDBusPrivate));
390
391   /**
392    * GTestDBus:flags:
393    *
394    * #GTestDBusFlags specifying the behaviour of the dbus session
395    *
396    * Since: 2.34
397    */
398   g_object_class_install_property (object_class, PROP_FLAGS,
399     g_param_spec_flags ("flags",
400                         P_("dbus session flags"),
401                         P_("Flags specifying the behaviour of the dbus session"),
402                         G_TYPE_TEST_DBUS_FLAGS, G_TEST_DBUS_NONE,
403                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
404                         G_PARAM_STATIC_STRINGS));
405
406 }
407
408 static GFile *
409 write_config_file (GTestDBus *self)
410 {
411   GString *contents;
412   GFile *file;
413   GFileIOStream *iostream;
414   guint i;
415   GError *error = NULL;
416
417   file = g_file_new_tmp ("g-test-dbus-XXXXXX", &iostream, &error);
418   g_assert_no_error (error);
419   g_object_unref (iostream);
420
421   contents = g_string_new (NULL);
422   g_string_append (contents,
423       "<busconfig>\n"
424       "  <type>session</type>\n"
425       "  <listen>unix:tmpdir=/tmp</listen>\n");
426
427   for (i = 0; i < self->priv->service_dirs->len; i++)
428     {
429       const gchar *path = g_ptr_array_index (self->priv->service_dirs, i);
430
431       g_string_append_printf (contents,
432           "  <servicedir>%s</servicedir>\n", path);
433     }
434
435   g_string_append (contents,
436       "  <policy context=\"default\">\n"
437       "    <!-- Allow everything to be sent -->\n"
438       "    <allow send_destination=\"*\" eavesdrop=\"true\"/>\n"
439       "    <!-- Allow everything to be received -->\n"
440       "    <allow eavesdrop=\"true\"/>\n"
441       "    <!-- Allow anyone to own anything -->\n"
442       "    <allow own=\"*\"/>\n"
443       "  </policy>\n"
444       "</busconfig>\n");
445
446   g_file_replace_contents (file, contents->str, contents->len,
447       NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &error);
448   g_assert_no_error (error);
449
450   g_string_free (contents, TRUE);
451
452   return file;
453 }
454
455 static void
456 start_daemon (GTestDBus *self)
457 {
458   gchar *argv[] = {"dbus-daemon", "--print-address", "--config-file=foo", NULL};
459   GFile *file;
460   gchar *config_path;
461   gchar *config_arg;
462   gint stdout_fd;
463   GIOChannel *channel;
464   gsize termpos;
465   GError *error = NULL;
466
467   /* Write config file and set its path in argv */
468   file = write_config_file (self);
469   config_path = g_file_get_path (file);
470   config_arg = g_strdup_printf ("--config-file=%s", config_path);
471   argv[2] = config_arg;
472
473   /* Spawn dbus-daemon */
474   g_spawn_async_with_pipes (NULL,
475                             argv,
476                             NULL,
477                             G_SPAWN_SEARCH_PATH,
478                             NULL,
479                             NULL,
480                             &self->priv->bus_pid,
481                             NULL,
482                             &stdout_fd,
483                             NULL,
484                             &error);
485   g_assert_no_error (error);
486
487   _g_test_watcher_add_pid (self->priv->bus_pid);
488
489   /* Read bus address from daemon' stdout */
490   channel = g_io_channel_unix_new (stdout_fd);
491   g_io_channel_read_line (channel, &self->priv->bus_address, NULL,
492       &termpos, &error);
493   g_assert_no_error (error);
494   self->priv->bus_address[termpos] = '\0';
495
496   /* start dbus-monitor */
497   if (g_getenv ("G_DBUS_MONITOR") != NULL)
498     {
499       gchar *command;
500
501       command = g_strdup_printf ("dbus-monitor --address %s",
502           self->priv->bus_address);
503       g_spawn_command_line_async (command, NULL);
504       g_free (command);
505
506       usleep (500 * 1000);
507     }
508
509   /* Cleanup */
510   g_io_channel_shutdown (channel, FALSE, &error);
511   g_assert_no_error (error);
512   g_io_channel_unref (channel);
513
514   g_file_delete (file, NULL, &error);
515   g_assert_no_error (error);
516   g_object_unref (file);
517
518   g_free (config_path);
519   g_free (config_arg);
520 }
521
522 static void
523 stop_daemon (GTestDBus *self)
524 {
525   kill (self->priv->bus_pid, SIGTERM);
526   _g_test_watcher_remove_pid (self->priv->bus_pid);
527   self->priv->bus_pid = 0;
528
529   g_free (self->priv->bus_address);
530   self->priv->bus_address = NULL;
531 }
532
533 /**
534  * g_test_dbus_new:
535  * @flags: a #GTestDBusFlags
536  *
537  * Create a new #GTestDBus object.
538  *
539  * Returns: (transfer full): a new #GTestDBus.
540  */
541 GTestDBus *
542 g_test_dbus_new (GTestDBusFlags flags)
543 {
544   return g_object_new (G_TYPE_TEST_DBUS,
545       "flags", flags,
546       NULL);
547 }
548
549 /**
550  * g_test_dbus_get_flags:
551  * @self: a #GTestDBus
552  *
553  * Returns: the value of #GTestDBus:flags property
554  */
555 GTestDBusFlags
556 g_test_dbus_get_flags (GTestDBus *self)
557 {
558   g_return_val_if_fail (G_IS_TEST_DBUS (self), G_TEST_DBUS_NONE);
559
560   return self->priv->flags;
561 }
562
563 /**
564  * g_test_dbus_get_bus_address:
565  * @self: a #GTestDBus
566  *
567  * Get the address on which dbus-daemon is running. if g_test_dbus_up() has not
568  * been called yet, %NULL is returned. This can be used with
569  * g_dbus_connection_new_for_address()
570  *
571  * Returns: the address of the bus, or %NULL.
572  */
573 const gchar *
574 g_test_dbus_get_bus_address (GTestDBus *self)
575 {
576   g_return_val_if_fail (G_IS_TEST_DBUS (self), NULL);
577
578   return self->priv->bus_address;
579 }
580
581 /**
582  * g_test_dbus_add_service_dir:
583  * @self: a #GTestDBus
584  * @path: path to a directory containing .service files
585  *
586  * Add a path where dbus-daemon will lookup for .services files. This can't be
587  * called after g_test_dbus_up().
588  */
589 void
590 g_test_dbus_add_service_dir (GTestDBus *self,
591     const gchar *path)
592 {
593   g_return_if_fail (G_IS_TEST_DBUS (self));
594   g_return_if_fail (self->priv->bus_address == NULL);
595
596   g_ptr_array_add (self->priv->service_dirs, g_strdup (path));
597 }
598
599 /**
600  * g_test_dbus_up:
601  * @self: a #GTestDBus
602  *
603  * Start a dbus-daemon instance and set DBUS_SESSION_BUS_ADDRESS. After this
604  * call, it is safe for unit tests to start sending messages on the session bug.
605  *
606  * If this function is called from setup callback of g_test_add(),
607  * g_test_dbus_down() must be called in its teardown callback.
608  *
609  * If this function is called from unit test's main(), then g_test_dbus_down()
610  * must be called after g_test_run().
611  */
612 void
613 g_test_dbus_up (GTestDBus *self)
614 {
615   g_return_if_fail (G_IS_TEST_DBUS (self));
616   g_return_if_fail (self->priv->bus_address == NULL);
617   g_return_if_fail (!self->priv->up);
618
619   start_daemon (self);
620
621   g_setenv ("DBUS_SESSION_BUS_ADDRESS", self->priv->bus_address, TRUE);
622   self->priv->up = TRUE;
623 }
624
625
626 /**
627  * g_test_dbus_stop:
628  * @self: a #GTestDBus
629  *
630  * Stop the session bus started by g_test_dbus_up().
631  *
632  * Unlike g_test_dbus_down(), this won't verify the #GDBusConnection
633  * singleton returned by g_bus_get() or g_bus_get_sync() is destroyed. Unit
634  * tests wanting to verify behaviour after the session bus has been stopped
635  * can use this function but should still call g_test_dbus_down() when done.
636  */
637 void
638 g_test_dbus_stop (GTestDBus *self)
639 {
640   g_return_if_fail (G_IS_TEST_DBUS (self));
641   g_return_if_fail (self->priv->bus_address != NULL);
642
643   stop_daemon (self);
644 }
645
646 /**
647  * g_test_dbus_down:
648  * @self: a #GTestDBus
649  *
650  * Stop the session bus started by g_test_dbus_up().
651  *
652  * This will wait for the singleton returned by g_bus_get() or g_bus_get_sync()
653  * is destroyed. This is done to ensure that the next unit test won't get a
654  * leaked singleton from this test.
655  */
656 void
657 g_test_dbus_down (GTestDBus *self)
658 {
659   GDBusConnection *connection;
660
661   g_return_if_fail (G_IS_TEST_DBUS (self));
662   g_return_if_fail (self->priv->up);
663
664   connection = _g_bus_get_singleton_if_exists (G_BUS_TYPE_SESSION);
665   if (connection != NULL)
666     g_dbus_connection_set_exit_on_close (connection, FALSE);
667
668   if (self->priv->bus_address != NULL)
669     stop_daemon (self);
670
671   if (connection != NULL)
672     _g_object_unref_and_wait_weak_notify (connection);
673
674   g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
675   self->priv->up = FALSE;
676 }
677
678 /**
679  * g_test_dbus_unset:
680  *
681  * Unset DISPLAY and DBUS_SESSION_BUS_ADDRESS env variables to ensure the test
682  * won't use user's session bus.
683  *
684  * This is useful for unit tests that want to verify behaviour when no session
685  * bus is running. It is not necessary to call this if unit test already calls
686  * g_test_dbus_up() before acquiring the session bus.
687  */
688 void
689 g_test_dbus_unset (void)
690 {
691   g_unsetenv ("DISPLAY");
692   g_unsetenv ("DBUS_SESSION_BUS_ADDRESS");
693 }