summaryrefslogtreecommitdiff
path: root/tests/dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/dbus.c')
-rw-r--r--tests/dbus.c519
1 files changed, 519 insertions, 0 deletions
diff --git a/tests/dbus.c b/tests/dbus.c
new file mode 100644
index 0000000..980d2b0
--- /dev/null
+++ b/tests/dbus.c
@@ -0,0 +1,519 @@
+#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_36 /* Suppress deprecation warnings */
+
+#include <string.h>
+#include <glib.h>
+#include <stdlib.h>
+
+/* Test the DBus communicaton code.
+ */
+
+#include "../engine/dconf-engine.h"
+
+static gboolean okay_in_main;
+static GThread *main_thread;
+static GThread *dbus_thread;
+static GQueue async_call_success_queue;
+static GQueue async_call_error_queue;
+static GMutex async_call_queue_lock;
+static gboolean signal_was_received;
+
+static void
+wait_for_queue_to_empty (GQueue *queue)
+{
+ okay_in_main = TRUE;
+
+ while (TRUE)
+ {
+ gboolean is_empty;
+
+ g_mutex_lock (&async_call_queue_lock);
+ is_empty = g_queue_is_empty (queue);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ if (is_empty)
+ return;
+
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ okay_in_main = FALSE;
+}
+
+static gboolean
+just_wake (gpointer user_data)
+{
+ return G_SOURCE_REMOVE;
+}
+
+static void
+signal_if_queue_is_empty (GQueue *queue)
+{
+ gboolean is_empty;
+
+ g_mutex_lock (&async_call_queue_lock);
+ is_empty = g_queue_is_empty (queue);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ if (is_empty)
+ g_idle_add (just_wake, NULL);
+}
+
+const GVariantType *
+dconf_engine_call_handle_get_expected_type (DConfEngineCallHandle *handle)
+{
+ return (GVariantType *) handle;
+}
+
+void
+dconf_engine_call_handle_reply (DConfEngineCallHandle *handle,
+ GVariant *parameters,
+ const GError *error)
+{
+ DConfEngineCallHandle *expected_handle;
+
+ /* Ensure that messages are never delivered in the main thread except
+ * by way of a mainloop (ie: not during sync calls).
+ *
+ * It's okay if they are delivered in another thread at the same time
+ * as a sync call is happening in the main thread, though...
+ */
+ g_assert (g_thread_self () != main_thread || okay_in_main);
+
+ /* Make sure that we only ever receive D-Bus calls from a single
+ * thread.
+ */
+ if (!dbus_thread)
+ dbus_thread = g_thread_self ();
+ g_assert (g_thread_self () == dbus_thread);
+
+ /* This is the passing case. */
+ if (parameters != NULL)
+ {
+ g_mutex_lock (&async_call_queue_lock);
+ g_assert (g_queue_is_empty (&async_call_error_queue));
+ expected_handle = g_queue_pop_head (&async_call_success_queue);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ g_assert (parameters != NULL);
+ g_assert (error == NULL);
+ g_assert (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")));
+
+ g_assert (expected_handle == handle);
+ g_variant_type_free ((GVariantType *) handle);
+
+ signal_if_queue_is_empty (&async_call_success_queue);
+ }
+ else
+ {
+ g_mutex_lock (&async_call_queue_lock);
+ g_assert (g_queue_is_empty (&async_call_success_queue));
+ expected_handle = g_queue_pop_head (&async_call_error_queue);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ g_assert (parameters == NULL);
+ g_assert (error != NULL);
+
+ g_assert (expected_handle == handle);
+ g_variant_type_free ((GVariantType *) handle);
+
+ signal_if_queue_is_empty (&async_call_error_queue);
+ }
+}
+
+void
+dconf_engine_handle_dbus_signal (GBusType bus_type,
+ const gchar *bus_name,
+ const gchar *object_path,
+ const gchar *signal_name,
+ GVariant *parameters)
+{
+ g_assert (g_thread_self () != main_thread || okay_in_main);
+
+ if (!dbus_thread)
+ dbus_thread = g_thread_self ();
+ g_assert (g_thread_self () == dbus_thread);
+
+ if (g_str_equal (signal_name, "TestSignal"))
+ {
+ GVariant *expected;
+
+ expected = g_variant_parse (NULL, "('1', ['2', '3'])", NULL, NULL, NULL);
+ g_assert (g_variant_equal (parameters, expected));
+ g_variant_unref (expected);
+
+ signal_was_received = TRUE;
+ g_idle_add (just_wake, NULL);
+ }
+}
+
+static void
+test_creation_error (void)
+{
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ /* Sync with 'error' */
+ if (g_test_trap_fork (0, 0))
+ {
+ GError *error = NULL;
+ GVariant *reply;
+
+ g_setenv ("DBUS_SESSION_BUS_ADDRESS", "some nonsense", 1);
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(as)"), &error);
+
+ g_assert (reply == NULL);
+ g_assert (error != NULL);
+ g_assert (strstr (error->message, "some nonsense"));
+ exit (0);
+ }
+
+ g_test_trap_assert_passed ();
+
+ /* Sync without 'error' */
+ if (g_test_trap_fork (0, 0))
+ {
+ GVariant *reply;
+
+ g_setenv ("DBUS_SESSION_BUS_ADDRESS", "some nonsense", 1);
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(as)"), NULL);
+
+ g_assert (reply == NULL);
+ exit (0);
+ }
+
+ g_test_trap_assert_passed ();
+
+ /* Async */
+ if (g_test_trap_fork (0, 0))
+ {
+ DConfEngineCallHandle *handle;
+ GError *error = NULL;
+ gboolean success;
+
+ g_setenv ("DBUS_SESSION_BUS_ADDRESS", "some nonsense", 1);
+
+ handle = (gpointer) g_variant_type_new ("(s)");
+ g_mutex_lock (&async_call_queue_lock);
+ g_queue_push_tail (&async_call_error_queue, handle);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ success = dconf_engine_dbus_call_async_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), handle, &error);
+
+ /* This could either fail immediately or asynchronously, depending
+ * on how the backend is setup.
+ */
+ if (success)
+ {
+ g_assert_no_error (error);
+
+ wait_for_queue_to_empty (&async_call_error_queue);
+ }
+ else
+ g_assert (error != NULL);
+
+ exit (0);
+ }
+
+ g_test_trap_assert_passed ();
+}
+
+static void
+test_sync_call_success (void)
+{
+ GError *error = NULL;
+ gchar *session_id;
+ gchar *system_id;
+ GVariant *reply;
+
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(as)"), &error);
+
+ g_assert_no_error (error);
+ g_assert (reply != NULL);
+ g_assert (g_variant_is_of_type (reply, G_VARIANT_TYPE ("(as)")));
+ g_variant_unref (reply);
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(s)"), &error);
+
+ g_assert_no_error (error);
+ g_assert (reply != NULL);
+ g_assert (g_variant_is_of_type (reply, G_VARIANT_TYPE ("(s)")));
+ g_variant_get (reply, "(s)", &session_id);
+ g_variant_unref (reply);
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SYSTEM,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(s)"), &error);
+
+ g_assert_no_error (error);
+ g_assert (reply != NULL);
+ g_assert (g_variant_is_of_type (reply, G_VARIANT_TYPE ("(s)")));
+ g_variant_get (reply, "(s)", &system_id);
+ g_variant_unref (reply);
+
+ /* Make sure we actually saw two separate buses */
+ g_assert_cmpstr (session_id, !=, system_id);
+ g_free (session_id);
+ g_free (system_id);
+}
+
+static void
+test_sync_call_error (void)
+{
+ GError *error = NULL;
+ GVariant *reply;
+
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ /* Test receiving errors from the other side */
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("(s)", ""), G_VARIANT_TYPE_UNIT, &error);
+ g_assert (reply == NULL);
+ g_assert (error != NULL);
+ g_assert (strstr (error->message, "org.freedesktop.DBus.Error.InvalidArgs"));
+ g_clear_error (&error);
+
+ /* Test with 'ay' to make sure transmitting that works as well */
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("(ay)", NULL), G_VARIANT_TYPE_UNIT, &error);
+ g_assert (reply == NULL);
+ g_assert (error != NULL);
+ g_assert (strstr (error->message, "org.freedesktop.DBus.Error.InvalidArgs"));
+ g_clear_error (&error);
+
+ /* Test reply type errors */
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(u)"), &error);
+ g_assert (reply == NULL);
+ g_assert (error != NULL);
+ g_assert (strstr (error->message, " type "));
+ g_clear_error (&error);
+
+ /* Test two oddities:
+ *
+ * - first, the dbus-1 backend can't handle return types other than
+ * 's' and 'as', so we do a method call that will get something
+ * else in order that we can check that the failure is treated
+ * properly
+ *
+ * - next, we want to make sure that the filter function for
+ * gdbus-filter doesn't block incoming method calls
+ */
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "RequestName",
+ g_variant_new_parsed ("('ca.desrt.dconf.testsuite', uint32 0)"),
+ G_VARIANT_TYPE ("(u)"), &error);
+ if (reply != NULL)
+ {
+ guint s;
+
+ /* It worked, so we must be on gdbus... */
+ g_assert_no_error (error);
+
+ g_variant_get (reply, "(u)", &s);
+ g_assert_cmpuint (s, ==, 1);
+ g_variant_unref (reply);
+
+ /* Ping ourselves... */
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "ca.desrt.dconf.testsuite", "/", "org.freedesktop.DBus.Peer",
+ "Ping", g_variant_new ("()"), G_VARIANT_TYPE_UNIT, &error);
+ g_assert (reply != NULL);
+ g_assert_no_error (error);
+ g_variant_unref (reply);
+ }
+ else
+ {
+ /* Else, we're on dbus1...
+ *
+ * Check that the error was emitted correctly.
+ */
+ g_assert_cmpstr (error->message, ==, "unable to handle message type '(u)'");
+ g_clear_error (&error);
+ }
+}
+
+static void
+test_async_call_success (void)
+{
+ gint i;
+
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ for (i = 0; i < 1000; i++)
+ {
+ DConfEngineCallHandle *handle;
+ GError *error = NULL;
+ gboolean success;
+
+ handle = (gpointer) g_variant_type_new ("(s)");
+ g_mutex_lock (&async_call_queue_lock);
+ g_queue_push_tail (&async_call_success_queue, handle);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ success = dconf_engine_dbus_call_async_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), handle, &error);
+ g_assert_no_error (error);
+ g_assert (success);
+ }
+
+ wait_for_queue_to_empty (&async_call_success_queue);
+}
+
+static void
+test_async_call_error (void)
+{
+ DConfEngineCallHandle *handle;
+ GError *error = NULL;
+ gboolean success;
+
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ handle = (gpointer) g_variant_type_new ("(s)");
+
+ g_mutex_lock (&async_call_queue_lock);
+ g_queue_push_tail (&async_call_error_queue, handle);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ success = dconf_engine_dbus_call_async_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("(s)", ""), handle, &error);
+ g_assert_no_error (error);
+ g_assert (success);
+
+ wait_for_queue_to_empty (&async_call_error_queue);
+}
+
+static void
+test_sync_during_async (void)
+{
+ DConfEngineCallHandle *handle;
+ GError *error = NULL;
+ gboolean success;
+ GVariant *reply;
+
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ handle = (gpointer) g_variant_type_new ("(s)");
+ g_mutex_lock (&async_call_queue_lock);
+ g_queue_push_tail (&async_call_success_queue, handle);
+ g_mutex_unlock (&async_call_queue_lock);
+
+ success = dconf_engine_dbus_call_async_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "GetId",
+ g_variant_new ("()"), handle, &error);
+ g_assert_no_error (error);
+ g_assert (success);
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "ListNames",
+ g_variant_new ("()"), G_VARIANT_TYPE ("(as)"), &error);
+ g_assert_no_error (error);
+ g_assert (reply != NULL);
+ g_variant_unref (reply);
+
+ wait_for_queue_to_empty (&async_call_success_queue);
+}
+
+static gboolean
+did_not_receive_signal (gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+test_signal_receipt (void)
+{
+ GError *error = NULL;
+ GVariant *reply;
+ gint status;
+ guint id;
+
+ if (g_getenv ("DISPLAY") == NULL || g_strcmp0 (g_getenv ("DISPLAY"), "") == 0)
+ {
+ g_test_skip ("FIXME: D-Bus tests do not work on CI at the moment");
+ return;
+ }
+
+ reply = dconf_engine_dbus_call_sync_func (G_BUS_TYPE_SESSION,
+ "org.freedesktop.DBus", "/", "org.freedesktop.DBus", "AddMatch",
+ g_variant_new ("(s)", "type='signal',interface='ca.desrt.dconf.Writer'"),
+ G_VARIANT_TYPE_UNIT, &error);
+ g_assert_no_error (error);
+ g_assert (reply != NULL);
+ g_variant_unref (reply);
+
+ status = system ("gdbus emit --session "
+ "--object-path /ca/desrt/dconf/Writer/testcase "
+ "--signal ca.desrt.dconf.Writer.TestSignal "
+ "\"'1'\" \"['2', '3']\"");
+ g_assert_cmpint (status, ==, 0);
+
+ id = g_timeout_add (30000, did_not_receive_signal, NULL);
+ while (!signal_was_received)
+ g_main_context_iteration (NULL, FALSE);
+ g_source_remove (id);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ main_thread = g_thread_self ();
+
+ dconf_engine_dbus_init_for_testing ();
+
+ /* test_creation_error absolutely must come first */
+ if (!g_str_equal (DBUS_BACKEND, "/libdbus-1"))
+ g_test_add_func (DBUS_BACKEND "/creation/error", test_creation_error);
+
+ g_test_add_func (DBUS_BACKEND "/sync-call/success", test_sync_call_success);
+ g_test_add_func (DBUS_BACKEND "/sync-call/error", test_sync_call_error);
+ g_test_add_func (DBUS_BACKEND "/async-call/success", test_async_call_success);
+ g_test_add_func (DBUS_BACKEND "/async-call/error", test_async_call_error);
+ g_test_add_func (DBUS_BACKEND "/sync-call/during-async", test_sync_during_async);
+ g_test_add_func (DBUS_BACKEND "/signal/receipt", test_signal_receipt);
+
+ return g_test_run ();
+}