Added examples to GTestDBus documentation
authorTristan Van Berkom <tristan.van.berkom@gmail.com>
Wed, 16 Jan 2013 07:26:08 +0000 (16:26 +0900)
committerTristan Van Berkom <tristan.van.berkom@gmail.com>
Thu, 21 Mar 2013 07:37:21 +0000 (16:37 +0900)
docs/reference/gio/migrating-gdbus.xml
gio/gtestdbus.c
gio/tests/gdbus-test-fixture.c

index 4f51679..423ad16 100644 (file)
           linkend="gio-D-Bus-Introspection-Data">Introspection
           XML</link>, dbus-glib doesn't.
         </para></listitem>
+        <listitem><para>
+          GTestDBus provides API to create isolated unit tests <link
+          linkend="gio-D-Bus-Test-Scaffolding">GDBus Test Scaffolding</link>.
+        </para></listitem>
       </itemizedlist>
     </para>
   </section>
index 2315451..3ca064c 100644 (file)
@@ -318,6 +318,81 @@ _g_test_watcher_remove_pid (GPid pid)
  *
  * A helper class for testing code which uses D-Bus without touching the user's
  * session bus.
+ *
+ * <refsect2 id="gio-D-Bus-Test-Scaffolding">
+ *   <title>Creating unit tests using GTestDBus</title>
+ *   <para>
+ *     Testing of D-Bus services can be tricky because normally we only ever run
+ *     D-Bus services over an existing instance of the D-Bus daemon thus we
+ *     usually don't activate D-Bus services that are not yet installed into the
+ *     target system. The #GTestDBus object makes this easier for us by taking care
+ *     of the lower level tasks such as running a private D-Bus daemon and looking
+ *     up uninstalled services in customizable locations, typically in your source code tree.
+ *   </para>
+ *   <para>
+ *     The first thing you will need is a separate service description file for the
+ *     D-Bus daemon. Typically a 'services' subdirectory of your 'tests' directory
+ *     is a good place to put this file.
+ *   </para>
+ *   <para>
+ *     The service file should list your service along with an absolute path to the
+ *     uninstalled service executable in your source tree. Using autotools we would
+ *     achieve this by adding a file such as 'my-server.service.in' in the services
+ *     directory and have it processed by configure.
+ *     <informalexample><programlisting>
+ *     [D-BUS Service]
+ *     Name=org.gtk.GDBus.Examples.ObjectManager
+ *     Exec=@abs_top_builddir@/gio/tests/gdbus-example-objectmanager-server
+ *     </programlisting></informalexample>
+ *     You will also need to indicate this service directory in your test
+ *     fixtures, so you will need to pass the path while compiling your
+ *     test cases. Typically this is done with autotools with an added
+ *     preprocessor flag specified to compile your tests such as:
+ *     <informalexample><programlisting>
+ *     -DTEST_SERVICES=\""$(abs_top_builddir)/tests/services"\"
+ *     </programlisting></informalexample>
+ *   </para>
+ *   <para>
+ *     Once you have a service definition file which is local to your source tree,
+ *     you can proceed to setup a GTest fixture using the GTestDBus scaffolding.
+ *     <example id="gdbus-test-fixture">
+ *       <title>Test Fixture for D-Bus services</title>
+ *       <programlisting>
+ *         <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-test-fixture.c">
+ *           <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
+ *         </xi:include>
+ *       </programlisting>
+ *     </example>
+ *   </para>
+ *   <para>
+ *     Note that these examples only deal with isolating the D-Bus aspect of your
+ *     service. To successfully run isolated unit tests on your service you may need
+ *     some additional modifications to your test case fixture. For example; if your
+ *     service uses GSettings and installs a schema then it is important that your test service
+ *     not load the schema in the ordinary installed location (chances are that your service
+ *     and schema files are not yet installed, or worse; there is an older version of the
+ *     schema file sitting in the install location).
+ *   </para>
+ *   <para>
+ *     Most of the time we can work around these obstacles using the environment. Since the
+ *     environment is inherited by the D-Bus daemon created by GTestDBus and then in turn
+ *     inherited by any services the D-Bus daemon activates, using the setup routine for your
+ *     fixture is a practical place to help sandbox your runtime environment. For the rather
+ *     typical GSettings case we can work around this by setting GSETTINGS_SCHEMA_DIR to the
+ *     in tree directory holding your schemas in the above fixture_setup() routine.
+ *   </para>
+ *   <para>
+ *     The GSettings schemas need to be locally pre-compiled for this to work. This can be achieved
+ *     by compiling the schemas locally as a step before running test cases, an autotools setup might
+ *     do the following in the directory holding schemas:
+ *     <informalexample><programlisting>
+ *     all-am:
+ *             $(GLIB_COMPILE_SCHEMAS) .
+ *
+ *     CLEANFILES += gschemas.compiled
+ *     </programlisting></informalexample>
+ *   </para>
+ * </refsect2>
  */
 
 typedef struct _GTestDBusClass   GTestDBusClass;
index ef1f6c5..a4403dd 100644 (file)
@@ -1,26 +1,11 @@
-/* gdbus-test-fixture.c - Test covering activation of in-tree servers.
- *
- * Copyright (C) 2012 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
- *
- * Authors: Tristan Van Berkom <tristanvb@openismus.com>
- */
 
-#include <gio/gio.h>
 #include "gdbus-example-objectmanager-generated.h"
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* The fixture contains a GTestDBus object and
+ * a proxy to the service we're going to be testing.
+ */
 typedef struct {
   GTestDBus *dbus;
   GDBusObjectManager *manager;
@@ -29,25 +14,46 @@ typedef struct {
 static void
 fixture_setup (TestFixture *fixture, gconstpointer unused)
 {
-  /* Create the global dbus-daemon for this test suite */
+  GError *error = NULL;
+
+  /* Create the global dbus-daemon for this test suite
+   */
   fixture->dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
 
-  /* Add the private directory with our in-tree service files */
+  /* Add the private directory with our in-tree service files, 
+   * TEST_SERVICES is defined by the build system to point
+   * to the right directory.
+   */
   g_test_dbus_add_service_dir (fixture->dbus, TEST_SERVICES);
 
-  /* Start the private D-Bus daemon */
+  /* Start the private D-Bus daemon
+   */
   g_test_dbus_up (fixture->dbus);
+
+  /* Create the proxy that we're going to test
+   */
+  fixture->manager =
+    example_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                                    G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+                                                    "org.gtk.GDBus.Examples.ObjectManager",
+                                                    "/example/Animals",
+                                                    NULL, /* GCancellable */
+                                                    &error);
+  if (fixture->manager == NULL)
+    g_error ("Error getting object manager client: %s", error->message);
 }
 
 static void
 fixture_teardown (TestFixture *fixture, gconstpointer unused)
 {
+  /* Tear down the proxy
+   */
   if (fixture->manager)
     g_object_unref (fixture->manager);
 
-  /* Stop the private D-Bus daemon */
+  /* Stop the private D-Bus daemon
+   */
   g_test_dbus_down (fixture->dbus);
-
   g_object_unref (fixture->dbus);
 }
 
@@ -56,46 +62,24 @@ fixture_teardown (TestFixture *fixture, gconstpointer unused)
  * that 10 objects exist.
  */
 static void
-assert_ten_objects (GDBusObjectManager *manager)
+test_gtest_dbus (TestFixture *fixture, gconstpointer unused)
 {
   GList *objects;
 
-  objects = g_dbus_object_manager_get_objects (manager);
+  objects = g_dbus_object_manager_get_objects (fixture->manager);
 
   g_assert_cmpint (g_list_length (objects), ==, 10);
   g_list_free_full (objects, g_object_unref);
 }
 
-static void
-test_gtest_dbus (TestFixture *fixture, gconstpointer unused)
-{
-
-  GError *error = NULL;
-
-  fixture->manager =
-    example_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SESSION,
-                                                    G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
-                                                    "org.gtk.GDBus.Examples.ObjectManager",
-                                                    "/example/Animals",
-                                                    NULL, /* GCancellable */
-                                                    &error);
-  if (fixture->manager == NULL)
-    g_error ("Error getting object manager client: %s", error->message);
-
-  assert_ten_objects (fixture->manager);
-}
-
 int
 main (int   argc,
       char *argv[])
 {
-#if !GLIB_CHECK_VERSION (2, 35, 1)
-  g_type_init ();
-#endif
   g_test_init (&argc, &argv, NULL);
 
-  /* Ensure that we can bring the GTestDBus up and down a hand full of times
-   * in a row, each time successfully activating the in-tree service
+  /* This test simply ensures that we can bring the GTestDBus up and down a hand
+   * full of times in a row, each time successfully activating the in-tree service
    */
   g_test_add ("/GTestDBus/Cycle1", TestFixture, NULL,
              fixture_setup, test_gtest_dbus, fixture_teardown);