wireplumber/tests/wp/settings.c
Julian Bouzas 2223cd47d4 settings: use WpSpaJson to parse the settings
We need to use WpSpaJson to parse the values in WpSettings. This is because the
wireplumber configuration is written in JSON, so WpSettings should only hold
JSON values. To fix this, 2 API changes have been done:

- wp_settings_get_int() only accepts gint values, instead of gint64 values. This
is because the WpSpaJson API only parses int values, like spa_json_parse_int().

- wp_settings_get_string() now returns a newly allocated string, this is because
the string needs to be decoded in case it has quotes.
2023-04-17 07:47:09 -04:00

692 lines
21 KiB
C

/* WirePlumber
*
* Copyright © 2022 Collabora Ltd.
* @author Ashok Sidipotu <ashok.sidipotu@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "../common/base-test-fixture.h"
/*
* tests the loading & parsing of JSON conf file(pls check the .conf that is
* loaded), metadata updates, wpsetttings object creation and its API.
*/
typedef enum {
BOOLEAN,
INTEGER,
STRING,
FLOAT
} SettingType;
typedef struct {
WpBaseTestFixture base;
WpProperties *settings;
WpImplMetadata *impl_metadata;
WpMetadata *metadata;
WpSettings *s;
gchar *triggered_setting;
gchar *triggered_setting_value;
gboolean triggered_callback;
SettingType setting_type;
} TestSettingsFixture;
static void
test_conf_file_setup (TestSettingsFixture *self, gconstpointer user_data)
{
self->base.conf_file =
g_strdup_printf ("%s/settings.conf", g_getenv ("G_TEST_SRCDIR"));
wp_base_test_fixture_setup (&self->base, WP_BASE_TEST_FLAG_CLIENT_CORE);
}
static void
test_conf_file_teardown (TestSettingsFixture *self, gconstpointer user_data)
{
g_free (self->base.conf_file);
wp_base_test_fixture_teardown (&self->base);
}
static int
dummy(void *data, const char *location, const char *section,
const char *str, size_t len)
{
return 1;
}
static void
test_conf_file (TestSettingsFixture *self, gconstpointer data)
{
struct pw_context *pw_ctx = wp_core_get_pw_context (self->base.core);
/* test if the "settings" section is present in the JSON config file */
g_assert_true (pw_context_conf_section_for_each(pw_ctx,
"wireplumber.settings", dummy, NULL));
}
struct data {
int count;
WpProperties *settings;
};
static int
do_parse_settings (void *data, const char *location,
const char *section, const char *str, size_t len)
{
struct data *d = data;
g_autoptr (WpSpaJson) json = wp_spa_json_new_from_stringn (str, len);
g_autoptr (WpIterator) iter = wp_spa_json_new_iterator (json);
g_auto (GValue) item = G_VALUE_INIT;
if (!wp_spa_json_is_object (json)) {
return -EINVAL;
}
while (wp_iterator_next (iter, &item)) {
WpSpaJson *j = g_value_get_boxed (&item);
g_autofree gchar *name = wp_spa_json_parse_string (j);
g_autofree gchar *value = NULL;
g_value_unset (&item);
wp_iterator_next (iter, &item);
j = g_value_get_boxed (&item);
value = wp_spa_json_to_string (j);
g_value_unset (&item);
if (name && value) {
wp_properties_set (d->settings, name, value);
d->count++;
}
}
g_debug ("parsed %d settings & rules from conf file\n", d->count);
return 0;
}
static void
test_parsing_setup (TestSettingsFixture *self, gconstpointer user_data)
{
test_conf_file_setup (self, user_data);
{
struct pw_context *pw_ctx = wp_core_get_pw_context (self->base.core);
g_autoptr (WpProperties) settings = wp_properties_new_empty();
struct data data = { .settings = settings };
g_assert_false (pw_context_conf_section_for_each(pw_ctx,
"wireplumber.settings", do_parse_settings, &data));
self->settings = g_steal_pointer (&settings);
/* total no.of settings in the conf file */
g_assert_cmpint (data.count, ==, 12);
}
}
static void
test_parsing_teardown (TestSettingsFixture *self, gconstpointer user_data)
{
g_clear_pointer (&self->settings, wp_properties_unref);
test_conf_file_teardown (self, user_data);
}
static void
test_parsing (TestSettingsFixture *self, gconstpointer data)
{
/* total no.of settings in the conf file */
g_assert_cmpint (wp_properties_get_count(self->settings), ==, 12);
}
static void
on_metadata_activated (WpMetadata * m, GAsyncResult * res, gpointer user_data)
{
TestSettingsFixture *self = user_data;
g_autoptr (GError) error = NULL;
g_autoptr (WpIterator) it = NULL;
g_auto (GValue) item = G_VALUE_INIT;
g_assert_true(wp_object_activate_finish (WP_OBJECT (m), res, NULL));
for (it = wp_properties_new_iterator (self->settings);
wp_iterator_next (it, &item);
g_value_unset (&item)) {
WpPropertiesItem *pi = g_value_get_boxed (&item);
const gchar *setting = wp_properties_item_get_key (pi);
const gchar *value = wp_properties_item_get_value (pi);
wp_metadata_set (m, 0, setting, "Spa:String:JSON", value);
}
g_debug ("loaded settings(%d) to \"test-settings\" metadata\n",
wp_properties_get_count (self->settings));
self->metadata = g_object_ref(m);
g_main_loop_quit(self->base.loop);
}
static void
test_metadata_setup (TestSettingsFixture *self, gconstpointer user_data)
{
test_parsing_setup (self, user_data);
{
self->impl_metadata = wp_impl_metadata_new_full (self->base.core,
"test-settings", NULL);
wp_object_activate (WP_OBJECT (self->impl_metadata),
WP_OBJECT_FEATURES_ALL,
NULL,
(GAsyncReadyCallback)on_metadata_activated,
self);
g_main_loop_run (self->base.loop);
}
}
static void
test_metadata_teardown (TestSettingsFixture *self, gconstpointer user_data)
{
test_parsing_teardown (self, user_data);
g_clear_object (&self->impl_metadata);
g_clear_object (&self->metadata);
}
static void
test_metadata (TestSettingsFixture *self, gconstpointer data)
{
g_autoptr (WpProperties) settings = wp_properties_new_empty();
g_autoptr (WpIterator) it = wp_metadata_new_iterator
(WP_METADATA (self->metadata), 0);
g_auto (GValue) val = G_VALUE_INIT;
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
const gchar *setting, *value;
wp_metadata_iterator_item_extract (&val, NULL, &setting, NULL, &value);
wp_properties_set (settings, setting, value);
g_debug ("%s(%lu) = %s\n", setting, strlen(value), value);
}
/* match the settings loaded from conf file and metadata */
g_assert_true (wp_properties_matches (self->settings, settings));
}
static void
on_settings_ready (WpSettings *s, GAsyncResult *res, gpointer data)
{
TestSettingsFixture *self = data;
g_assert_true(wp_object_activate_finish (WP_OBJECT (s), res, NULL));
g_main_loop_quit(self->base.loop);
}
static void
test_wpsettings_setup (TestSettingsFixture *self, gconstpointer user_data)
{
test_metadata_setup (self, user_data);
{
self->s = wp_settings_get_instance (self->base.core, "test-settings");
wp_object_activate (WP_OBJECT (self->s),
WP_OBJECT_FEATURES_ALL,
NULL,
(GAsyncReadyCallback)on_settings_ready,
self);
g_main_loop_run (self->base.loop);
}
}
static void
test_wpsettings_teardown (TestSettingsFixture *self, gconstpointer user_data)
{
test_metadata_teardown (self, user_data);
g_clear_object (&self->s);
}
static void
test_wpsettings (TestSettingsFixture *self, gconstpointer data)
{
WpSettings *s = self->s;
{
gboolean value = 0;
/* test settings _get_boolean */
g_assert_false (wp_settings_get_boolean (s, "test-setting-undefined",
&value));
g_assert_true (wp_settings_get_boolean (s, "test-setting1", &value));
g_assert_false (value);
g_assert_true (wp_settings_get_boolean (s, "test-setting2", &value));
g_assert_true (value);
}
{
gint value = 0;
/* _get_int () */
g_assert_false (wp_settings_get_int (s, "test-setting-undefined",
&value));
g_assert_true (wp_settings_get_int (s, "test-setting3-int", &value));
g_assert_cmpint (value, ==, -20);
}
{
/* _get_string () */
{
g_autofree gchar *value = NULL;
value = wp_settings_get_string (s, "test-setting-undefined");
g_assert_null (value);
}
{
g_autofree gchar *value = NULL;
value = wp_settings_get_string (s, "test-setting4-string");
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, "blahblah");
}
{
g_autofree gchar *value = NULL;
value = wp_settings_get_string (s, "test-setting2");
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, "true");
}
{
g_autofree gchar *value = NULL;
value = wp_settings_get_string (s, "test-setting3-int");
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, "-20");
}
{
g_autofree gchar *value = NULL;
value = wp_settings_get_string (s, "test-setting5-string-with-quotes");
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, "a string with \"quotes\"");
}
}
{
gfloat value = 0.0;
/* _get_float () */
g_assert_false (wp_settings_get_float (s, "test-setting-undefined",
&value));
g_assert_true (wp_settings_get_float (s, "test-setting-float1",
&value));
g_assert_cmpfloat_with_epsilon (value, 3.14, 0.001);
g_assert_true (wp_settings_get_float (s, "test-setting-float2",
&value));
g_assert_cmpfloat_with_epsilon (value, 0.4, 0.001);
}
/* test the wp_settings_get_instance () API */
{
g_autoptr (WpSettings) s1 =
wp_settings_get_instance (self->base.core, "test-settings");
g_autoptr (WpSettings) s2 =
wp_settings_get_instance (self->base.core, "test-settings");
g_autoptr (WpSettings) s3 =
wp_settings_get_instance (self->base.core, "blah-blah");
g_assert_true (s == s1);
g_assert_true (s1 == s2);
g_assert_false (s1 == s3);
}
{
/* _get_json () */
{
g_autoptr (WpSpaJson) value = NULL;
value = wp_settings_get (s, "test-setting-json");
g_assert_nonnull (value);
g_assert_true (wp_spa_json_is_array (value));
g_assert_cmpstr (wp_spa_json_get_data (value), ==, "[1, 2, 3]");
}
{
g_autoptr (WpSpaJson) value = NULL;
value = wp_settings_get (s, "test-setting-json2");
g_assert_nonnull (value);
g_assert_true (wp_spa_json_is_array (value));
{
g_autofree gchar *s1 = NULL;
g_autofree gchar *s2 = NULL;
g_autofree gchar *s3 = NULL;
g_autofree gchar *s4 = NULL;
wp_spa_json_parse_array
(value, "s", &s1, "s", &s2, "s", &s3, "s", &s4, NULL);
g_assert_cmpstr (s1, ==, "test1");
g_assert_cmpstr (s2, ==, "test 2");
g_assert_cmpstr (s3, ==, "test three");
g_assert_cmpstr (s4, ==, "test-four");
}
{
gchar *sample_str[] = {
"test1",
"test 2",
"test three",
"test-four"
};
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (value);
g_auto (GValue) item = G_VALUE_INIT;
for (int i = 0; wp_iterator_next (it, &item);
g_value_unset (&item), i++) {
WpSpaJson *s = g_value_get_boxed (&item);
g_autofree gchar *str = wp_spa_json_parse_string (s);
g_assert_cmpstr (str, ==, sample_str[i]);
}
}
}
}
{
g_autoptr (WpSettings) s4 =
wp_settings_get_instance (self->base.core, NULL);
g_auto (GValue) value = G_VALUE_INIT;
g_object_get_property (G_OBJECT(s4), "metadata-name", &value);
g_assert_cmpstr (g_value_get_string (&value), ==, "sm-settings");
}
}
static void
test_rules (TestSettingsFixture *self, gconstpointer data)
{
WpSettings *s = self->s;
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string2", "juggler",
NULL);
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string2", "jugglr",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string1", "copper",
"test-int1", "100",
NULL);
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string1", "copper",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string2", "juggler",
NULL);
gint before = wp_properties_get_count (props), after = 0;
guint prop_int1 = 0;
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
after = wp_properties_get_count (props);
g_assert_cmpint (after-before, ==, 2);
g_assert_cmpstr (wp_properties_get(props, "prop-string1"), ==, "metal");
g_assert_cmpstr (wp_properties_get(props, "prop-string2"), ==, NULL);
g_assert_cmpstr (wp_properties_get(props, "prop-int1"), ==, "123");
spa_atou32 (wp_properties_get(props, "prop-int1"), &prop_int1, 0);
g_assert_cmpint (prop_int1, ==, 123);
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string4", "ferrous",
"test-int2", "100",
"test-string5", "blend",
NULL);
gint before = wp_properties_get_count (props), after = 0;
guint prop_int2 = 0;
g_assert_true (wp_settings_apply_rule (s, "rule_one", props, NULL));
after = wp_properties_get_count (props);
g_assert_cmpint (after-before, ==, 3);
g_assert_cmpstr (wp_properties_get(props, "prop-string1"), ==, NULL);
g_assert_cmpstr (wp_properties_get(props, "prop-string2"), ==, "standard");
g_assert_cmpstr (wp_properties_get(props, "prop-int2"), ==, "26");
spa_atou32 (wp_properties_get(props, "prop-int2"), &prop_int2, 0);
g_assert_cmpint (prop_int2, ==, 26);
g_assert_true (spa_atob(wp_properties_get(props, "prop-bool1")));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test-string6", "ethylene",
"test-int2", "625",
"test-string5", "blend",
NULL);
g_autoptr (WpProperties) applied_props = wp_properties_new_empty ();
guint prop_int2 = 0;
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
g_assert_true (wp_settings_apply_rule (s, "rule_two", props,
applied_props));
g_assert_cmpint (wp_properties_get_count (applied_props), ==, 2);
g_assert_cmpstr (wp_properties_get(applied_props, "prop-string1"),
==, NULL);
g_assert_cmpstr (wp_properties_get(applied_props, "prop-string2"),
==, "spray");
g_assert_cmpstr (wp_properties_get(applied_props, "prop-int2"), ==, "111");
spa_atou32 (wp_properties_get(applied_props, "prop-int2"), &prop_int2, 0);
g_assert_cmpint (prop_int2, ==, 111);
g_assert_false (spa_atob(wp_properties_get(applied_props, "prop-bool1")));
}
/* test the regular experession syntax */
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "metal.iron",
"test.table.entry", "true",
NULL);
g_autoptr (WpProperties) applied_props = wp_properties_new_empty ();
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
g_assert_false (wp_settings_apply_rule (s, "rule_two", props,
applied_props));
g_assert_true (wp_settings_apply_rule (s, "rule_three", props,
applied_props));
g_assert_cmpint (wp_properties_get_count (applied_props), ==, 3);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.string1"),
==, NULL);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.state"),
==, "solid");
g_assert_cmpstr (wp_properties_get(applied_props, "prop.example"),
==, "ferrous");
g_assert_true (spa_atob(wp_properties_get(applied_props,
"prop.electrical.conductivity")));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "metal.iron",
"test.table.entry", "false",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_three", props,
NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "metl.iron",
"test.table.entry", "true",
NULL);
g_assert_false (wp_settings_apply_rule (s, "rule_three", props,
NULL));
}
{
g_autoptr (WpProperties) props = wp_properties_new (
"test.string6", "gas.neon",
"test.table.entry", "maybe",
NULL);
g_autoptr (WpProperties) applied_props = wp_properties_new_empty ();
g_assert_false (wp_settings_apply_rule (s, "rule_one", props, NULL));
g_assert_false (wp_settings_apply_rule (s, "rule_two", props,
applied_props));
g_assert_true (wp_settings_apply_rule (s, "rule_three", props,
applied_props));
g_assert_cmpint (wp_properties_get_count (applied_props), ==, 3);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.string1"),
==, NULL);
g_assert_cmpstr (wp_properties_get(applied_props, "prop.state"),
==, "gas");
g_assert_cmpstr (wp_properties_get(applied_props, "prop.example"),
==, "neon");
g_assert_false (spa_atob(wp_properties_get(applied_props,
"prop.electrical.conductivity")));
}
}
void wp_settings_changed_callback (WpSettings *obj, const gchar *setting,
const gchar *raw_value, gpointer user_data)
{
TestSettingsFixture *self = user_data;
g_assert_cmpstr (setting, ==, self->triggered_setting);
self->triggered_callback = true;
if (self->setting_type == BOOLEAN) {
gboolean value = false;
wp_settings_get_boolean (self->s, setting, &value);
g_assert_cmpint (value, ==, spa_atob (self->triggered_setting_value));
g_assert_cmpstr (raw_value, ==, self->triggered_setting_value);
} else if (self->setting_type == INTEGER) {
gint value = 0;
wp_settings_get_int (self->s, setting, &value);
g_assert_cmpint (value, ==, atoi (self->triggered_setting_value));
g_assert_cmpstr (raw_value, ==, self->triggered_setting_value);
} else if (self->setting_type == STRING) {
g_autofree gchar *value = wp_settings_get_string (self->s, setting);
g_assert_nonnull (value);
g_assert_cmpstr (value, ==, self->triggered_setting_value);
g_assert_cmpstr (raw_value, ==, self->triggered_setting_value);
}
}
static void
test_callbacks (TestSettingsFixture *self, gconstpointer data)
{
WpSettings *s = self->s;
guintptr sub_id;
/* register callback */
sub_id = wp_settings_subscribe (s, "test*",
wp_settings_changed_callback, (gpointer)self);
{
self->triggered_setting = "test-setting1";
self->triggered_setting_value = "true";
self->triggered_callback = false;
self->setting_type = BOOLEAN;
wp_metadata_set (self->metadata, 0, self->triggered_setting,
"Spa:String:JSON", self->triggered_setting_value);
g_assert_cmpint (self->triggered_callback, ==, true);
}
{
self->triggered_setting = "test-setting1";
self->triggered_setting_value = "true";
self->setting_type = BOOLEAN;
self->triggered_callback = false;
wp_metadata_set (self->metadata, 0, self->triggered_setting,
"Spa:String:JSON", self->triggered_setting_value);
g_assert_cmpint (self->triggered_callback, ==, false);
}
{
self->triggered_setting = "test-setting3-int";
self->setting_type = INTEGER;
self->triggered_setting_value = "99";
self->triggered_callback = true;
wp_metadata_set (self->metadata, 0, self->triggered_setting,
"Spa:String:JSON", self->triggered_setting_value);
g_assert_cmpint (self->triggered_callback, ==, true);
}
{
self->triggered_setting = "test-setting4-string";
self->setting_type = STRING;
self->triggered_setting_value = "lets not blabber";
self->triggered_callback = true;
wp_metadata_set (self->metadata, 0, self->triggered_setting,
"Spa:String:JSON", self->triggered_setting_value);
g_assert_cmpint (self->triggered_callback, ==, true);
}
{
self->triggered_setting = "test-setting4-string";
self->setting_type = STRING;
self->triggered_setting_value = "lets blabber";
self->triggered_callback = false;
g_assert_cmpint (wp_settings_unsubscribe (s, sub_id), ==,
true);
g_assert_cmpint (wp_settings_unsubscribe (s, (sub_id-1)), ==,
false);
wp_metadata_set (self->metadata, 0, self->triggered_setting,
"Spa:String:JSON", self->triggered_setting_value);
g_assert_cmpint (self->triggered_callback, ==, false);
}
}
gint
main (gint argc, gchar *argv[])
{
g_test_init (&argc, &argv, NULL);
wp_init (WP_INIT_ALL);
/* take a close look at .conf file that is loaded, all the test work on it */
g_test_add ("/wp/settings/conf-file-loading", TestSettingsFixture, NULL,
test_conf_file_setup, test_conf_file, test_conf_file_teardown);
g_test_add ("/wp/settings/parsing", TestSettingsFixture, NULL,
test_parsing_setup, test_parsing, test_parsing_teardown);
g_test_add ("/wp/settings/metadata-creation", TestSettingsFixture, NULL,
test_metadata_setup, test_metadata, test_metadata_teardown);
g_test_add ("/wp/settings/wpsettings-creation-get", TestSettingsFixture, NULL,
test_wpsettings_setup, test_wpsettings, test_wpsettings_teardown);
g_test_add ("/wp/settings/wpsettings-creation-rules", TestSettingsFixture, NULL,
test_wpsettings_setup, test_rules, test_wpsettings_teardown);
g_test_add ("/wp/settings/wpsettings-callbacks", TestSettingsFixture, NULL,
test_wpsettings_setup, test_callbacks, test_wpsettings_teardown);
return g_test_run ();
}