[dconf/wip/reorg] tests/: add more testing code for engine



commit 0725a5fd7cd8a8a3af00b7edbbe8de4216e3f578
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Jul 12 14:35:12 2012 -0400

    tests/: add more testing code for engine
    
    Add an initial implementation of the gvdb mocking support and improve
    the existing shm mock by adding logging.
    
    Use these new features to test the 'user' DConfEngineSource.

 tests/dconf-mock-gvdb.c |  123 ++++++++++++++++++++++++++++++++++++++++++++--
 tests/dconf-mock-shm.c  |   46 +++++++++++++++++-
 tests/dconf-mock.h      |   12 +++++
 tests/engine.c          |   97 +++++++++++++++++++++++++++++++++++++
 4 files changed, 270 insertions(+), 8 deletions(-)
---
diff --git a/tests/dconf-mock-gvdb.c b/tests/dconf-mock-gvdb.c
index 96695ad..50ffbac 100644
--- a/tests/dconf-mock-gvdb.c
+++ b/tests/dconf-mock-gvdb.c
@@ -1,36 +1,136 @@
 #include "../gvdb/gvdb-reader.h"
+#include "dconf-mock.h"
+
+/* The global dconf_mock_gvdb_tables hashtable is modified all the time
+ * so we need to hold the lock while we access it.
+ *
+ * The hashtables contained within it are never modified, however.  They
+ * can be safely accessed without a lock.
+ */
+
+static GHashTable *dconf_mock_gvdb_tables;
+static GMutex      dconf_mock_gvdb_lock;
+
+typedef struct
+{
+  GVariant   *value;
+  GHashTable *table;
+} DConfMockGvdbItem;
+
+static void
+dconf_mock_gvdb_item_free (gpointer data)
+{
+  DConfMockGvdbItem *item = data;
+
+  if (item->value)
+    g_variant_unref (item->value);
+
+  if (item->table)
+    g_hash_table_unref (item->table);
+
+  g_slice_free (DConfMockGvdbItem, item);
+}
+
+static void
+dconf_mock_gvdb_init (void)
+{
+  if (dconf_mock_gvdb_tables == NULL)
+    dconf_mock_gvdb_tables = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                                    (GDestroyNotify) g_hash_table_unref);
+}
+
+DConfMockGvdbTable *
+dconf_mock_gvdb_table_new (void)
+{
+  GHashTable *hash_table;
+
+  hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, dconf_mock_gvdb_item_free);
+
+  return (DConfMockGvdbTable *) hash_table;
+}
+
+void
+dconf_mock_gvdb_table_insert (DConfMockGvdbTable *table,
+                              const gchar        *name,
+                              GVariant           *value,
+                              DConfMockGvdbTable *subtable)
+{
+  GHashTable *hash_table = (GHashTable *) table;
+  DConfMockGvdbItem *item;
+
+  g_assert (value == NULL || subtable == NULL);
+
+  item = g_slice_new (DConfMockGvdbItem);
+  item->value = value ? g_variant_ref_sink (value) : NULL;
+  item->table = (GHashTable *) subtable;
+
+  g_hash_table_insert (hash_table, g_strdup (name), item);
+}
+
+void
+dconf_mock_gvdb_install (const gchar        *filename,
+                         DConfMockGvdbTable *table)
+{
+  g_mutex_lock (&dconf_mock_gvdb_lock);
+  dconf_mock_gvdb_init ();
+
+  if (table)
+    g_hash_table_insert (dconf_mock_gvdb_tables, g_strdup (filename), table);
+  else
+    g_hash_table_remove (dconf_mock_gvdb_tables, filename);
+
+  g_mutex_unlock (&dconf_mock_gvdb_lock);
+}
 
 void
 gvdb_table_unref (GvdbTable *table)
 {
+  GHashTable *hash_table = (GHashTable *) table;
+
+  g_hash_table_unref (hash_table);
 }
 
 GvdbTable *
 gvdb_table_get_table (GvdbTable   *table,
                       const gchar *key)
 {
-  return NULL;
+  GHashTable *hash_table = (GHashTable *) table;
+  DConfMockGvdbItem *item;
+
+  item = g_hash_table_lookup (hash_table, key);
+
+  return (GvdbTable *) (item ? g_hash_table_ref (item->table) : NULL);
 }
 
 gboolean
 gvdb_table_has_value (GvdbTable   *table,
                       const gchar *key)
 {
-  return FALSE;
+  GHashTable *hash_table = (GHashTable *) table;
+  DConfMockGvdbItem *item;
+
+  item = g_hash_table_lookup (hash_table, key);
+
+  return item && item->value;
 }
 
 GVariant *
 gvdb_table_get_value (GvdbTable   *table,
                       const gchar *key)
 {
-  return NULL;
+  GHashTable *hash_table = (GHashTable *) table;
+  DConfMockGvdbItem *item;
+
+  item = g_hash_table_lookup (hash_table, key);
+
+  return item ? g_variant_ref (item->value) : NULL;
 }
 
 gchar **
 gvdb_table_list (GvdbTable *table,
                  const gchar *key)
 {
-  return NULL;
+  g_assert_not_reached ();
 }
 
 GvdbTable *
@@ -38,8 +138,19 @@ gvdb_table_new (const gchar  *filename,
                 gboolean      trusted,
                 GError      **error)
 {
-  g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, "not implemented");
-  return NULL;
+  GHashTable *hash_table;
+
+  g_mutex_lock (&dconf_mock_gvdb_lock);
+  dconf_mock_gvdb_init ();
+  hash_table = g_hash_table_lookup (dconf_mock_gvdb_tables, filename);
+  if (hash_table)
+      g_hash_table_ref (hash_table);
+  g_mutex_unlock (&dconf_mock_gvdb_lock);
+
+  if (hash_table == NULL)
+    g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "this gvdb does not exist");
+
+  return (GvdbTable *) hash_table;
 }
 
 gboolean
diff --git a/tests/dconf-mock-shm.c b/tests/dconf-mock-shm.c
index 3e9c38d..588667e 100644
--- a/tests/dconf-mock-shm.c
+++ b/tests/dconf-mock-shm.c
@@ -10,6 +10,7 @@ typedef struct
 
 static GHashTable *dconf_mock_shm_table;
 static GMutex      dconf_mock_shm_lock;
+static GString    *dconf_mock_shm_log;
 
 static void
 dconf_mock_shm_unref (gpointer data)
@@ -36,7 +37,10 @@ dconf_shm_open (const gchar *name)
   g_mutex_lock (&dconf_mock_shm_lock);
 
   if G_UNLIKELY (dconf_mock_shm_table == NULL)
-    dconf_mock_shm_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, dconf_mock_shm_unref);
+    {
+      dconf_mock_shm_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, dconf_mock_shm_unref);
+      dconf_mock_shm_log = g_string_new (NULL);
+    }
 
   shm = g_hash_table_lookup (dconf_mock_shm_table, name);
   if (shm == NULL)
@@ -48,6 +52,8 @@ dconf_shm_open (const gchar *name)
   /* before unlocking... */
   dconf_mock_shm_ref (shm);
 
+  g_string_append_printf (dconf_mock_shm_log, "open %s;", name);
+
   g_mutex_unlock (&dconf_mock_shm_lock);
 
   return &shm->flagged;
@@ -57,7 +63,32 @@ void
 dconf_shm_close (guint8 *shm)
 {
   if (shm)
-    dconf_mock_shm_unref (shm);
+    {
+      g_mutex_lock (&dconf_mock_shm_lock);
+      g_string_append (dconf_mock_shm_log, "close;");
+      g_mutex_unlock (&dconf_mock_shm_lock);
+
+      dconf_mock_shm_unref (shm);
+    }
+}
+
+gint
+dconf_mock_shm_flag (const gchar *name)
+{
+  DConfMockShm *shm;
+  gint count = 0;
+
+  g_mutex_lock (&dconf_mock_shm_lock);
+  shm = g_hash_table_lookup (dconf_mock_shm_table, name);
+  if (shm)
+    {
+      shm->flagged = 1;
+      count = shm->ref_count;
+      g_hash_table_remove (dconf_mock_shm_table, name);
+    }
+  g_mutex_unlock (&dconf_mock_shm_lock);
+
+  return count;
 }
 
 void
@@ -77,6 +108,17 @@ dconf_mock_shm_reset (void)
           g_assert_cmpint (shm->ref_count, ==, 1);
           g_hash_table_iter_remove (&iter);
         }
+
+      g_string_truncate (dconf_mock_shm_log, 0);
     }
   g_mutex_unlock (&dconf_mock_shm_lock);
 }
+
+void
+dconf_mock_shm_assert_log (const gchar *expected_log)
+{
+  g_mutex_lock (&dconf_mock_shm_lock);
+  g_assert_cmpstr (dconf_mock_shm_log->str, ==, expected_log);
+  g_string_truncate (dconf_mock_shm_log, 0);
+  g_mutex_unlock (&dconf_mock_shm_lock);
+}
diff --git a/tests/dconf-mock.h b/tests/dconf-mock.h
index 8ce7f1f..81c41c4 100644
--- a/tests/dconf-mock.h
+++ b/tests/dconf-mock.h
@@ -2,5 +2,17 @@
 #define __dconf_mock_h__
 
 void                    dconf_mock_shm_reset                            (void);
+gint                    dconf_mock_shm_flag                             (const gchar *name);
+void                    dconf_mock_shm_assert_log                       (const gchar *expected_log);
+
+typedef struct _DConfMockGvdbTable                          DConfMockGvdbTable;
+
+DConfMockGvdbTable *    dconf_mock_gvdb_table_new                       (void);
+void                    dconf_mock_gvdb_table_insert                    (DConfMockGvdbTable *table,
+                                                                         const gchar        *name,
+                                                                         GVariant           *value,
+                                                                         DConfMockGvdbTable *subtable);
+void                    dconf_mock_gvdb_install                         (const gchar        *filename,
+                                                                         DConfMockGvdbTable *table);
 
 #endif
diff --git a/tests/engine.c b/tests/engine.c
index ea29e37..4ac0a2e 100644
--- a/tests/engine.c
+++ b/tests/engine.c
@@ -224,9 +224,105 @@ test_signal_threadsafety (void)
   dconf_mock_shm_reset ();
 }
 
+static void
+test_user_source (void)
+{
+  DConfEngineSource *source;
+  DConfMockGvdbTable *table;
+  DConfMockGvdbTable *locks;
+  gboolean reopened;
+
+  source = dconf_engine_source_new ("user-db:user");
+  g_assert (source != NULL);
+
+  /* Create the source from a clean slate */
+  dconf_engine_source_init (source);
+  g_assert (source->values == NULL);
+  g_assert (source->locks == NULL);
+  dconf_mock_shm_assert_log ("open user;");
+
+  /* Try to refresh it.  There must be no IO at this point. */
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (!reopened);
+  dconf_mock_shm_assert_log ("");
+
+  /* Add a real database. */
+  table = dconf_mock_gvdb_table_new ();
+  dconf_mock_gvdb_table_insert (table, "/values/int32", g_variant_new_int32 (123456), NULL);
+  dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table);
+
+  /* Try to refresh it again.
+   * Because we didn't flag the change there must still be no IO.
+   */
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (!reopened);
+  g_assert (source->values == NULL);
+  g_assert (source->locks == NULL);
+  dconf_mock_shm_assert_log ("");
+
+  /* Now flag it and reopen. */
+  dconf_mock_shm_flag ("user");
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (reopened);
+  g_assert (source->values != NULL);
+  g_assert (source->locks == NULL);
+  g_assert (gvdb_table_has_value (source->values, "/values/int32"));
+  dconf_mock_shm_assert_log ("close;open user;");
+
+  /* Do it again -- should get the same result, after some IO */
+  dconf_mock_shm_flag ("user");
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (reopened);
+  g_assert (source->values != NULL);
+  g_assert (source->locks == NULL);
+  dconf_mock_shm_assert_log ("close;open user;");
+
+  /* "Delete" the gvdb and make sure dconf notices after a flag */
+  dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL);
+  dconf_mock_shm_flag ("user");
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (reopened);
+  g_assert (source->values == NULL);
+  g_assert (source->locks == NULL);
+  dconf_mock_shm_assert_log ("close;open user;");
+
+  /* Add a gvdb with a lock */
+  table = dconf_mock_gvdb_table_new ();
+  locks = dconf_mock_gvdb_table_new ();
+  dconf_mock_gvdb_table_insert (table, "/values/int32", g_variant_new_int32 (123456), NULL);
+  dconf_mock_gvdb_table_insert (locks, "/values/int32", g_variant_new_boolean (TRUE), NULL);
+  dconf_mock_gvdb_table_insert (table, ".locks", NULL, locks);
+  dconf_mock_gvdb_install ("/HOME/.config/dconf/user", table);
+
+  /* Reopen and check if we have the lock */
+  dconf_mock_shm_flag ("user");
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (reopened);
+  g_assert (source->values != NULL);
+  g_assert (source->locks != NULL);
+  g_assert (gvdb_table_has_value (source->values, "/values/int32"));
+  g_assert (gvdb_table_has_value (source->locks, "/values/int32"));
+  dconf_mock_shm_assert_log ("close;open user;");
+
+  /* Reopen one last time */
+  dconf_mock_shm_flag ("user");
+  reopened = dconf_engine_source_refresh (source);
+  g_assert (reopened);
+  g_assert (source->values != NULL);
+  g_assert (source->locks != NULL);
+  dconf_mock_shm_assert_log ("close;open user;");
+
+  dconf_engine_source_free (source);
+  dconf_mock_shm_assert_log ("close;");
+
+  dconf_mock_gvdb_install ("/HOME/.config/dconf/user", NULL);
+  dconf_mock_shm_reset ();
+}
+
 int
 main (int argc, char **argv)
 {
+  g_setenv ("XDG_CONFIG_HOME", "/HOME/.config", TRUE);
   g_unsetenv ("DCONF_PROFILE");
 
   main_thread = g_thread_self ();
@@ -235,6 +331,7 @@ main (int argc, char **argv)
 
   g_test_add_func ("/engine/profile-parser", test_profile_parser);
   g_test_add_func ("/engine/signal-threadsafety", test_signal_threadsafety);
+  g_test_add_func ("/engine/sources/user", test_user_source);
 
   return g_test_run ();
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]