summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2012-09-12 13:21:02 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2012-09-12 14:24:11 +0100
commit73306e67755de2b2b16d3a88d2ac9c8efe40bd99 (patch)
treea70c13e69362ba1884f55107eff2e847e9615d8b
parentfb470a3a8bde4e2bf07cf93722daa016a6344c2c (diff)
downloadtelepathy-mission-control-73306e67755de2b2b16d3a88d2ac9c8efe40bd99.tar.gz
Add a fake account storage backend which uses a mock D-Bus service
-rw-r--r--tests/twisted/Makefile.am7
-rw-r--r--tests/twisted/constants.py10
-rw-r--r--tests/twisted/dbus-account-plugin.c1096
-rw-r--r--tests/twisted/dbus-account-plugin.h50
-rw-r--r--tests/twisted/fakeaccountsservice.py188
-rw-r--r--tests/twisted/mcp-plugin.c8
-rw-r--r--tests/twisted/servicetest.py1
7 files changed, 1359 insertions, 1 deletions
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index ac931465..4c47d0f0 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -94,6 +94,7 @@ TWISTED_SEPARATE_TESTS += $(TWISTED_SPECIAL_BUILD_TESTS)
# source
TWISTED_OTHER_FILES = \
constants.py \
+ fakeaccountsservice.py \
fakeclient.py \
fakecm.py \
fakeconnectivity.py \
@@ -183,7 +184,11 @@ noinst_LTLIBRARIES = $(plugins_list)
endif
-mcp_plugin_la_SOURCES = mcp-plugin.c
+mcp_plugin_la_SOURCES = \
+ dbus-account-plugin.c \
+ dbus-account-plugin.h \
+ mcp-plugin.c \
+ $(NULL)
# these runes are necessary to make libtool build a dlopen()able shared
# library even though it's not going to be installed - the default for noinst
# libraries is static
diff --git a/tests/twisted/constants.py b/tests/twisted/constants.py
index c3de47cd..3fe4d1ae 100644
--- a/tests/twisted/constants.py
+++ b/tests/twisted/constants.py
@@ -188,3 +188,13 @@ CD_REDISPATCH = CD + '.Interface.Redispatch.DRAFT'
MC = tp_name_prefix + '.MissionControl5'
MC_PATH = tp_path_prefix + '/MissionControl5'
+
+TESTDOT = "org.freedesktop.Telepathy.MC.Test."
+TESTSLASH = "/org/freedesktop/Telepathy/MC/Test/"
+
+TEST_DBUS_ACCOUNT_SERVICE = TESTDOT + "DBusAccountService"
+TEST_DBUS_ACCOUNT_SERVICE_PATH = TESTSLASH + "DBusAccountService"
+TEST_DBUS_ACCOUNT_SERVICE_IFACE = TEST_DBUS_ACCOUNT_SERVICE
+
+TEST_DBUS_ACCOUNT_PLUGIN_PATH = TESTSLASH + "DBusAccountPlugin"
+TEST_DBUS_ACCOUNT_PLUGIN_IFACE = TESTDOT + "DBusAccountPlugin"
diff --git a/tests/twisted/dbus-account-plugin.c b/tests/twisted/dbus-account-plugin.c
new file mode 100644
index 00000000..c2bcf060
--- /dev/null
+++ b/tests/twisted/dbus-account-plugin.c
@@ -0,0 +1,1096 @@
+/*
+ * A demonstration plugin that diverts account storage to D-Bus, where the
+ * regression tests can manipulate it.
+ *
+ * Copyright © 2010 Nokia Corporation
+ * Copyright © 2010-2012 Collabora Ltd.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "dbus-account-plugin.h"
+
+#define DEBUG(format, ...) g_debug ("%s: " format, G_STRFUNC, ##__VA_ARGS__)
+
+#define TESTDOT "org.freedesktop.Telepathy.MC.Test."
+#define TESTSLASH "/org/freedesktop/Telepathy/MC/Test/"
+
+#define TEST_DBUS_ACCOUNT_SERVICE TESTDOT "DBusAccountService"
+#define TEST_DBUS_ACCOUNT_SERVICE_PATH TESTSLASH "DBusAccountService"
+#define TEST_DBUS_ACCOUNT_SERVICE_IFACE TEST_DBUS_ACCOUNT_SERVICE
+
+#define TEST_DBUS_ACCOUNT_PLUGIN_PATH TESTSLASH "DBusAccountPlugin"
+#define TEST_DBUS_ACCOUNT_PLUGIN_IFACE TESTDOT "DBusAccountPlugin"
+
+/* for now, the concepts of parameter/attribute flags are local to this
+ * plugin */
+
+typedef enum {
+ ATTRIBUTE_FLAG_NONE = 0
+} AttributeFlag;
+
+typedef enum {
+ PARAMETER_FLAG_NONE = 0,
+ PARAMETER_FLAG_SECRET = 1
+} ParameterFlag;
+
+typedef struct {
+ gchar *path;
+ /* string => GVariant */
+ GHashTable *attributes;
+ /* string => GUINT_TO_POINTER(guint32) */
+ GHashTable *attribute_flags;
+ /* set of strings */
+ GHashTable *uncommitted_attributes;
+ /* string => GVariant */
+ GHashTable *parameters;
+ /* string => string */
+ GHashTable *untyped_parameters;
+ /* string => GUINT_TO_POINTER(guint32) */
+ GHashTable *parameter_flags;
+ /* set of strings */
+ GHashTable *uncommitted_parameters;
+ enum { UNCOMMITTED_CREATION, UNCOMMITTED_DELETION } flags;
+} Account;
+
+static void
+test_dbus_account_free (gpointer p)
+{
+ Account *account = p;
+
+ g_hash_table_unref (account->attributes);
+ g_hash_table_unref (account->attribute_flags);
+ g_hash_table_unref (account->parameters);
+ g_hash_table_unref (account->untyped_parameters);
+ g_hash_table_unref (account->parameter_flags);
+
+ g_hash_table_unref (account->uncommitted_attributes);
+ g_hash_table_unref (account->uncommitted_parameters);
+
+ g_slice_free (Account, account);
+}
+
+static void account_storage_iface_init (McpAccountStorageIface *);
+
+struct _TestDBusAccountPlugin {
+ GObject parent;
+
+ GDBusConnection *bus;
+ GHashTable *accounts;
+ gboolean active;
+};
+
+struct _TestDBusAccountPluginClass {
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE_WITH_CODE (TestDBusAccountPlugin, test_dbus_account_plugin,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (MCP_TYPE_ACCOUNT_STORAGE,
+ account_storage_iface_init));
+
+typedef struct {
+ TestDBusAccountPlugin *self;
+ gchar *account_name;
+} AsyncData;
+
+static AsyncData *
+async_data_new (TestDBusAccountPlugin *self,
+ const gchar *account_name)
+{
+ AsyncData *ret = g_slice_new0 (AsyncData);
+
+ ret->self = g_object_ref (self);
+ ret->account_name = g_strdup (account_name);
+ return ret;
+}
+
+static void
+async_data_free (AsyncData *ad)
+{
+ g_clear_object (&ad->self);
+ g_free (ad->account_name);
+ g_slice_free (AsyncData, ad);
+}
+
+static Account *
+lookup_account (TestDBusAccountPlugin *self,
+ const gchar *account_name)
+{
+ return g_hash_table_lookup (self->accounts, account_name);
+}
+
+static Account *
+ensure_account (TestDBusAccountPlugin *self,
+ const gchar *account_name)
+{
+ Account *account = lookup_account (self, account_name);
+
+ if (account == NULL)
+ {
+ account = g_slice_new (Account);
+ account->path = g_strdup_printf ("%s%s", TP_ACCOUNT_OBJECT_PATH_BASE,
+ account_name);
+
+ account->attributes = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) g_variant_unref);
+ account->attribute_flags = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, NULL);
+ account->parameters = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) g_variant_unref);
+ account->untyped_parameters = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, g_free);
+ account->parameter_flags = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, NULL);
+
+ account->uncommitted_attributes = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, NULL);
+ account->uncommitted_parameters = g_hash_table_new_full (g_str_hash,
+ g_str_equal, g_free, NULL);
+
+ account->flags = UNCOMMITTED_CREATION;
+
+ g_hash_table_insert (self->accounts, g_strdup (account_name), account);
+ }
+
+ account->flags &= ~UNCOMMITTED_DELETION;
+ return account;
+}
+
+static void
+service_appeared_cb (GDBusConnection *bus,
+ const gchar *name,
+ const gchar *owner,
+ gpointer user_data)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (user_data);
+
+ self->active = TRUE;
+
+ /* FIXME: for now, we assume there are no accounts. */
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "Active", NULL, NULL);
+}
+
+static void
+service_vanished_cb (GDBusConnection *bus,
+ const gchar *name,
+ gpointer user_data)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (user_data);
+ GHashTableIter iter;
+ gpointer k, v;
+
+ self->active = FALSE;
+ g_hash_table_iter_init (&iter, self->accounts);
+
+ while (g_hash_table_iter_next (&iter, &k, &v))
+ {
+ Account *account = v;
+
+ if ((account->flags & UNCOMMITTED_DELETION) == 0)
+ mcp_account_storage_emit_deleted (MCP_ACCOUNT_STORAGE (self), k);
+
+ g_hash_table_iter_remove (&iter);
+ }
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "Inactive", NULL, NULL);
+}
+
+static void
+test_dbus_account_plugin_init (TestDBusAccountPlugin *self)
+{
+ GError *error = NULL;
+
+ DEBUG ("called");
+
+ self->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, test_dbus_account_free);
+
+ self->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (self->bus != NULL);
+
+ g_bus_watch_name (G_BUS_TYPE_SESSION, TEST_DBUS_ACCOUNT_SERVICE,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ service_appeared_cb,
+ service_vanished_cb,
+ g_object_ref (self),
+ g_object_unref);
+}
+
+static void
+test_dbus_account_plugin_class_init (TestDBusAccountPluginClass *cls)
+{
+ DEBUG ("called");
+}
+
+static void
+test_dbus_account_plugin_add_account (TestDBusAccountPlugin *self,
+ const gchar *account_name,
+ GVariant *attributes,
+ GVariant *attribute_flags,
+ GVariant *parameters,
+ GVariant *untyped_parameters,
+ GVariant *param_flags)
+{
+ GVariantIter iter;
+ const gchar *k;
+ GVariant *v;
+ const gchar *s;
+ guint32 u;
+ Account *account = ensure_account (self, account_name);
+
+ g_variant_iter_init (&iter, attributes);
+
+ while (g_variant_iter_loop (&iter, "{sv}", &k, &v))
+ g_hash_table_insert (account->attributes, g_strdup (k),
+ g_variant_ref (v));
+
+ g_variant_iter_init (&iter, attribute_flags);
+
+ while (g_variant_iter_loop (&iter, "{su}", &k, &u))
+ g_hash_table_insert (account->attribute_flags, g_strdup (k),
+ GUINT_TO_POINTER (u));
+
+ g_variant_iter_init (&iter, parameters);
+
+ while (g_variant_iter_loop (&iter, "{sv}", &k, &v))
+ g_hash_table_insert (account->parameters, g_strdup (k),
+ g_variant_ref (v));
+
+ g_variant_iter_init (&iter, untyped_parameters);
+
+ while (g_variant_iter_loop (&iter, "{ss}", &k, &s))
+ g_hash_table_insert (account->untyped_parameters,
+ g_strdup (k), g_strdup (s));
+
+ g_variant_iter_init (&iter, param_flags);
+
+ while (g_variant_iter_loop (&iter, "{su}", &k, &u))
+ g_hash_table_insert (account->parameter_flags, g_strdup (k),
+ GUINT_TO_POINTER (u));
+}
+
+static GList *
+test_dbus_account_plugin_list (const McpAccountStorage *storage,
+ const McpAccountManager *am)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ GError *error = NULL;
+ GVariant *tuple, *accounts;
+ GVariant *attributes, *attribute_flags;
+ GVariant *parameters, *untyped_parameters, *param_flags;
+ GVariantIter account_iter;
+ const gchar *account_name;
+ GList *ret = NULL;
+
+ DEBUG ("called");
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "Listing", NULL, NULL);
+
+ /* list is allowed to block */
+ tuple = g_dbus_connection_call_sync (self->bus,
+ TEST_DBUS_ACCOUNT_SERVICE,
+ TEST_DBUS_ACCOUNT_SERVICE_PATH,
+ TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ "GetAccounts",
+ NULL, /* no parameters */
+ G_VARIANT_TYPE ("(a{s(a{sv}a{su}a{sv}a{ss}a{su})})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* no cancellable */
+ &error);
+
+ if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER) ||
+ g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN))
+ {
+ /* this regression test isn't using the fake accounts service */
+ g_clear_error (&error);
+ return NULL;
+ }
+
+ self->active = TRUE;
+
+ g_assert_no_error (error);
+
+ g_variant_get (tuple, "(@*)", &accounts);
+
+ g_variant_iter_init (&account_iter, accounts);
+
+ while (g_variant_iter_loop (&account_iter,
+ "{s(@a{sv}@a{su}@a{sv}@a{ss}@a{su})}", &account_name,
+ &attributes, &attribute_flags,
+ &parameters, &untyped_parameters, &param_flags))
+ {
+ test_dbus_account_plugin_add_account (self, account_name,
+ attributes, attribute_flags, parameters, untyped_parameters,
+ param_flags);
+
+ ret = g_list_prepend (ret, g_strdup (account_name));
+ }
+
+ g_variant_unref (accounts);
+ g_variant_unref (tuple);
+ return ret;
+}
+
+static void
+test_dbus_account_plugin_ready (const McpAccountStorage *storage,
+ const McpAccountManager *am)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+
+ DEBUG ("called");
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "Ready", NULL, NULL);
+}
+
+static gchar *
+test_dbus_account_plugin_create (const McpAccountStorage *storage,
+ const McpAccountManager *am,
+ const gchar *manager,
+ const gchar *protocol,
+ GHashTable *params,
+ GError **error)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account;
+ gchar *name;
+
+ if (!self->active)
+ return FALSE;
+
+ name = mcp_account_manager_get_unique_name ((McpAccountManager *) am,
+ manager, protocol, params);
+ account = ensure_account (self, name);
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringCreate", g_variant_new_parsed ("(%o,)", account->path), NULL);
+ return name;
+}
+
+static gboolean
+test_dbus_account_plugin_delete (const McpAccountStorage *storage,
+ const McpAccountManager *am,
+ const gchar *account_name,
+ const gchar *key)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+
+ DEBUG ("called");
+
+ if (account == NULL || !self->active)
+ return FALSE;
+
+ if (key == NULL)
+ {
+ account->flags |= UNCOMMITTED_DELETION;
+ g_hash_table_remove_all (account->attributes);
+ g_hash_table_remove_all (account->parameters);
+ g_hash_table_remove_all (account->untyped_parameters);
+ g_hash_table_remove_all (account->attribute_flags);
+ g_hash_table_remove_all (account->parameter_flags);
+
+ account->flags &= ~UNCOMMITTED_CREATION;
+ g_hash_table_remove_all (account->uncommitted_attributes);
+ g_hash_table_remove_all (account->uncommitted_parameters);
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringDelete", g_variant_new_parsed ("(%o,)", account->path),
+ NULL);
+ }
+ else if (g_str_has_prefix (key, "param-"))
+ {
+ g_hash_table_remove (account->parameters, key + 6);
+ g_hash_table_remove (account->untyped_parameters, key + 6);
+ g_hash_table_remove (account->parameter_flags, key + 6);
+ g_hash_table_add (account->uncommitted_parameters, g_strdup (key + 6));
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringDeleteParameter",
+ g_variant_new_parsed ("(%o, %s)", account->path, key + 6), NULL);
+ }
+ else
+ {
+ g_hash_table_remove (account->attributes, key);
+ g_hash_table_remove (account->attribute_flags, key);
+ g_hash_table_add (account->uncommitted_attributes, g_strdup (key));
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringDeleteAttribute",
+ g_variant_new_parsed ("(%o, %s)", account->path, key), NULL);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+test_dbus_account_plugin_get (const McpAccountStorage *storage,
+ const McpAccountManager *am,
+ const gchar *account_name,
+ const gchar *key)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+
+ if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
+ return FALSE;
+
+ if (key == NULL)
+ {
+ GHashTableIter iter;
+ gpointer k, v;
+
+ /* get everything */
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "GetAllKeys",
+ g_variant_new_parsed ("(%o,)", account->path), NULL);
+
+ g_hash_table_iter_init (&iter, account->attributes);
+
+ while (g_hash_table_iter_next (&iter, &k, &v))
+ {
+ gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
+ v);
+
+ mcp_account_manager_set_value (am, account_name, k, escaped);
+ g_free (escaped);
+ }
+
+ g_hash_table_iter_init (&iter, account->untyped_parameters);
+
+ while (g_hash_table_iter_next (&iter, &k, &v))
+ {
+ gchar *param_foo;
+ guint32 flags;
+
+ param_foo = g_strdup_printf ("param-%s", (const gchar *) k);
+ mcp_account_manager_set_value (am, account_name, param_foo, v);
+
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (account->parameter_flags,
+ k));
+
+ if (flags & PARAMETER_FLAG_SECRET)
+ mcp_account_manager_parameter_make_secret (am, account_name,
+ param_foo);
+
+ g_free (param_foo);
+ }
+
+ g_hash_table_iter_init (&iter, account->parameters);
+
+ while (g_hash_table_iter_next (&iter, &k, &v))
+ {
+ gchar *param_foo;
+ guint32 flags;
+ gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
+ v);
+
+ param_foo = g_strdup_printf ("param-%s", (const gchar *) k);
+ mcp_account_manager_set_value (am, account_name, param_foo, escaped);
+ g_free (escaped);
+
+ flags = GPOINTER_TO_UINT (g_hash_table_lookup (account->parameter_flags,
+ k));
+
+ if (flags & PARAMETER_FLAG_SECRET)
+ mcp_account_manager_parameter_make_secret (am, account_name,
+ param_foo);
+
+ g_free (param_foo);
+ }
+
+ return TRUE;
+ }
+
+ /* get one parameter */
+
+ if (g_str_has_prefix (key, "param-"))
+ {
+ GVariant *v = g_hash_table_lookup (account->parameters, key + 6);
+ const gchar *s = g_hash_table_lookup (account->untyped_parameters, key + 6);
+ guint32 flags = GPOINTER_TO_UINT (
+ g_hash_table_lookup (account->parameter_flags, key + 6));
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "GetParameter",
+ g_variant_new_parsed ("(%o, %s)", account->path, key + 6), NULL);
+
+ if (flags & PARAMETER_FLAG_SECRET)
+ mcp_account_manager_parameter_make_secret (am, account_name, key);
+
+ if (v != NULL)
+ {
+ gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
+ v);
+
+ mcp_account_manager_set_value (am, account_name, key, escaped);
+ g_free (escaped);
+ }
+ else if (s != NULL)
+ {
+ mcp_account_manager_set_value (am, account_name, key, s);
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ GVariant *v = g_hash_table_lookup (account->attributes, key);
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "GetAttribute",
+ g_variant_new_parsed ("(%o, %s)", account->path, key), NULL);
+
+ if (v != NULL)
+ {
+ gchar *escaped = mcp_account_manager_escape_variant_for_keyfile (am,
+ v);
+
+ mcp_account_manager_set_value (am, account_name, key, escaped);
+ g_free (escaped);
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+test_dbus_account_plugin_set (const McpAccountStorage *storage,
+ const McpAccountManager *am,
+ const gchar *account_name,
+ const gchar *key,
+ const gchar *value)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+
+ g_return_val_if_fail (account_name != NULL, FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+ /* for deletions, MC would call delete() instead */
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ DEBUG ("%s of %s", key, account_name);
+
+ if (!self->active || account == NULL ||
+ (account->flags & UNCOMMITTED_DELETION))
+ return FALSE;
+
+ if (g_str_has_prefix (key, "param-"))
+ {
+ guint32 flags = PARAMETER_FLAG_NONE;
+
+ if (mcp_account_manager_parameter_is_secret (am, account_name, key))
+ {
+ flags |= PARAMETER_FLAG_SECRET;
+ }
+
+ g_hash_table_remove (account->parameters, key + 6);
+ g_hash_table_insert (account->untyped_parameters, g_strdup (key + 6),
+ g_strdup (value));
+ g_hash_table_insert (account->parameter_flags, g_strdup (key + 6),
+ GUINT_TO_POINTER (flags));
+ g_hash_table_add (account->uncommitted_parameters, g_strdup (key + 6));
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringSetParameterUntyped",
+ g_variant_new_parsed ("(%o, %s, %s)", account->path, key, value), NULL);
+ }
+ else
+ {
+ GValue gvalue = G_VALUE_INIT;
+ GError *error = NULL;
+ GVariant *variant;
+
+ if (!mcp_account_manager_init_value_for_attribute (am, &gvalue, key))
+ {
+ g_warning ("Cannot store unknown attribute %s", key);
+ return FALSE;
+ }
+
+ if (!mcp_account_manager_unescape_value_from_keyfile (am, value,
+ &gvalue, &error))
+ {
+ g_warning ("MC gave me a attribute it couldn't unescape: %s: %s",
+ key, error->message);
+ g_clear_error (&error);
+ return FALSE;
+ }
+
+ variant = g_variant_ref_sink (dbus_g_value_build_g_variant (&gvalue));
+
+ g_hash_table_insert (account->attributes, g_strdup (key),
+ g_variant_ref (variant));
+ g_hash_table_remove (account->attribute_flags, key);
+ g_hash_table_add (account->uncommitted_attributes, g_strdup (key));
+ g_value_unset (&gvalue);
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "DeferringSetAttribute",
+ g_variant_new_parsed ("(%o, %s, %v)", account->path, key, variant), NULL);
+ g_variant_unref (variant);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+test_dbus_account_plugin_commit (const McpAccountStorage *storage,
+ const McpAccountManager *am)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ GHashTableIter iter;
+ gpointer k;
+
+ DEBUG ("called");
+
+ if (!self->active)
+ return FALSE;
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "CommittingAll", NULL, NULL);
+
+ g_hash_table_iter_init (&iter, self->accounts);
+
+ while (g_hash_table_iter_next (&iter, &k, NULL))
+ {
+ if (!mcp_account_storage_commit_one (storage, am, k))
+ {
+ g_warning ("declined to commit account %s", (const gchar *) k);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+delete_account_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ AsyncData *ad = user_data;
+ GVariant *tuple;
+ GError *error = NULL;
+
+ tuple = g_dbus_connection_call_finish (ad->self->bus, res, &error);
+
+ if (tuple != NULL)
+ {
+ g_hash_table_remove (ad->self->accounts, ad->account_name);
+ g_variant_unref (tuple);
+ }
+ else
+ {
+ g_warning ("Unable to delete account %s: %s", ad->account_name,
+ error->message);
+ g_clear_error (&error);
+ /* FIXME: we could roll back the deletion by claiming that
+ * the service re-created the account? */
+ }
+
+ async_data_free (ad);
+}
+
+static void
+create_account_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ AsyncData *ad = user_data;
+ GVariant *tuple;
+ GError *error = NULL;
+
+ tuple = g_dbus_connection_call_finish (ad->self->bus, res, &error);
+
+ if (tuple != NULL)
+ {
+ Account *account = lookup_account (ad->self, ad->account_name);
+
+ if (account != NULL)
+ account->flags &= ~UNCOMMITTED_CREATION;
+
+ g_variant_unref (tuple);
+ }
+ else
+ {
+ g_warning ("Unable to create account %s: %s", ad->account_name,
+ error->message);
+ g_clear_error (&error);
+ /* FIXME: we could roll back the creation by claiming that
+ * the service deleted the account? If we do, we will have
+ * to do it in an idle because we might be iterating over
+ * all accounts in commit() */
+ }
+
+ async_data_free (ad);
+}
+
+static void
+update_attributes_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ AsyncData *ad = user_data;
+ GVariant *tuple;
+ GError *error = NULL;
+
+ tuple = g_dbus_connection_call_finish (ad->self->bus, res, &error);
+
+ if (tuple != NULL)
+ {
+ Account *account = lookup_account (ad->self, ad->account_name);
+
+ DEBUG ("Successfully committed attributes of %s", ad->account_name);
+
+ if (account != NULL)
+ g_hash_table_remove_all (account->uncommitted_attributes);
+
+ g_variant_unref (tuple);
+ }
+ else
+ {
+ g_warning ("Unable to update attributes on %s: %s", ad->account_name,
+ error->message);
+ g_clear_error (&error);
+ /* FIXME: we could roll back the creation by claiming that
+ * the service restored the old attributes? */
+ }
+
+ async_data_free (ad);
+}
+
+static void
+update_parameters_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ AsyncData *ad = user_data;
+ GVariant *tuple;
+ GError *error = NULL;
+
+ tuple = g_dbus_connection_call_finish (ad->self->bus, res, &error);
+
+ if (tuple != NULL)
+ {
+ Account *account = lookup_account (ad->self, ad->account_name);
+
+ DEBUG ("Successfully committed parameters of %s", ad->account_name);
+
+ if (account != NULL)
+ g_hash_table_remove_all (account->uncommitted_parameters);
+
+ g_variant_unref (tuple);
+ }
+ else
+ {
+ g_warning ("Unable to update parameters on %s: %s", ad->account_name,
+ error->message);
+ g_clear_error (&error);
+ /* FIXME: we could roll back the creation by claiming that
+ * the service restored the old parameters? */
+ }
+
+ async_data_free (ad);
+}
+
+static gboolean
+test_dbus_account_plugin_commit_one (const McpAccountStorage *storage,
+ const McpAccountManager *am,
+ const gchar *account_name)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+ GHashTableIter iter;
+ gpointer k;
+ GVariantBuilder a_sv_builder;
+ GVariantBuilder a_ss_builder;
+ GVariantBuilder a_su_builder;
+ GVariantBuilder as_builder;
+
+ DEBUG ("%s", account_name);
+
+ /* MC does not call @commit_one with parameter %NULL (meaning "all accounts")
+ * if we also implement commit(), which, as it happens, we do */
+ g_return_val_if_fail (account_name != NULL, FALSE);
+
+ if (!self->active || account == NULL)
+ return FALSE;
+
+ g_dbus_connection_emit_signal (self->bus, NULL,
+ TEST_DBUS_ACCOUNT_PLUGIN_PATH, TEST_DBUS_ACCOUNT_PLUGIN_IFACE,
+ "CommittingOne", g_variant_new_parsed ("(%o,)", account->path), NULL);
+
+ if (account->flags & UNCOMMITTED_DELETION)
+ {
+ g_dbus_connection_call (self->bus,
+ TEST_DBUS_ACCOUNT_SERVICE,
+ TEST_DBUS_ACCOUNT_SERVICE_PATH,
+ TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ "DeleteAccount",
+ g_variant_new_parsed ("(%s,)", account_name),
+ G_VARIANT_TYPE_UNIT,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* no cancellable */
+ delete_account_cb,
+ async_data_new (self, account_name));
+
+ /* this doesn't mean we succeeded: it means we tried */
+ return TRUE;
+ }
+
+ if (account->flags & UNCOMMITTED_CREATION)
+ {
+ g_dbus_connection_call (self->bus,
+ TEST_DBUS_ACCOUNT_SERVICE,
+ TEST_DBUS_ACCOUNT_SERVICE_PATH,
+ TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ "CreateAccount",
+ g_variant_new_parsed ("(%s,)", account_name),
+ G_VARIANT_TYPE_UNIT,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* no cancellable */
+ create_account_cb,
+ async_data_new (self, account_name));
+ }
+
+ if (g_hash_table_size (account->uncommitted_attributes) != 0)
+ {
+ g_variant_builder_init (&a_sv_builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_init (&a_su_builder, G_VARIANT_TYPE ("a{su}"));
+ g_variant_builder_init (&as_builder, G_VARIANT_TYPE_STRING_ARRAY);
+ g_hash_table_iter_init (&iter, account->uncommitted_attributes);
+
+ while (g_hash_table_iter_next (&iter, &k, NULL))
+ {
+ GVariant *v = g_hash_table_lookup (account->attributes, k);
+
+ DEBUG ("Attribute %s uncommitted, committing it now",
+ (const gchar *) k);
+
+ if (v != NULL)
+ {
+ g_variant_builder_add (&a_sv_builder, "{sv}", k, v);
+ g_variant_builder_add (&a_su_builder, "{su}", k,
+ GPOINTER_TO_UINT (g_hash_table_lookup (account->attribute_flags,
+ k)));
+ }
+ else
+ {
+ g_variant_builder_add (&as_builder, "s", k);
+ }
+ }
+
+ g_dbus_connection_call (self->bus,
+ TEST_DBUS_ACCOUNT_SERVICE,
+ TEST_DBUS_ACCOUNT_SERVICE_PATH,
+ TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ "UpdateAttributes",
+ g_variant_new_parsed ("(%s, %v, %v, %v)", account_name,
+ g_variant_builder_end (&a_sv_builder),
+ g_variant_builder_end (&a_su_builder),
+ g_variant_builder_end (&as_builder)),
+ G_VARIANT_TYPE_UNIT,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* no cancellable */
+ update_attributes_cb,
+ async_data_new (self, account_name));
+ }
+ else
+ {
+ DEBUG ("no attributes to commit");
+ }
+
+ if (g_hash_table_size (account->uncommitted_parameters) != 0)
+ {
+ g_variant_builder_init (&a_sv_builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_init (&a_ss_builder, G_VARIANT_TYPE ("a{ss}"));
+ g_variant_builder_init (&a_su_builder, G_VARIANT_TYPE ("a{su}"));
+ g_variant_builder_init (&as_builder, G_VARIANT_TYPE_STRING_ARRAY);
+ g_hash_table_iter_init (&iter, account->uncommitted_parameters);
+
+ while (g_hash_table_iter_next (&iter, &k, NULL))
+ {
+ GVariant *v = g_hash_table_lookup (account->parameters, k);
+ const gchar *s = g_hash_table_lookup (account->untyped_parameters, k);
+
+ DEBUG ("Parameter %s uncommitted, committing it now",
+ (const gchar *) k);
+
+ if (v != NULL)
+ {
+ g_variant_builder_add (&a_sv_builder, "{sv}", k, v);
+ g_variant_builder_add (&a_su_builder, "{su}", k,
+ GPOINTER_TO_UINT (g_hash_table_lookup (account->parameter_flags,
+ k)));
+ }
+ else if (s != NULL)
+ {
+ g_variant_builder_add (&a_ss_builder, "{ss}", k, s);
+ g_variant_builder_add (&a_su_builder, "{su}", k,
+ GPOINTER_TO_UINT (g_hash_table_lookup (account->parameter_flags,
+ k)));
+ }
+ else
+ {
+ g_variant_builder_add (&as_builder, "s", k);
+ }
+ }
+
+ g_dbus_connection_call (self->bus,
+ TEST_DBUS_ACCOUNT_SERVICE,
+ TEST_DBUS_ACCOUNT_SERVICE_PATH,
+ TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ "UpdateParameters",
+ g_variant_new_parsed ("(%s, %v, %v, %v, %v)", account_name,
+ g_variant_builder_end (&a_sv_builder),
+ g_variant_builder_end (&a_ss_builder),
+ g_variant_builder_end (&a_su_builder),
+ g_variant_builder_end (&as_builder)),
+ G_VARIANT_TYPE_UNIT,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* no cancellable */
+ update_parameters_cb,
+ async_data_new (self, account_name));
+ }
+ else
+ {
+ DEBUG ("no parameters to commit");
+ }
+
+ return TRUE;
+}
+
+static void
+test_dbus_account_plugin_get_identifier (const McpAccountStorage *storage,
+ const gchar *account_name,
+ GValue *identifier)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+
+ DEBUG ("%s", account_name);
+
+ if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
+ return;
+
+ /* Our "library-specific unique identifier" is just the object-path
+ * as a string. */
+ g_value_init (identifier, G_TYPE_STRING);
+ g_value_set_string (identifier, account->path);
+}
+
+static GHashTable *
+test_dbus_account_plugin_get_additional_info (const McpAccountStorage *storage,
+ const gchar *account_name)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+ GHashTable *ret;
+
+ DEBUG ("%s", account_name);
+
+ if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
+ return NULL;
+
+ ret = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) tp_g_value_slice_free);
+ g_hash_table_insert (ret, g_strdup ("hello"),
+ tp_g_value_slice_new_static_string ("world"));
+
+ return ret;
+}
+
+static guint
+test_dbus_account_plugin_get_restrictions (const McpAccountStorage *storage,
+ const gchar *account_name)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+
+ DEBUG ("%s", account_name);
+
+ if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
+ return 0;
+
+ /* FIXME: actually enforce this restriction */
+ return TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_SERVICE;
+}
+
+static gboolean
+test_dbus_account_plugin_owns (McpAccountStorage *storage,
+ McpAccountManager *am,
+ const gchar *account_name)
+{
+ TestDBusAccountPlugin *self = TEST_DBUS_ACCOUNT_PLUGIN (storage);
+ Account *account = lookup_account (self, account_name);
+
+ DEBUG ("%s", account_name);
+
+ if (!self->active || account == NULL || (account->flags & UNCOMMITTED_DELETION))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+account_storage_iface_init (McpAccountStorageIface *iface)
+{
+ iface->name = "TestDBusAccount";
+ iface->desc = "Regression test plugin";
+ /* this should be higher priority than the diverted-keyfile one */
+ iface->priority = MCP_ACCOUNT_STORAGE_PLUGIN_PRIO_NORMAL + 100;
+
+ iface->get = test_dbus_account_plugin_get;
+ iface->set = test_dbus_account_plugin_set;
+ iface->list = test_dbus_account_plugin_list;
+ iface->ready = test_dbus_account_plugin_ready;
+ iface->delete = test_dbus_account_plugin_delete;
+ iface->commit = test_dbus_account_plugin_commit;
+ iface->commit_one = test_dbus_account_plugin_commit_one;
+ iface->get_identifier = test_dbus_account_plugin_get_identifier;
+ iface->get_additional_info = test_dbus_account_plugin_get_additional_info;
+ iface->get_restrictions = test_dbus_account_plugin_get_restrictions;
+ iface->create = test_dbus_account_plugin_create;
+ iface->owns = test_dbus_account_plugin_owns;
+}
diff --git a/tests/twisted/dbus-account-plugin.h b/tests/twisted/dbus-account-plugin.h
new file mode 100644
index 00000000..36789bdb
--- /dev/null
+++ b/tests/twisted/dbus-account-plugin.h
@@ -0,0 +1,50 @@
+/*
+ * A demonstration plugin that diverts account storage to D-Bus, where the
+ * regression tests can manipulate it.
+ *
+ * Copyright © 2010 Nokia Corporation
+ * Copyright © 2010-2012 Collabora Ltd.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_DBUS_ACCOUNT_PLUGIN_H
+#define TEST_DBUS_ACCOUNT_PLUGIN_H
+
+#include <mission-control-plugins/mission-control-plugins.h>
+
+typedef struct _TestDBusAccountPlugin TestDBusAccountPlugin;
+typedef struct _TestDBusAccountPluginClass TestDBusAccountPluginClass;
+typedef struct _TestDBusAccountPluginPrivate TestDBusAccountPluginPrivate;
+
+GType test_dbus_account_plugin_get_type (void);
+
+#define TEST_TYPE_DBUS_ACCOUNT_PLUGIN \
+ (test_dbus_account_plugin_get_type ())
+#define TEST_DBUS_ACCOUNT_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_DBUS_ACCOUNT_PLUGIN, \
+ TestDBusAccountPlugin))
+#define TEST_DBUS_ACCOUNT_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_DBUS_ACCOUNT_PLUGIN, \
+ TestDBusAccountPluginClass))
+#define TEST_IS_DBUS_ACCOUNT_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_DBUS_ACCOUNT_PLUGIN))
+#define TEST_IS_DBUS_ACCOUNT_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_DBUS_ACCOUNT_PLUGIN))
+#define TEST_DBUS_ACCOUNT_PLUGIN_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_DBUS_ACCOUNT_PLUGIN, \
+ TestDBusAccountPluginClass))
+
+#endif
diff --git a/tests/twisted/fakeaccountsservice.py b/tests/twisted/fakeaccountsservice.py
new file mode 100644
index 00000000..3c10a156
--- /dev/null
+++ b/tests/twisted/fakeaccountsservice.py
@@ -0,0 +1,188 @@
+# vim: set fileencoding=utf-8
+#
+# Copyright © 2009 Nokia Corporation
+# Copyright © 2009-2012 Collabora Ltd.
+#
+# This library 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.1 of the License, or (at your option) any later version.
+#
+# This library 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 this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+import dbus
+import dbus.service
+
+from servicetest import (Event, EventPattern)
+
+import constants as cs
+
+# indices into the tuple of dicts representing an account
+ATTRS = 0
+ATTR_FLAGS = 1
+PARAMS = 2
+UNTYPED_PARAMS = 3
+PARAM_FLAGS = 4
+
+class FakeAccountsService(object):
+ def __init__(self, q, bus):
+ self.q = q
+ self.bus = bus
+ self.nameref = dbus.service.BusName(cs.TEST_DBUS_ACCOUNT_SERVICE,
+ self.bus)
+ self.object_path = cs.TEST_DBUS_ACCOUNT_SERVICE_PATH
+
+ self.accounts = {}
+
+ q.add_dbus_method_impl(self.GetAccounts,
+ path=self.object_path,
+ interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ method='GetAccounts')
+
+ q.add_dbus_method_impl(self.CreateAccount,
+ path=self.object_path,
+ interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ method='CreateAccount')
+
+ q.add_dbus_method_impl(self.DeleteAccount,
+ path=self.object_path,
+ interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ method='DeleteAccount')
+
+ q.add_dbus_method_impl(self.UpdateAttributes,
+ path=self.object_path,
+ interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ method='UpdateAttributes')
+
+ q.add_dbus_method_impl(self.UpdateParameters,
+ path=self.object_path,
+ interface=cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ method='UpdateParameters')
+
+ def create_account(self, account, attrs={}, attr_flags={}, params={},
+ untyped_params={}, param_flags={}):
+ if account in self.accounts:
+ raise KeyError('Account %s already exists' % account)
+ self.accounts[account] = ({}, {}, {}, {}, {})
+ self.accounts[account][ATTRS].update(attrs)
+ for attr in attrs:
+ self.accounts[account][ATTR_FLAGS][attr] = dbus.UInt32(0)
+ self.accounts[account][ATTR_FLAGS].update(attr_flags)
+ self.accounts[account][PARAMS].update(params)
+ for param in params:
+ self.accounts[account][PARAM_FLAGS][param] = dbus.UInt32(0)
+ self.accounts[account][UNTYPED_PARAMS].update(untyped_params)
+ for param in untyped_params:
+ self.accounts[account][PARAM_FLAGS][param] = dbus.UInt32(0)
+ self.accounts[account][PARAM_FLAGS].update(param_flags)
+ self.q.dbus_emit(self.object_path, cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ 'AccountCreated',
+ account, *self.accounts[account],
+ signature='sa{sv}a{su}a{sv}a{ss}a{su}')
+
+ def CreateAccount(self, e):
+ try:
+ self.create_account(*e.raw_args)
+ except Exception as ex:
+ self.q.dbus_raise(e.message, cs.NOT_AVAILABLE, str(ex))
+ else:
+ self.q.dbus_return(e.message, signature='')
+
+ def delete_account(self, account):
+ # raises if not found
+ del self.accounts[account]
+ self.q.dbus_emit(self.object_path, cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ 'AccountDeleted', account, signature='s')
+
+ def DeleteAccount(self, e):
+ try:
+ self.delete_account(*e.raw_args)
+ except Exception as ex:
+ self.q.dbus_raise(e.message, cs.NOT_AVAILABLE, str(ex))
+ else:
+ self.q.dbus_return(e.message, signature='')
+
+ def GetAccounts(self, e):
+ self.q.dbus_return(e.message, self.accounts,
+ signature='a{s(a{sv}a{su}a{sv}a{ss}a{su})}')
+
+ def update_attributes(self, account, changed={}, flags={}, deleted=[]):
+ if account not in self.accounts:
+ self.create_account(account)
+
+ for (attribute, value) in changed.items():
+ self.accounts[account][ATTRS][attribute] = value
+ self.accounts[account][ATTR_FLAGS][attribute] = flags.get(
+ attribute, dbus.UInt32(0))
+
+ for attribute in deleted:
+ if attribute in self.accounts[account][ATTRS]:
+ del self.accounts[account][ATTRS][attribute]
+ if attribute in self.accounts[account][ATTR_FLAGS]:
+ del self.accounts[account][ATTR_FLAGS][attribute]
+
+ self.q.dbus_emit(self.object_path, cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ 'AttributesChanged',
+ account, changed,
+ dict([(a, self.accounts[account][ATTR_FLAGS][a])
+ for a in changed]),
+ deleted, signature='sa{sv}a{su}as')
+
+ def UpdateAttributes(self, e):
+ try:
+ self.update_attributes(*e.raw_args)
+ except Exception as ex:
+ self.q.dbus_raise(e.message, cs.NOT_AVAILABLE, str(ex))
+ else:
+ self.q.dbus_return(e.message, signature='')
+
+ def update_parameters(self, account, changed={}, untyped={}, flags={},
+ deleted=[]):
+ if account not in self.accounts:
+ self.create_account(account)
+
+ for (param, value) in changed.items():
+ self.accounts[account][PARAMS][param] = value
+ if param in self.accounts[account][UNTYPED_PARAMS]:
+ del self.accounts[account][UNTYPED_PARAMS][param]
+ self.accounts[account][PARAM_FLAGS][param] = flags.get(
+ param, dbus.UInt32(0))
+
+ for (param, value) in untyped.items():
+ self.accounts[account][UNTYPED_PARAMS][param] = value
+ if param in self.accounts[account][PARAMS]:
+ del self.accounts[account][PARAMS][param]
+ self.accounts[account][PARAM_FLAGS][param] = flags.get(
+ param, dbus.UInt32(0))
+
+ for param in deleted:
+ if param in self.accounts[account][PARAMS]:
+ del self.accounts[account][PARAMS][param]
+ if param in self.accounts[account][UNTYPED_PARAMS]:
+ del self.accounts[account][UNTYPED_PARAMS][param]
+ if param in self.accounts[account][PARAM_FLAGS]:
+ del self.accounts[account][PARAM_FLAGS][param]
+
+ self.q.dbus_emit(self.object_path, cs.TEST_DBUS_ACCOUNT_SERVICE_IFACE,
+ 'ParametersChanged',
+ account, changed, untyped,
+ dict([(p, self.accounts[account][PARAM_FLAGS][p])
+ for p in (set(changed.keys()) | set(untyped.keys()))]),
+ deleted,
+ signature='sa{sv}a{ss}a{su}as')
+
+ def UpdateParameters(self, e):
+ try:
+ self.update_parameters(*e.raw_args)
+ except Exception as ex:
+ self.q.dbus_raise(e.message, cs.NOT_AVAILABLE, str(ex))
+ else:
+ self.q.dbus_return(e.message, signature='')
diff --git a/tests/twisted/mcp-plugin.c b/tests/twisted/mcp-plugin.c
index f103dac0..1c536665 100644
--- a/tests/twisted/mcp-plugin.c
+++ b/tests/twisted/mcp-plugin.c
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "config.h"
+
#include <mission-control-plugins/mission-control-plugins.h>
#include <dbus/dbus.h>
@@ -27,6 +29,8 @@
#include <telepathy-glib/telepathy-glib.h>
#include <telepathy-glib/telepathy-glib-dbus.h>
+#include "dbus-account-plugin.h"
+
#define DEBUG g_debug
/* ------ TestNoOpPlugin -------------------------------------- */
@@ -584,6 +588,10 @@ mcp_plugin_ref_nth_object (guint n)
return g_object_new (test_no_op_plugin_get_type (),
NULL);
+ case 4:
+ return g_object_new (test_dbus_account_plugin_get_type (),
+ NULL);
+
default:
return NULL;
}
diff --git a/tests/twisted/servicetest.py b/tests/twisted/servicetest.py
index 60418312..4dc604f3 100644
--- a/tests/twisted/servicetest.py
+++ b/tests/twisted/servicetest.py
@@ -364,6 +364,7 @@ class IteratingEventQueue(BaseEventQueue):
e = Event('dbus-method-call', message=message,
interface=message.get_interface(), path=message.get_path(),
+ raw_args=message.get_args_list(byte_arrays=True),
args=map(unwrap, message.get_args_list(byte_arrays=True)),
destination=str(destination),
method=message.get_member(),