2023-06-13 20:01:02 +03:00
|
|
|
/* WirePlumber
|
|
|
|
|
*
|
|
|
|
|
* Copyright © 2023 Collabora Ltd.
|
|
|
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
|
*/
|
|
|
|
|
#include "../common/base-test-fixture.h"
|
|
|
|
|
|
|
|
|
|
struct _WpTestPlugin
|
|
|
|
|
{
|
|
|
|
|
WpPlugin parent;
|
|
|
|
|
gboolean enabled;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define WP_TYPE_TEST_PLUGIN (wp_test_plugin_get_type ())
|
|
|
|
|
G_DECLARE_FINAL_TYPE (WpTestPlugin, wp_test_plugin, WP, TEST_PLUGIN, WpPlugin)
|
|
|
|
|
G_DEFINE_TYPE (WpTestPlugin, wp_test_plugin, WP_TYPE_PLUGIN)
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_plugin_init (WpTestPlugin * self)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_plugin_enable (WpPlugin * self, WpTransition * transition)
|
|
|
|
|
{
|
|
|
|
|
WP_TEST_PLUGIN (self)->enabled = TRUE;
|
2023-06-20 16:57:49 +03:00
|
|
|
|
|
|
|
|
if (g_str_equal (wp_plugin_get_name (self), "fail")) {
|
|
|
|
|
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
|
|
|
|
WP_LIBRARY_ERROR_INVALID_ARGUMENT, "fail"));
|
|
|
|
|
} else {
|
|
|
|
|
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
|
|
|
|
|
}
|
2023-06-13 20:01:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_plugin_class_init (WpTestPluginClass * klass)
|
|
|
|
|
{
|
|
|
|
|
WpPluginClass *pclass = (WpPluginClass *) klass;
|
|
|
|
|
pclass->enable = wp_test_plugin_enable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct _WpTestCompLoader
|
|
|
|
|
{
|
|
|
|
|
GObject parent;
|
2023-06-15 21:27:13 +03:00
|
|
|
GPtrArray *history;
|
2023-06-13 20:01:02 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void wp_test_comp_loader_iface_init (WpComponentLoaderInterface * iface);
|
|
|
|
|
|
|
|
|
|
#define WP_TYPE_TEST_COMP_LOADER (wp_test_comp_loader_get_type ())
|
|
|
|
|
G_DECLARE_FINAL_TYPE (WpTestCompLoader, wp_test_comp_loader,
|
|
|
|
|
WP, TEST_COMP_LOADER, GObject)
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (WpTestCompLoader, wp_test_comp_loader,
|
|
|
|
|
G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (
|
|
|
|
|
WP_TYPE_COMPONENT_LOADER,
|
|
|
|
|
wp_test_comp_loader_iface_init))
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_comp_loader_init (WpTestCompLoader * self)
|
|
|
|
|
{
|
2023-06-15 21:27:13 +03:00
|
|
|
self->history = g_ptr_array_new_with_free_func (g_free);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_comp_loader_finalize (GObject * self)
|
|
|
|
|
{
|
|
|
|
|
g_clear_pointer (&WP_TEST_COMP_LOADER (self)->history, g_ptr_array_unref);
|
|
|
|
|
G_OBJECT_CLASS (wp_test_comp_loader_parent_class)->finalize (self);
|
2023-06-13 20:01:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_comp_loader_class_init (WpTestCompLoaderClass * klass)
|
|
|
|
|
{
|
2023-06-15 21:27:13 +03:00
|
|
|
GObjectClass *oclass = (GObjectClass *) klass;
|
|
|
|
|
oclass->finalize = wp_test_comp_loader_finalize;
|
2023-06-13 20:01:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
wp_test_comp_loader_supports_type (WpComponentLoader * cl, const gchar * type)
|
|
|
|
|
{
|
|
|
|
|
return g_str_equal (type, "test");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_comp_loader_load (WpComponentLoader * self, WpCore * core,
|
|
|
|
|
const gchar * component, const gchar * type, WpSpaJson * args,
|
|
|
|
|
GCancellable * cancellable, GAsyncReadyCallback callback, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_autoptr (GTask) task = g_task_new (self, cancellable, callback, data);
|
|
|
|
|
GObject *plugin = g_object_new (WP_TYPE_TEST_PLUGIN,
|
|
|
|
|
"name", component,
|
|
|
|
|
"core", core,
|
|
|
|
|
NULL);
|
2023-06-15 21:27:13 +03:00
|
|
|
g_ptr_array_add (WP_TEST_COMP_LOADER (self)->history, g_strdup (component));
|
2023-06-13 20:01:02 +03:00
|
|
|
g_task_return_pointer (task, plugin, g_object_unref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GObject *
|
|
|
|
|
wp_test_comp_loader_load_finish (WpComponentLoader * self,
|
|
|
|
|
GAsyncResult * res, GError ** error)
|
|
|
|
|
{
|
|
|
|
|
return g_task_propagate_pointer (G_TASK (res), error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
wp_test_comp_loader_iface_init (WpComponentLoaderInterface * iface)
|
|
|
|
|
{
|
|
|
|
|
iface->supports_type = wp_test_comp_loader_supports_type;
|
|
|
|
|
iface->load = wp_test_comp_loader_load;
|
|
|
|
|
iface->load_finish = wp_test_comp_loader_load_finish;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
WpBaseTestFixture base;
|
2023-06-15 21:27:13 +03:00
|
|
|
WpTestCompLoader *loader;
|
2023-06-13 20:01:02 +03:00
|
|
|
} TestFixture;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_setup (TestFixture *self, gconstpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
wp_base_test_fixture_setup (&self->base, 0);
|
2023-06-15 21:27:13 +03:00
|
|
|
self->loader = g_object_new (WP_TYPE_TEST_COMP_LOADER, NULL);
|
|
|
|
|
wp_core_register_object (self->base.core, self->loader);
|
2023-06-13 20:01:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_teardown (TestFixture *self, gconstpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
wp_base_test_fixture_teardown (&self->base);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
on_component_loaded (WpCore * core, GAsyncResult * res, TestFixture *f)
|
|
|
|
|
{
|
|
|
|
|
gboolean loaded;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
loaded = wp_core_load_component_finish (core, res, &error);
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
g_assert_true (loaded);
|
|
|
|
|
|
|
|
|
|
g_main_loop_quit (f->base.loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_load (TestFixture *f, gconstpointer data)
|
|
|
|
|
{
|
|
|
|
|
wp_core_load_component (f->base.core, "name123", "test", NULL,
|
|
|
|
|
"feature.name123", NULL, (GAsyncReadyCallback) on_component_loaded, f);
|
|
|
|
|
g_main_loop_run (f->base.loop);
|
|
|
|
|
|
|
|
|
|
g_autoptr (WpPlugin) plugin = wp_plugin_find (f->base.core, "name123");
|
|
|
|
|
g_assert_nonnull (plugin);
|
|
|
|
|
g_assert_true (WP_IS_TEST_PLUGIN (plugin));
|
|
|
|
|
g_assert_true (WP_TEST_PLUGIN (plugin)->enabled);
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "feature.name123"));
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-20 16:57:49 +03:00
|
|
|
static void
|
|
|
|
|
on_component_failed (WpCore * core, GAsyncResult * res, TestFixture *f)
|
|
|
|
|
{
|
|
|
|
|
gboolean loaded;
|
2024-08-31 20:47:45 +03:00
|
|
|
g_autoptr (GError) error = NULL;
|
2023-06-20 16:57:49 +03:00
|
|
|
|
|
|
|
|
loaded = wp_core_load_component_finish (core, res, &error);
|
|
|
|
|
g_assert_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT);
|
|
|
|
|
g_assert_false (loaded);
|
|
|
|
|
|
|
|
|
|
g_main_loop_quit (f->base.loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_load_failure (TestFixture *f, gconstpointer data)
|
|
|
|
|
{
|
|
|
|
|
wp_core_load_component (f->base.core, "fail", "test", NULL,
|
|
|
|
|
"feature.fail", NULL, (GAsyncReadyCallback) on_component_failed, f);
|
|
|
|
|
g_main_loop_run (f->base.loop);
|
|
|
|
|
|
|
|
|
|
g_assert_cmpuint (f->loader->history->len, ==, 1);
|
|
|
|
|
g_assert_cmpstr (f->loader->history->pdata[0], ==, "fail");
|
|
|
|
|
|
|
|
|
|
g_autoptr (WpPlugin) plugin = wp_plugin_find (f->base.core, "fail");
|
|
|
|
|
g_assert_null (plugin);
|
|
|
|
|
g_assert_false (wp_core_test_feature (f->base.core, "feature.fail"));
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-15 21:27:13 +03:00
|
|
|
static void
|
|
|
|
|
test_dependencies_setup (TestFixture *f, gconstpointer data)
|
|
|
|
|
{
|
|
|
|
|
f->base.conf_file =
|
|
|
|
|
g_strdup_printf ("%s/component-loader.conf", g_getenv ("G_TEST_SRCDIR"));
|
|
|
|
|
test_setup (f, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
test_dependencies (TestFixture *f, gconstpointer data)
|
|
|
|
|
{
|
2023-06-23 20:15:26 +03:00
|
|
|
wp_core_load_component (f->base.core, "test", "profile", NULL,
|
2023-06-15 21:27:13 +03:00
|
|
|
NULL, NULL, (GAsyncReadyCallback) on_component_loaded, f);
|
|
|
|
|
g_main_loop_run (f->base.loop);
|
|
|
|
|
|
|
|
|
|
// NULL-terminate the array
|
|
|
|
|
g_ptr_array_add (f->loader->history, NULL);
|
|
|
|
|
|
|
|
|
|
/* verify the order of loading the plugins was as expected */
|
|
|
|
|
const gchar *expected[] = {
|
internal-comp-loader: implement before/after dependencies for components
In some cases, requires/wants dependencies are not enough. As we saw in
!617, the m-standard-event-source module needs to be loaded after all
the hooks, otherwise there may be missed events that the hook was
supposed to "catch", but they were delivered before the hook was actually
loaded. In a similar fashion, we have in purpose put all the "monitor"
components at the every end of the array because if we load them earlier,
they will create devices and nodes before all the hooks are in place to
react.
While in standard configuration we can work this around, in extended
user configurations with custom components, it is impossible to do this
without overriding the entire components array.
To fix this properly, introduce before/after dependencies. They work in
a similar fashion as they work with event hooks. They do not implicitly
"pull" any components to be loaded, but they affect the ordering if the
mentioned components are indeed present.
Note that for backwards compatibility reasons and unlike systemd units,
the "requires"/"wants" targets imply an "after" dependency on them.
Fixes: #600
2024-08-31 20:33:42 +03:00
|
|
|
"five", "one", "seven", "ten", "eleven", "six", "two", "three", "four", "nine", NULL };
|
2023-06-15 21:27:13 +03:00
|
|
|
g_assert_cmpstrv (f->loader->history->pdata, expected);
|
|
|
|
|
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.one"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.two"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.three"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.four"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "virtual.four"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.five"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.six"));
|
|
|
|
|
g_assert_false (wp_core_test_feature (f->base.core, "support.seven"));
|
|
|
|
|
g_assert_false (wp_core_test_feature (f->base.core, "support.eight"));
|
internal-comp-loader: implement before/after dependencies for components
In some cases, requires/wants dependencies are not enough. As we saw in
!617, the m-standard-event-source module needs to be loaded after all
the hooks, otherwise there may be missed events that the hook was
supposed to "catch", but they were delivered before the hook was actually
loaded. In a similar fashion, we have in purpose put all the "monitor"
components at the every end of the array because if we load them earlier,
they will create devices and nodes before all the hooks are in place to
react.
While in standard configuration we can work this around, in extended
user configurations with custom components, it is impossible to do this
without overriding the entire components array.
To fix this properly, introduce before/after dependencies. They work in
a similar fashion as they work with event hooks. They do not implicitly
"pull" any components to be loaded, but they affect the ordering if the
mentioned components are indeed present.
Note that for backwards compatibility reasons and unlike systemd units,
the "requires"/"wants" targets imply an "after" dependency on them.
Fixes: #600
2024-08-31 20:33:42 +03:00
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.nine"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.ten"));
|
|
|
|
|
g_assert_true (wp_core_test_feature (f->base.core, "support.eleven"));
|
2023-06-15 21:27:13 +03:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 20:01:02 +03:00
|
|
|
gint
|
|
|
|
|
main (gint argc, gchar *argv[])
|
|
|
|
|
{
|
|
|
|
|
g_test_init (&argc, &argv, NULL);
|
|
|
|
|
wp_init (WP_INIT_ALL);
|
|
|
|
|
|
|
|
|
|
g_test_add ("/wp/comploader/load", TestFixture, NULL,
|
|
|
|
|
test_setup, test_load, test_teardown);
|
2023-06-20 16:57:49 +03:00
|
|
|
g_test_add ("/wp/comploader/load_failure", TestFixture, NULL,
|
|
|
|
|
test_setup, test_load_failure, test_teardown);
|
2023-06-15 21:27:13 +03:00
|
|
|
g_test_add ("/wp/comploader/dependencies", TestFixture, NULL,
|
|
|
|
|
test_dependencies_setup, test_dependencies, test_teardown);
|
2023-06-13 20:01:02 +03:00
|
|
|
|
|
|
|
|
return g_test_run ();
|
|
|
|
|
}
|