[libdazzle] tests: rewrite recursive monitor test for accuracy
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libdazzle] tests: rewrite recursive monitor test for accuracy
- Date: Fri, 1 Dec 2017 04:25:10 +0000 (UTC)
commit 72cea3ea66fcbc039d504b5c2a5d197cbfaafb48
Author: Christian Hergert <chergert redhat com>
Date: Thu Nov 30 20:24:38 2017 -0800
tests: rewrite recursive monitor test for accuracy
This tries much harder to avoid the races in the process of testing our
recursive directory monitor.
tests/meson.build | 4 +-
tests/test-recursive-monitor.c | 210 ++++++++++++++++++++++++++--------------
2 files changed, 137 insertions(+), 77 deletions(-)
---
diff --git a/tests/meson.build b/tests/meson.build
index 79bcd69..e037414 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -343,13 +343,11 @@ test_pattern_spec = executable('test-pattern-spec', 'test-pattern-spec.c',
)
test('test-pattern-spec', test_pattern_spec, env: test_env)
-# Test is not automated because file system notification is fairly
-# racey due to what else is going on with the system and how big
-# the notification queue depth is.
test_recursive_monitor = executable('test-recursive-monitor', 'test-recursive-monitor.c',
c_args: test_cflags,
link_args: test_link_args,
dependencies: libdazzle_deps + [libdazzle_dep],
)
+test('test-recursive-monitor', test_recursive_monitor, env: test_env)
endif
diff --git a/tests/test-recursive-monitor.c b/tests/test-recursive-monitor.c
index be6edc9..c77cc6a 100644
--- a/tests/test-recursive-monitor.c
+++ b/tests/test-recursive-monitor.c
@@ -3,36 +3,92 @@
static const gchar *layer1[] = { "a", "b", "c", "d", "e", "f", "g", "h", "i", NULL };
static const gchar *layer2[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", NULL };
-static GMainLoop *main_loop;
-static GHashTable *created;
-static GHashTable *deleted;
-static void
-sync_for_changes (void)
-{
- GMainContext *context = g_main_loop_get_context (main_loop);
- gint64 enter = g_get_monotonic_time ();
+enum {
+ MODE_CREATE,
+ MODE_DELETE,
+};
- /*
- * we need to spin a little bit while we wait for things
- * to complete.
- */
+typedef struct
+{
+ GMainLoop *main_loop;
+ DzlRecursiveFileMonitor *monitor;
+ GHashTable *created;
+ GHashTable *deleted;
+ GQueue dirs;
+ GList *iter;
+ guint mode : 1;
+ guint did_action : 1;
+} BasicState;
+
+static gboolean
+failed_timeout (gpointer state)
+{
+ /* timed out */
+ g_assert_not_reached ();
+ return G_SOURCE_REMOVE;
+}
- for (;;)
- {
- gint64 now;
+static gboolean
+begin_test_basic (gpointer data)
+{
+ g_autoptr(GError) error = NULL;
+ BasicState *state = data;
+ GFile *current;
+ gboolean r;
- if (g_main_context_pending (context))
- g_main_context_iteration (context, FALSE);
+ g_assert (state != NULL);
+ g_assert (state->iter != NULL);
+ g_assert (state->iter->data != NULL);
+ g_assert (G_IS_FILE (state->iter->data));
- now = g_get_monotonic_time ();
+ current = state->iter->data;
- /* Spin at least a milliseconds */
- if ((now - enter) > (G_USEC_PER_SEC / 1000))
- break;
+ if (state->mode == MODE_CREATE)
+ {
+ if (g_hash_table_contains (state->created, current))
+ {
+ state->iter = state->iter->next;
+ state->did_action = FALSE;
+
+ if (state->iter == NULL)
+ {
+ state->mode = MODE_DELETE;
+ state->iter = state->dirs.tail;
+ }
+ }
+ else if (!state->did_action)
+ {
+ state->did_action = TRUE;
+ r = g_file_make_directory (current, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (r, ==, TRUE);
+ }
}
+ else if (state->mode == MODE_DELETE)
+ {
+ if (g_hash_table_contains (state->deleted, current))
+ {
+ state->iter = state->iter->prev;
+ state->did_action = FALSE;
+
+ if (state->iter == NULL)
+ {
+ g_main_loop_quit (state->main_loop);
+ return G_SOURCE_REMOVE;
+ }
+ }
+ else if (!state->did_action)
+ {
+ state->did_action = TRUE;
+ g_file_delete (current, NULL, &error);
+ g_assert_no_error (error);
+ }
+ }
+ else
+ g_assert_not_reached ();
- g_main_context_iteration (context, FALSE);
+ return G_SOURCE_CONTINUE;
}
static void
@@ -42,27 +98,60 @@ monitor_changed_cb (DzlRecursiveFileMonitor *monitor,
GFileMonitorEvent event,
gpointer data)
{
- sync_for_changes ();
+ BasicState *state = data;
if (event == G_FILE_MONITOR_EVENT_CREATED)
- g_hash_table_insert (created, g_object_ref (file), NULL);
+ g_hash_table_insert (state->created, g_object_ref (file), NULL);
else if (event == G_FILE_MONITOR_EVENT_DELETED)
- g_hash_table_insert (deleted, g_object_ref (file), NULL);
+ g_hash_table_insert (state->deleted, g_object_ref (file), NULL);
+}
+
+static void
+started_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DzlRecursiveFileMonitor *monitor = (DzlRecursiveFileMonitor *)object;
+ BasicState *state = user_data;
+ g_autoptr(GError) error = NULL;
+ gboolean r;
+
+ g_assert (DZL_IS_RECURSIVE_FILE_MONITOR (monitor));
+
+ r = dzl_recursive_file_monitor_start_finish (monitor, result, &error);
+ g_assert_no_error (error);
+ g_assert_cmpint (r, ==, TRUE);
+
+ /*
+ * Now start the async test processing. We use a very
+ * low priority idle to ensure other things process before us.
+ */
+
+ state->iter = state->dirs.head;
+ state->did_action = FALSE;
+ state->mode = MODE_CREATE;
+ g_idle_add_full (G_MAXINT, begin_test_basic, state, NULL);
}
static void
test_basic (void)
{
- g_autoptr(DzlRecursiveFileMonitor) monitor = NULL;
g_autoptr(GFile) dir = g_file_new_for_path ("recursive-dir");
- g_autoptr(GPtrArray) dirs = NULL;
+ BasicState state = { 0 };
gint r;
- main_loop = g_main_loop_new (NULL, FALSE);
-
- created = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref);
- deleted = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref);
-
+ state.main_loop = g_main_loop_new (NULL, FALSE);
+ g_queue_init (&state.dirs);
+ state.created = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc) g_file_equal,
+ g_object_unref,
+ g_object_unref);
+ state.deleted = g_hash_table_new_full (g_file_hash,
+ (GEqualFunc) g_file_equal,
+ g_object_unref,
+ g_object_unref);
+
+ /* Cleanup any previously failed run */
if (g_file_test ("recursive-dir", G_FILE_TEST_EXISTS))
{
g_autoptr(DzlDirectoryReaper) reaper = dzl_directory_reaper_new ();
@@ -74,62 +163,35 @@ test_basic (void)
g_assert_cmpint (r, ==, 0);
}
+ /* Create our root directory to use */
r = g_mkdir ("recursive-dir", 0750);
g_assert_cmpint (r, ==, 0);
- monitor = dzl_recursive_file_monitor_new (dir);
- g_assert (monitor != NULL);
- sync_for_changes ();
-
- g_signal_connect (monitor,
- "changed",
- G_CALLBACK (monitor_changed_cb),
- NULL);
-
- /* Make a bunch of directories while we monitor. We'll add files to
- * the directories afterwards, and then ensure we got notified. This
- * allows us to ensure that we track changes as we add dirs.
- */
- dirs = g_ptr_array_new_with_free_func (g_object_unref);
-
+ /* Build our list of directories to create/test */
for (guint i = 0; layer1[i]; i++)
{
- g_autofree gchar *first = g_build_filename ("recursive-dir", layer1[i], NULL);
- g_autoptr(GFile) file1 = g_file_new_for_path (first);
-
- r = g_mkdir (first, 0750);
- g_assert_cmpint (r, ==, 0);
- sync_for_changes ();
+ g_autoptr(GFile) file1 = g_file_new_build_filename ("recursive-dir", layer1[i], NULL);
- g_ptr_array_add (dirs, g_object_ref (file1));
-
- g_assert (g_hash_table_contains (created, file1));
+ g_queue_push_tail (&state.dirs, g_object_ref (file1));
for (guint j = 0; layer2[j]; j++)
{
- g_autofree gchar *second = g_build_filename (first, layer2[j], NULL);
- g_autoptr(GFile) file2 = g_file_new_for_path (second);
-
- r = g_mkdir (second, 0750);
- g_assert_cmpint (r, ==, 0);
- sync_for_changes ();
-
- g_assert (g_hash_table_contains (created, file2));
-
- g_ptr_array_add (dirs, g_object_ref (file2));
+ g_autoptr(GFile) file2 = g_file_get_child (file1, layer2[j]);
+ g_queue_push_tail (&state.dirs, g_steal_pointer (&file2));
}
}
- for (guint i = dirs->len; i > 0; i--)
- {
- GFile *file = g_ptr_array_index (dirs, i - 1);
+ state.monitor = dzl_recursive_file_monitor_new (dir);
+ g_signal_connect (state.monitor, "changed", G_CALLBACK (monitor_changed_cb), &state);
- r = g_file_delete (file, NULL, NULL);
- g_assert_cmpint (r, ==, TRUE);
- sync_for_changes ();
+ /* Add a timeout to avoid infinite running */
+ g_timeout_add_seconds (3, failed_timeout, &state);
- g_assert (g_hash_table_contains (deleted, file));
- }
+ dzl_recursive_file_monitor_start_async (state.monitor, NULL, started_cb, &state);
+
+ g_main_loop_run (state.main_loop);
+
+ dzl_recursive_file_monitor_cancel (state.monitor);
}
gint
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]