[dconf] Add torture-test for GSettings backend
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dconf] Add torture-test for GSettings backend
- Date: Sun, 19 Dec 2010 07:33:53 +0000 (UTC)
commit cc4e8bbf45af0e5d5ae35585778aebec35e261c5
Author: Ryan Lortie <desrt desrt ca>
Date: Sun Dec 19 02:32:23 2010 -0500
Add torture-test for GSettings backend
tests/.gitignore | 1 +
tests/Makefile.am | 3 +-
tests/gsettings.c | 393 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 396 insertions(+), 1 deletions(-)
---
diff --git a/tests/.gitignore b/tests/.gitignore
index 217c33c..791498d 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1 +1,2 @@
paths
+gsettings
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6418598..99f3760 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,8 +1,9 @@
AM_CFLAGS = -std=c89 -Wall -Wmissing-prototypes -Wwrite-strings
INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/engine -I$(top_srcdir)/client $(gio_CFLAGS)
-noinst_PROGRAMS = paths
+noinst_PROGRAMS = paths gsettings
+gsettings_LDADD = $(gio_LIBS)
paths_LDADD = $(gio_LIBS)
paths_SOURCES = \
../common/dconf-paths.c \
diff --git a/tests/gsettings.c b/tests/gsettings.c
new file mode 100644
index 0000000..ce7cf7b
--- /dev/null
+++ b/tests/gsettings.c
@@ -0,0 +1,393 @@
+/**
+ * Copyright © 2010 Canonical Limited
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the licence, or (at
+ * your option) any later version.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
+ **/
+
+#define G_SETTINGS_ENABLE_BACKEND
+#include <gio/gsettingsbackend.h>
+#include <gio/gio.h>
+
+#include <stdbool.h>
+#include <string.h>
+
+static GSettingsBackend *backend;
+
+static void
+free_variant (gpointer data)
+{
+ if (data != NULL)
+ g_variant_unref (data);
+}
+
+static GVariant *
+do_read (const gchar *key)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->read (backend, key, NULL, FALSE);
+}
+
+static gboolean
+do_write (const gchar *key,
+ GVariant *value)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->write (backend, key, value, do_write);
+}
+
+static gboolean
+do_write_tree (GTree *tree)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->write_tree (backend, tree, do_write);
+}
+
+static void
+do_sync (void)
+{
+ return G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->sync (backend);
+}
+
+#define RANDOM_ELEMENT(array) \
+ array[g_test_rand_int_range(0, G_N_ELEMENTS(array))]
+
+static gchar *
+random_key (void)
+{
+ const gchar * const words[] = {
+ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf",
+ "hotel", "india", "juliet", "kilo", "lima", "mike", "november",
+ "oscar", "papa", "quebec", "romeo", "sierra", "tango", "uniform",
+ "victor", "whiskey", "xray", "yankee", "zulu"
+ };
+ const gchar *parts[8];
+ gint n, i;
+
+ n = g_test_rand_int_range (2, 8);
+ parts[0] = "";
+ for (i = 1; i < n; i++)
+ parts[i] = RANDOM_ELEMENT (words);
+ parts[n] = NULL;
+
+ return g_strjoinv ("/", (gchar **) parts);
+}
+
+static GVariant *
+random_value (void)
+{
+ switch (g_test_rand_int_range (0, 3))
+ {
+ case 0:
+ return g_variant_new_int32 (g_test_rand_int ());
+
+ case 1:
+ return g_variant_new_boolean (g_test_rand_bit ());
+
+ case 2:
+ {
+ gint length = g_test_rand_int_range (0, 24);
+ gchar buffer[24];
+ gint i;
+
+ for (i = 0; i < length; i++)
+ buffer[i] = 'a' + g_test_rand_int_range (0, 26);
+ buffer[i] = '\0';
+
+ return g_variant_new_string (buffer);
+ }
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static GTree *
+random_tree (void)
+{
+ GTree *tree;
+ gint n;
+
+ tree = g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
+ g_free, free_variant);
+ n = g_test_rand_int_range (1, 20);
+
+ while (n--)
+ g_tree_insert (tree, random_key (), g_variant_ref_sink (random_value ()));
+
+ return tree;
+}
+
+static void
+apply_change (GHashTable *table,
+ const gchar *key,
+ GVariant *value)
+{
+ if (value)
+ g_hash_table_insert (table, g_strdup (key), g_variant_ref_sink (value));
+ else
+ g_hash_table_insert (table, g_strdup (key), NULL);
+}
+
+static gboolean
+apply_one_change (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ apply_change (user_data, key, value);
+ return FALSE;
+}
+
+static void
+apply_change_tree (GHashTable *table,
+ GTree *tree)
+{
+ g_tree_foreach (tree, apply_one_change, table);
+}
+
+static GHashTable *implicit;
+static GHashTable *explicit;
+
+/* interpose */
+void
+g_settings_backend_changed (GSettingsBackend *backend_,
+ const gchar *key,
+ gpointer origin_tag)
+{
+ /* ensure that we see no dupes from the bus */
+ g_assert (origin_tag == do_write);
+ g_assert (backend == backend_);
+
+ apply_change (implicit, key, do_read (key));
+}
+
+/* interpose */
+void
+g_settings_backend_keys_changed (GSettingsBackend *backend_,
+ const gchar *path,
+ const gchar * const *items,
+ gpointer origin_tag)
+{
+ gint i;
+
+ /* ensure that we see no dupes from the bus */
+ g_assert (origin_tag == do_write);
+ g_assert (backend == backend_);
+
+ for (i = 0; items[i]; i++)
+ {
+ gchar *key = g_strconcat (path, items[i], NULL);
+ apply_change (implicit, key, do_read (key));
+ g_free (key);
+ }
+}
+
+/* interpose */
+void
+g_settings_backend_changed_tree (GSettingsBackend *backend_,
+ GTree *tree,
+ gpointer origin_tag)
+{
+ const gchar **keys;
+ gchar *path;
+
+ g_settings_backend_flatten_tree (tree, &path, &keys, NULL);
+ g_settings_backend_keys_changed (backend_, path, keys, origin_tag);
+}
+
+static void
+setup (void)
+{
+ extern void _g_io_modules_ensure_loaded (void);
+ GIOExtensionPoint *point;
+ GIOExtension *extension;
+ GType extension_type;
+ gchar *file;
+
+ file = g_build_filename (g_get_user_config_dir (),
+ "dconf/test", NULL);
+ unlink (file);
+ g_free (file);
+
+ g_setenv ("DCONF_PROFILE", "test", false);
+
+ g_type_init ();
+ g_file_new_for_path (".");
+
+ point = g_io_extension_point_lookup ("gsettings-backend");
+ extension = g_io_extension_point_get_extension_by_name (point, "dconf");
+ extension_type = g_io_extension_get_type (extension);
+ backend = g_object_new (extension_type, NULL);
+
+ G_SETTINGS_BACKEND_GET_CLASS (backend)
+ ->subscribe (backend, "/");
+
+ implicit = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, free_variant);
+ explicit = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, free_variant);
+
+ sleep(1);
+}
+
+static void
+make_random_change (void)
+{
+ if (g_test_rand_bit ())
+ {
+ GVariant *value;
+ gchar *key;
+
+ key = random_key ();
+ value = random_value ();
+ apply_change (explicit, key, value);
+ do_write (key, value);
+
+ g_free (key);
+ }
+ else
+ {
+ GTree *tree;
+
+ tree = random_tree ();
+ apply_change_tree (explicit, tree);
+ do_write_tree (tree);
+
+ g_tree_unref (tree);
+ }
+}
+
+guint64 dconf_time;
+guint64 ghash_time;
+guint64 lookups;
+gboolean dots;
+
+static void
+verify_consistency (void)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (dots)
+ g_print (".");
+ else
+ g_print ("(%d)", g_hash_table_size (implicit));
+
+ g_assert (g_hash_table_size (explicit) == g_hash_table_size (implicit));
+ g_hash_table_iter_init (&iter, explicit);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ if (value)
+ {
+ GVariant *other;
+
+ ghash_time -= g_get_monotonic_time ();
+ other = g_hash_table_lookup (explicit, key);
+ ghash_time += g_get_monotonic_time ();
+ g_assert (g_variant_equal (value, other));
+
+ dconf_time -= g_get_monotonic_time ();
+ other = do_read (key);
+ dconf_time += g_get_monotonic_time ();
+ g_assert (g_variant_equal (value, other));
+ g_variant_unref (other);
+ }
+ else
+ {
+ g_assert (g_hash_table_lookup (implicit, key) == NULL);
+ g_assert (do_read (key) == NULL);
+ }
+
+ lookups++;
+ }
+}
+
+#if 0
+static void
+dump_table (void)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_print ("{");
+ g_hash_table_iter_init (&iter, explicit);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ if (value)
+ {
+ gchar *printed;
+
+ if (value)
+ printed = g_variant_print (value, FALSE);
+ else
+ printed = g_strdup ("None");
+
+ g_print ("'%s': %s, ", (gchar *) key, printed);
+ g_free (printed);
+ }
+ g_print ("}");
+}
+#endif
+
+static void
+test (void)
+{
+ int i;
+
+ g_print ("Testing dconf...");
+ for (i = 0; i < 1000; i++)
+ {
+ g_print (" %d", i);
+ make_random_change ();
+ verify_consistency ();
+ }
+
+ g_print ("\n");
+ g_print ("GSettings lookup time: %f µs/lookup\n",
+ ((double) dconf_time / lookups));
+ g_print ("GHashTable lookup time: %f µs/lookup\n",
+ ((double) ghash_time / lookups));
+
+ dconf_time = 0;
+ ghash_time = 0;
+ lookups = 0;
+
+ g_print ("\nWaiting for dconf-service to catch up...");
+ do_sync ();
+ g_print (" done.\n");
+
+ g_print ("Measuring dconf read performance...");
+ dots = TRUE;
+ for (i = 0; i < 1000; i++)
+ verify_consistency ();
+ g_print ("\n");
+
+ g_print ("dconf lookup time: %f µs/lookup\n",
+ ((double) dconf_time / lookups));
+ g_print ("GHashTable lookup time: %f µs/lookup\n",
+ ((double) ghash_time / lookups));
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ setup ();
+
+ test ();
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]