diff --git a/lib/wp/session-item.c b/lib/wp/session-item.c index a0e015be97d320340678881acb86c89d4254e1f6..6ef53ab0b129ed3c6ade52cf3b8317a360a341d2 100644 --- a/lib/wp/session-item.c +++ b/lib/wp/session-item.c @@ -178,9 +178,7 @@ wp_session_item_default_execute_step (WpSessionItem * self, { switch (step) { case WP_TRANSITION_STEP_NONE: - break; case WP_TRANSITION_STEP_ERROR: - wp_session_item_reset (self); break; default: g_return_if_reached (); @@ -578,7 +576,7 @@ wp_session_item_configure (WpSessionItem * self, GVariant * args) g_return_val_if_fail (WP_IS_SESSION_ITEM (self), FALSE); g_return_val_if_fail (WP_SESSION_ITEM_GET_CLASS (self)->configure, FALSE); - g_return_val_if_fail (g_variant_is_of_type (args, G_VARIANT_TYPE ("a{sv}")), + g_return_val_if_fail (g_variant_is_of_type (args, G_VARIANT_TYPE_VARDICT), FALSE); return WP_SESSION_ITEM_GET_CLASS (self)->configure (self, args); diff --git a/modules/module-si-adapter.c b/modules/module-si-adapter.c index 1b8ebde1db28cca7090c6deb9f7b49041b14fff8..3c4b6c87c9f225d27e4e85db58eb3bd23104f9c9 100644 --- a/modules/module-si-adapter.c +++ b/modules/module-si-adapter.c @@ -354,7 +354,7 @@ si_adapter_execute_step (WpSessionItem * item, WpTransition * transition, break; } default: - WP_SESSION_ITEM_GET_CLASS (si_adapter_parent_class)->execute_step (item, + WP_SESSION_ITEM_CLASS (si_adapter_parent_class)->execute_step (item, transition, step); break; } diff --git a/modules/module-si-standard-link.c b/modules/module-si-standard-link.c index 973cee37466f69a259b92700fec1bde6fc9a4f1f..f03a45339f358f0bc855ac3d3bebaa924985533c 100644 --- a/modules/module-si-standard-link.c +++ b/modules/module-si-standard-link.c @@ -374,7 +374,7 @@ si_standard_link_execute_step (WpSessionItem * item, WpTransition * transition, break; } default: - WP_SESSION_ITEM_GET_CLASS (si_standard_link_parent_class)->execute_step ( + WP_SESSION_ITEM_CLASS (si_standard_link_parent_class)->execute_step ( item, transition, step); break; } diff --git a/tests/wp/meson.build b/tests/wp/meson.build index 2dff1c91738d886ca0e416e8fe4f42d23bc4e9d8..c0f9f4eea9a39d59afb1c67b9c4cd3db4fb0a848 100644 --- a/tests/wp/meson.build +++ b/tests/wp/meson.build @@ -35,6 +35,13 @@ test( env: common_env, ) +test( + 'test-session-item', + executable('test-session-item', 'session-item.c', + dependencies: common_deps, c_args: common_args), + env: common_env, +) + test( 'test-spa-pod', executable('test-spa-pod', 'spa-pod.c', diff --git a/tests/wp/session-item.c b/tests/wp/session-item.c new file mode 100644 index 0000000000000000000000000000000000000000..6cca612329023b731a781a188aaf42fa9d3f3c3d --- /dev/null +++ b/tests/wp/session-item.c @@ -0,0 +1,338 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author George Kiagiadakis <george.kiagiadakis@collabora.com> + * + * SPDX-License-Identifier: MIT + */ + +#include <wp/wp.h> + +G_DEFINE_QUARK (test-domain, test_domain) + +enum { + STEP_1 = WP_TRANSITION_STEP_CUSTOM_START, + STEP_2, +}; + +struct _TestSiDummy +{ + WpSessionItem parent; + gboolean fail; + gboolean step_1_done; + gboolean step_2_done; + gboolean cleaned_up; +}; + +G_DECLARE_FINAL_TYPE (TestSiDummy, si_dummy, TEST, SI_DUMMY, WpSessionItem) +G_DEFINE_TYPE (TestSiDummy, si_dummy, WP_TYPE_SESSION_ITEM) + +static void +si_dummy_init (TestSiDummy * self) +{ +} + +static GVariant * +si_dummy_get_configuration (WpSessionItem * item) +{ + TestSiDummy *self = TEST_SI_DUMMY (item); + GVariantBuilder b; + g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", + "fail", g_variant_new_boolean (self->fail)); + return g_variant_builder_end (&b); +} + +static gboolean +si_dummy_configure (WpSessionItem * item, GVariant * args) +{ + TestSiDummy *self = TEST_SI_DUMMY (item); + + if (wp_session_item_get_flags (item) & (WP_SI_FLAG_ACTIVATING | WP_SI_FLAG_ACTIVE)) + return FALSE; + + g_variant_lookup (args, "fail", "b", &self->fail); + wp_session_item_set_flag (item, WP_SI_FLAG_CONFIGURED); + + return TRUE; +} + +static guint +si_dummy_get_next_step (WpSessionItem * item, + WpTransition * transition, guint step) +{ + switch (step) { + case WP_TRANSITION_STEP_NONE: + return STEP_1; + case STEP_1: + return STEP_2; + case STEP_2: + return WP_TRANSITION_STEP_NONE; + default: + return WP_TRANSITION_STEP_ERROR; + } +} + +static gboolean +si_dummy_step_1 (gpointer data) +{ + WpTransition *transition = data; + g_assert_true (WP_IS_TRANSITION (transition)); + + TestSiDummy *self = wp_transition_get_source_object (transition); + g_assert_true (TEST_IS_SI_DUMMY (self)); + + self->step_1_done = TRUE; + + if (self->fail) + wp_transition_return_error (transition, + g_error_new (test_domain_quark (), 0, "error")); + else + wp_transition_advance (transition); + + return G_SOURCE_REMOVE; +} + +static void +si_dummy_execute_step (WpSessionItem * item, WpTransition * transition, + guint step) +{ + TestSiDummy *self = TEST_SI_DUMMY (item); + + switch (step) { + case STEP_1: + /* execute async */ + g_idle_add (si_dummy_step_1, transition); + break; + + case STEP_2: + /* execute sync */ + self->step_2_done = TRUE; + wp_transition_advance (transition); + break; + + case WP_TRANSITION_STEP_ERROR: + self->cleaned_up = TRUE; + self->step_1_done = FALSE; + self->step_2_done = FALSE; + WP_SESSION_ITEM_CLASS (si_dummy_parent_class)->execute_step (item, + transition, step); + break; + + default: + g_assert_not_reached (); + } +} + +static void +si_dummy_deactivate (WpSessionItem * item) +{ + TestSiDummy *self = TEST_SI_DUMMY (item); + + self->cleaned_up = FALSE; + self->step_1_done = FALSE; + self->step_2_done = FALSE; + + WP_SESSION_ITEM_CLASS (si_dummy_parent_class)->deactivate (item); +} + +static void +si_dummy_class_init (TestSiDummyClass * klass) +{ + WpSessionItemClass *si_class = (WpSessionItemClass *) klass; + + si_class->configure = si_dummy_configure; + si_class->get_configuration = si_dummy_get_configuration; + si_class->get_next_step = si_dummy_get_next_step; + si_class->execute_step = si_dummy_execute_step; + si_class->deactivate = si_dummy_deactivate; +} + +static void +expect_flags (WpSessionItem * item, WpSiFlags flags, WpSiFlags *signalled_flags) +{ + *signalled_flags = flags; +} + +static void +test_flags (void) +{ + g_autoptr (WpSessionItem) item = NULL; + WpSiFlags signalled_flags = 0; + + item = g_object_new (si_dummy_get_type (), NULL); + g_assert_cmpint (wp_session_item_get_flags (item), ==, 0); + + g_signal_connect (item, "flags-changed", G_CALLBACK (expect_flags), + &signalled_flags); + wp_session_item_set_flag (item, WP_SI_FLAG_CUSTOM_START); + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_CUSTOM_START); + g_assert_cmpint (signalled_flags, ==, WP_SI_FLAG_CUSTOM_START); + + /* internal flag, cannot be set */ + signalled_flags = 0; + wp_session_item_set_flag (item, WP_SI_FLAG_ACTIVATING); + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_CUSTOM_START); + g_assert_cmpint (signalled_flags, ==, 0); + + signalled_flags = WP_SI_FLAG_CUSTOM_START; + wp_session_item_clear_flag (item, WP_SI_FLAG_CUSTOM_START); + g_assert_cmpint (wp_session_item_get_flags (item), ==, 0); + g_assert_cmpint (signalled_flags, ==, 0); +} + +static void +test_configuration (void) +{ + g_autoptr (WpSessionItem) item = NULL; + g_autoptr (GVariant) v = NULL; + WpSiFlags signalled_flags = 0; + gboolean fail = FALSE; + GVariantBuilder b; + + item = g_object_new (si_dummy_get_type (), NULL); + g_signal_connect (item, "flags-changed", G_CALLBACK (expect_flags), + &signalled_flags); + + g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "fail", g_variant_new_boolean (TRUE)); + g_assert_true (wp_session_item_configure (item, g_variant_builder_end (&b))); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_CONFIGURED); + g_assert_cmpint (signalled_flags, ==, WP_SI_FLAG_CONFIGURED); + + v = wp_session_item_get_configuration (item); + g_assert_nonnull (v); + g_assert_true (g_variant_is_of_type (v, G_VARIANT_TYPE_VARDICT)); + g_assert_true (g_variant_lookup (v, "fail", "b", &fail)); + g_assert_true (fail); +} + +static void +expect_activate_success (WpSessionItem * item, GAsyncResult * res, gpointer data) +{ + GMainLoop *loop = data; + g_autoptr (GError) error = NULL; + + g_assert_true (TEST_IS_SI_DUMMY (item)); + g_assert_true (g_async_result_is_tagged (res, wp_session_item_activate)); + g_assert_true (wp_session_item_activate_finish (item, res, &error)); + g_assert_no_error (error); + + g_main_loop_quit (loop); +} + +static void +test_activation (void) +{ + g_autoptr (WpSessionItem) item = NULL; + g_autoptr (GMainLoop) loop = NULL; + WpSiFlags signalled_flags = 0; + TestSiDummy *dummy; + + loop = g_main_loop_new (NULL, FALSE); + item = g_object_new (si_dummy_get_type (), NULL); + dummy = TEST_SI_DUMMY (item); + g_signal_connect (item, "flags-changed", G_CALLBACK (expect_flags), + &signalled_flags); + + wp_session_item_activate (item, + (GAsyncReadyCallback) expect_activate_success, loop); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_ACTIVATING); + g_assert_cmpint (signalled_flags, ==, WP_SI_FLAG_ACTIVATING); + + g_main_loop_run (loop); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_ACTIVE); + g_assert_cmpint (signalled_flags, ==, WP_SI_FLAG_ACTIVE); + g_assert_true (dummy->step_1_done); + g_assert_true (dummy->step_2_done); + g_assert_false (dummy->cleaned_up); + + wp_session_item_deactivate (item); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, 0); + g_assert_cmpint (signalled_flags, ==, 0); + g_assert_false (dummy->step_1_done); + g_assert_false (dummy->step_2_done); + g_assert_false (dummy->cleaned_up); +} + + +static void +expect_activate_failure (WpSessionItem * item, GAsyncResult * res, gpointer data) +{ + GMainLoop *loop = data; + g_autoptr (GError) error = NULL; + + g_assert_true (TEST_IS_SI_DUMMY (item)); + g_assert_true (g_async_result_is_tagged (res, wp_session_item_activate)); + g_assert_false (wp_session_item_activate_finish (item, res, &error)); + g_assert_error (error, test_domain_quark (), 0); + + g_main_loop_quit (loop); +} + +static void +test_activation_error (void) +{ + g_autoptr (WpSessionItem) item = NULL; + g_autoptr (GMainLoop) loop = NULL; + WpSiFlags signalled_flags = 0; + TestSiDummy *dummy; + GVariantBuilder b; + + loop = g_main_loop_new (NULL, FALSE); + item = g_object_new (si_dummy_get_type (), NULL); + dummy = TEST_SI_DUMMY (item); + g_signal_connect (item, "flags-changed", G_CALLBACK (expect_flags), + &signalled_flags); + + g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "fail", g_variant_new_boolean (TRUE)); + g_assert_true (wp_session_item_configure (item, g_variant_builder_end (&b))); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_CONFIGURED); + g_assert_cmpint (signalled_flags, ==, WP_SI_FLAG_CONFIGURED); + + wp_session_item_activate (item, + (GAsyncReadyCallback) expect_activate_failure, loop); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, + WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVATING); + g_assert_cmpint (signalled_flags, ==, + WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_ACTIVATING); + + g_main_loop_run (loop); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, + WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_IN_ERROR); + g_assert_cmpint (signalled_flags, ==, + WP_SI_FLAG_CONFIGURED | WP_SI_FLAG_IN_ERROR); + g_assert_false (dummy->step_1_done); + g_assert_false (dummy->step_2_done); + g_assert_true (dummy->cleaned_up); + + wp_session_item_deactivate (item); + + g_assert_cmpint (wp_session_item_get_flags (item), ==, WP_SI_FLAG_CONFIGURED); + g_assert_cmpint (signalled_flags, ==, WP_SI_FLAG_CONFIGURED); + g_assert_false (dummy->step_1_done); + g_assert_false (dummy->step_2_done); + g_assert_false (dummy->cleaned_up); +} + +gint +main (gint argc, gchar *argv[]) +{ + g_test_init (&argc, &argv, NULL); + g_log_set_writer_func (wp_log_writer_default, NULL, NULL); + + g_test_add_func ("/wp/session-item/flags", test_flags); + g_test_add_func ("/wp/session-item/configuration", test_configuration); + g_test_add_func ("/wp/session-item/activation", test_activation); + g_test_add_func ("/wp/session-item/activation-error", test_activation_error); + + return g_test_run (); +}