summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-11-02 14:15:48 +0100
committerThomas Haller <thaller@redhat.com>2019-11-07 11:34:36 +0100
commit8def37dd65ae9dfec8d3faca36665c92ea91828f (patch)
treefccb5e0d5fb81c3b29d90f4624c8f79abc819c3e
parentec39498fc6d70cf6887f08b4dfbc5cff021fc231 (diff)
downloadNetworkManager-8def37dd65ae9dfec8d3faca36665c92ea91828f.tar.gz
tests: add nmtstc_client_new() helper
-rw-r--r--shared/nm-test-libnm-utils.h1
-rw-r--r--shared/nm-test-utils-impl.c148
2 files changed, 149 insertions, 0 deletions
diff --git a/shared/nm-test-libnm-utils.h b/shared/nm-test-libnm-utils.h
index 76e2a2158c..63e3b4c72c 100644
--- a/shared/nm-test-libnm-utils.h
+++ b/shared/nm-test-libnm-utils.h
@@ -67,3 +67,4 @@ void nmtstc_service_update_connection_variant (NMTstcServiceInfo *sinfo,
GVariant *connection,
gboolean verify_connection);
+NMClient *nmtstc_client_new (gboolean allow_iterate_main_context);
diff --git a/shared/nm-test-utils-impl.c b/shared/nm-test-utils-impl.c
index 39f0a08325..bbe74a9656 100644
--- a/shared/nm-test-utils-impl.c
+++ b/shared/nm-test-utils-impl.c
@@ -406,3 +406,151 @@ nmtstc_service_update_connection_variant (NMTstcServiceInfo *sinfo,
g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE ("()")));
g_variant_unref (result);
}
+
+/*****************************************************************************/
+
+typedef struct {
+ GMainLoop *loop;
+ NMClient *client;
+} NMTstcClientNewData;
+
+static void
+_nmtstc_client_new_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ NMTstcClientNewData *d = user_data;
+ gs_free_error GError *error = NULL;
+
+ g_assert (!d->client);
+
+ d->client = nm_client_new_finish (res,
+ nmtst_get_rand_bool () ? &error : NULL);
+
+ nmtst_assert_success (NM_IS_CLIENT (d->client), error);
+
+ g_main_loop_quit (d->loop);
+}
+
+static NMClient *
+_nmtstc_client_new (gboolean sync)
+{
+ gs_free GError *error = NULL;
+ NMClient *client;
+
+ /* Create a NMClient instance synchronously, and arbitrarily use either
+ * the sync or async constructor.
+ *
+ * Note that the sync and async construct differ in one important aspect:
+ * the async constructor iterates the current g_main_context_get_thread_default(),
+ * while the sync constructor does not! Aside from that, both should behave
+ * pretty much the same way. */
+
+ if (sync) {
+ nm_auto_destroy_and_unref_gsource GSource *source = NULL;
+
+ if (nmtst_get_rand_bool ()) {
+ /* the current main context must not be iterated! */
+ source = g_idle_source_new ();
+ g_source_set_callback (source, nmtst_g_source_assert_not_called, NULL, NULL);
+ g_source_attach (source, g_main_context_get_thread_default ());
+ }
+
+ if (nmtst_get_rand_bool ()) {
+ gboolean success;
+
+ client = g_object_new (NM_TYPE_CLIENT, NULL);
+ g_assert (NM_IS_CLIENT (client));
+
+ success = g_initable_init (G_INITABLE (client),
+ NULL,
+ nmtst_get_rand_bool () ? &error : NULL);
+ nmtst_assert_success (success, error);
+ } else {
+ client = nm_client_new (NULL,
+ nmtst_get_rand_bool () ? &error : NULL);
+ }
+ } else {
+ nm_auto_unref_gmainloop GMainLoop *loop = NULL;
+ NMTstcClientNewData d = { .loop = NULL, };
+
+ loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
+
+ d.loop = loop;
+ nm_client_new_async (NULL,
+ _nmtstc_client_new_cb,
+ &d);
+ g_main_loop_run (loop);
+ g_assert (NM_IS_CLIENT (d.client));
+ client = d.client;
+ }
+
+ nmtst_assert_success (NM_IS_CLIENT (client), error);
+ return client;
+}
+
+typedef struct {
+ GMainLoop *loop;
+ NMClient *client;
+ bool sync;
+} NewSyncInsideDispatchedData;
+
+static gboolean
+_nmtstc_client_new_inside_loop_do (gpointer user_data)
+{
+ NewSyncInsideDispatchedData *d = user_data;
+
+ g_assert (d->loop);
+ g_assert (!d->client);
+
+ d->client = nmtstc_client_new (d->sync);
+ g_main_loop_quit (d->loop);
+ return G_SOURCE_CONTINUE;
+}
+
+static NMClient *
+_nmtstc_client_new_inside_loop (gboolean sync)
+{
+ GMainContext *context = g_main_context_get_thread_default ();
+ nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new (context, FALSE);
+ NewSyncInsideDispatchedData d = {
+ .sync = sync,
+ .loop = loop,
+ };
+ nm_auto_destroy_and_unref_gsource GSource *source = NULL;
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, _nmtstc_client_new_inside_loop_do, &d, NULL);
+ g_source_attach (source, context);
+
+ g_main_loop_run (loop);
+ g_assert (NM_IS_CLIENT (d.client));
+ return d.client;
+}
+
+NMClient *
+nmtstc_client_new (gboolean allow_iterate_main_context)
+{
+ gboolean inside_loop;
+ gboolean sync;
+
+ if (!allow_iterate_main_context) {
+ sync = TRUE;
+ inside_loop = FALSE;
+ } else {
+ /* The caller allows to iterate the main context. That that point,
+ * we can both use the synchronous and the asynchronous initialization,
+ * both should yield the same result. Choose one randomly. */
+ sync = nmtst_get_rand_bool ();
+ inside_loop = ((nmtst_get_rand_uint32 () % 3) == 0);
+ }
+
+ if (inside_loop) {
+ /* Create the client on an idle handler of the current context.
+ * In practice, it should make no difference, which this check
+ * tries to prove. */
+ return _nmtstc_client_new_inside_loop (sync);
+ }
+
+ return _nmtstc_client_new (sync);
+}