diff options
author | Garrett Regier <garrett.regier@riftio.com> | 2014-11-08 12:31:58 -0800 |
---|---|---|
committer | Garrett Regier <garrett.regier@riftio.com> | 2014-11-18 10:30:39 -0800 |
commit | 9a2b7a92741fd88fb059882c84eca9381246d554 (patch) | |
tree | 3927de976367d3086becc4e8be680c793ee4d69d /tests | |
parent | 47ff5e97b4066822b773c04a063914fecafb20bf (diff) | |
download | libpeas-9a2b7a92741fd88fb059882c84eca9381246d554.tar.gz |
Add an extension test that uses multiple threads
This should act as a good stress test for checking that
libpeas is thread-safe. This also changes testing-utils to
be thread aware.
https://bugzilla.gnome.org/show_bug.cgi?id=739619
Diffstat (limited to 'tests')
-rw-r--r-- | tests/libpeas/testing/testing-extension.c | 62 | ||||
-rw-r--r-- | tests/testing-util/testing-util.c | 92 |
2 files changed, 131 insertions, 23 deletions
diff --git a/tests/libpeas/testing/testing-extension.c b/tests/libpeas/testing/testing-extension.c index 2fd5dda..97e7dfc 100644 --- a/tests/libpeas/testing/testing-extension.c +++ b/tests/libpeas/testing/testing-extension.c @@ -270,6 +270,64 @@ test_extension_get_settings (PeasEngine *engine, } static void +multiple_threads_in_thread (guint nth_thread) +{ + gint i, j; + PeasEngine *engine; + PeasPluginInfo *info; + GObject *extension; + const gboolean is_slow = strstr (loader, "python") != NULL; + + engine = testing_engine_new (); + peas_engine_enable_loader (engine, loader); + + info = peas_engine_get_plugin_info (engine, extension_plugin); + g_assert (info != NULL); + + for (i = 0; i < (is_slow ? 5 : 20); ++i) + { + g_assert (peas_engine_load_plugin (engine, info)); + + for (j = 0; j < 5; ++j) + { + extension = peas_engine_create_extension (engine, info, + INTROSPECTION_TYPE_BASE, + NULL); + + g_assert (extension != NULL); + g_object_unref (extension); + } + + g_assert (peas_engine_unload_plugin (engine, info)); + } + + testing_engine_free (engine); +} + +static void +test_extension_multiple_threads (PeasEngine *engine, + PeasPluginInfo *info) +{ + gint i; + GThreadPool *pool; + GError *error = NULL; + const gboolean is_slow = strstr (loader, "python") != NULL; + + pool = g_thread_pool_new ((GFunc) multiple_threads_in_thread, + NULL, g_get_num_processors (), TRUE, &error); + g_assert_no_error (error); + + for (i = 0; i < (is_slow ? 20 : 100); ++i) + { + /* Cannot supply NULL as the data... */ + g_thread_pool_push (pool, GUINT_TO_POINTER (i + 1), &error); + g_assert_no_error (error); + } + + g_thread_pool_free (pool, FALSE, TRUE); +} + +static void test_extension_call_no_args (PeasEngine *engine, PeasPluginInfo *info) { @@ -428,6 +486,10 @@ testing_extension_basic (const gchar *loader_) _EXTENSION_TEST (loader, "plugin-info", plugin_info); _EXTENSION_TEST (loader, "get-settings", get_settings); + + /* See peas_engine_enable_loader() */ + if (g_strcmp0 (loader, "lua5.1") != 0) + _EXTENSION_TEST (loader, "multiple-threads", multiple_threads); } void diff --git a/tests/testing-util/testing-util.c b/tests/testing-util/testing-util.c index e67b502..bd0f839 100644 --- a/tests/testing-util/testing-util.c +++ b/tests/testing-util/testing-util.c @@ -37,10 +37,17 @@ typedef struct { gboolean hit; } LogHook; -static PeasEngine *engine = NULL; -static GPtrArray *log_hooks = NULL; +static void engine_private_notify (gpointer value); +static void log_hooks_private_notify (gpointer value); + static gboolean initialized = FALSE; +static gpointer dead_engine = NULL; +#define DEAD_ENGINE ((gpointer) &dead_engine) + +static GPrivate engine_key = G_PRIVATE_INIT (engine_private_notify); +static GPrivate log_hooks_key = G_PRIVATE_INIT (log_hooks_private_notify); + /* These are warnings and criticals that just have to happen * for testing purposes and as such we don't want to abort on them. * @@ -55,11 +62,47 @@ static const gchar *allowed_patterns[] = { }; static void +engine_private_notify (gpointer value) +{ + if (value != NULL) + g_error ("A PeasEngine was not freed!"); +} + +static void +log_hooks_private_notify (gpointer value) +{ + GPtrArray *log_hooks = value; + + if (log_hooks != NULL) + { + g_assert_cmpuint (log_hooks->len, ==, 0); + g_ptr_array_unref (log_hooks); + } +} + +static GPtrArray * +get_log_hooks (void) +{ + GPtrArray *log_hooks = g_private_get (&log_hooks_key); + + if (log_hooks != NULL) + return log_hooks; + + g_assert (initialized); + + log_hooks = g_ptr_array_new_with_free_func (g_free); + g_private_set (&log_hooks_key, log_hooks); + + return log_hooks; +} + +static void log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { + GPtrArray *log_hooks = get_log_hooks (); guint i; /* We always want to log debug, info and message logs */ @@ -148,25 +191,36 @@ testing_util_init (void) g_irepository_require (g_irepository_get_default (), "Peas", "1.0", 0, &error); g_assert_no_error (error); - log_hooks = g_ptr_array_new_with_free_func (g_free); - initialized = TRUE; } +static void +engine_weak_notify (gpointer unused, + PeasEngine *engine) +{ + /* Cannot use NULL because testing_util_engine_free() must be called */ + g_private_set (&engine_key, DEAD_ENGINE); +} + PeasEngine * testing_util_engine_new (void) { + PeasEngine *engine; + g_assert (initialized); /* testing_util_engine_free() checks that the * engine is freed so only one engine can be created */ - g_assert (engine == NULL); + g_assert (g_private_get (&engine_key) == NULL); /* Must be after requiring typelibs */ engine = peas_engine_new (); + g_private_set (&engine_key, engine); - g_object_add_weak_pointer (G_OBJECT (engine), (gpointer *) &engine); + g_object_weak_ref (G_OBJECT (engine), + (GWeakNotify) engine_weak_notify, + NULL); peas_engine_add_search_path (engine, BUILDDIR "/tests/plugins", SRCDIR "/tests/plugins"); @@ -175,17 +229,19 @@ testing_util_engine_new (void) } void -testing_util_engine_free (PeasEngine *engine_) +testing_util_engine_free (PeasEngine *engine) { /* In case a test needs to free the engine */ - if (engine != NULL) + if (g_private_get (&engine_key) != DEAD_ENGINE) { - g_object_unref (engine_); + g_object_unref (engine); /* Make sure that at the end of every test the engine is freed */ - g_assert (engine == NULL); + g_assert (g_private_get (&engine_key) == DEAD_ENGINE); } + g_private_set (&engine_key, NULL); + /* Pop the log hooks so the test cases don't have to */ testing_util_pop_log_hooks (); } @@ -199,15 +255,6 @@ testing_util_run_tests (void) retval = g_test_run (); - /* Make sure all the engines have been freed */ - g_assert (engine == NULL); - - if (log_hooks != NULL) - { - g_assert_cmpuint (log_hooks->len, ==, 0); - g_ptr_array_unref (log_hooks); - } - /* Cannot call this with atexit() because * gcov does not register that it was called. */ @@ -219,9 +266,9 @@ testing_util_run_tests (void) void testing_util_push_log_hook (const gchar *pattern) { + GPtrArray *log_hooks = get_log_hooks (); LogHook *hook; - g_return_if_fail (log_hooks != NULL); g_return_if_fail (pattern != NULL && *pattern != '\0'); hook = g_new (LogHook, 1); @@ -235,9 +282,9 @@ testing_util_push_log_hook (const gchar *pattern) void testing_util_pop_log_hook (void) { + GPtrArray *log_hooks = get_log_hooks (); LogHook *hook; - g_return_if_fail (log_hooks != NULL); g_return_if_fail (log_hooks->len > 0); hook = g_ptr_array_index (log_hooks, log_hooks->len - 1); @@ -251,12 +298,11 @@ testing_util_pop_log_hook (void) void testing_util_pop_log_hooks (void) { + GPtrArray *log_hooks = get_log_hooks (); guint i; LogHook *hook; GPtrArray *unhit_hooks; - g_return_if_fail (log_hooks != NULL); - if (log_hooks->len == 0) return; |