diff options
author | Thomas Haller <thaller@redhat.com> | 2019-09-21 20:35:18 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-09-21 22:01:29 +0200 |
commit | d19a403faa480b20f9ca6c9ce9e66a015b16cf46 (patch) | |
tree | a0e74971e6fb81619cc744ad152798aa719a8eb5 | |
parent | bf8118b8290d498f71068d9b77628cf7cb668400 (diff) | |
download | NetworkManager-d19a403faa480b20f9ca6c9ce9e66a015b16cf46.tar.gz |
libnm/test: add unit test with consistency checks about NMSetting type info
Add test for checking the meta data for expected consistency.
This is also useful if you want to check something about the meta data
programatically.
For example, if you have the question which (if any) properties
are GObject based but also implement a to_dbus_fcn() function. Then you
can extend this code with some simple printf debugging to get a list of
those.
Or, if you want to find how many NMSettInfoProperty instances are in
static data (e.g. to determine how much memory is used). You can easily
modify this code to count them (and find 447 properties). Out of these,
326 are plain GObject based properties. Meaning, we could refactor the
code to create smaller NMSettInfoProperty instances for those, saving
thus (326 * 4 * sizeof (gpointer)) bytes (10K).
Such questions are interesting when refactoring the code.
-rw-r--r-- | libnm-core/nm-core-internal.h | 2 | ||||
-rw-r--r-- | libnm-core/nm-setting.c | 6 | ||||
-rw-r--r-- | libnm-core/tests/test-setting.c | 158 |
3 files changed, 166 insertions, 0 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index e9b07e2025..37523e2564 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -706,6 +706,8 @@ typedef GVariant *(*NMSettInfoPropGPropToDBusFcn) (const GValue *from); typedef void (*NMSettInfoPropGPropFromDBusFcn) (GVariant *from, GValue *to); +const NMSettInfoSetting *nmtst_sett_info_settings (void); + struct _NMSettInfoProperty { const char *name; GParamSpec *param_spec; diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 1e853f8575..7a932f6cf2 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -354,6 +354,12 @@ _properties_override_add_transform (GArray *properties_override, static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM]; +const NMSettInfoSetting * +nmtst_sett_info_settings (void) +{ + return _sett_info_settings; +} + static int _property_infos_sort_cmp_setting_connection (gconstpointer p_a, gconstpointer p_b, diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 6f16080fc8..ee0caa3d19 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -9,6 +9,7 @@ #include <linux/pkt_sched.h> #include <net/if.h> +#include "nm-core-internal.h" #include "nm-utils.h" #include "nm-utils-private.h" #include "nm-core-internal.h" @@ -3317,6 +3318,161 @@ test_empty_setting (void) /*****************************************************************************/ +static void +test_setting_metadata (void) +{ + const NMSettInfoSetting *sett_info_settings = nmtst_sett_info_settings (); + NMMetaSettingType meta_type; + + G_STATIC_ASSERT (_NM_META_SETTING_TYPE_NUM == NM_META_SETTING_TYPE_UNKNOWN); + + for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++) { + const NMMetaSettingInfo *msi = &nm_meta_setting_infos[meta_type]; + nm_auto_unref_gtypeclass NMSettingClass *klass = NULL; + GType gtype; + + g_assert (msi->setting_name); + g_assert (msi->get_setting_gtype); + g_assert (msi->meta_type == meta_type); + g_assert (msi->setting_priority >= NM_SETTING_PRIORITY_CONNECTION); + g_assert (msi->setting_priority <= NM_SETTING_PRIORITY_USER); + + if (meta_type > 0) + g_assert_cmpint (strcmp (nm_meta_setting_infos[meta_type - 1].setting_name, msi->setting_name), <, 0); + + gtype = msi->get_setting_gtype (); + + g_assert (g_type_is_a (gtype, NM_TYPE_SETTING)); + g_assert (gtype != NM_TYPE_SETTING); + + klass = g_type_class_ref (gtype); + g_assert (klass); + g_assert (NM_IS_SETTING_CLASS (klass)); + } + + g_assert (sett_info_settings); + + for (meta_type = 0; meta_type < _NM_META_SETTING_TYPE_NUM; meta_type++) { + const NMSettInfoSetting *sis = &sett_info_settings[meta_type]; + const NMMetaSettingInfo *msi = &nm_meta_setting_infos[meta_type]; + gs_unref_hashtable GHashTable *h_properties = NULL; + GType gtype; + gs_unref_object NMSetting *setting = NULL; + guint prop_idx; + gs_free GParamSpec **property_specs = NULL; + guint n_property_specs; + + g_assert (sis); + + g_assert (NM_IS_SETTING_CLASS (sis->setting_class)); + + gtype = msi->get_setting_gtype (); + + g_assert (G_TYPE_FROM_CLASS (sis->setting_class) == gtype); + + setting = g_object_new (gtype, NULL); + + g_assert (NM_IS_SETTING (setting)); + + g_assert_cmpint (sis->property_infos_len, >, 0); + g_assert (sis->property_infos); + + h_properties = g_hash_table_new (nm_str_hash, g_str_equal); + + for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) { + const NMSettInfoProperty *sip = &sis->property_infos[prop_idx]; + + g_assert (sip->name); + + if (prop_idx > 0) + g_assert_cmpint (strcmp (sis->property_infos[prop_idx - 1].name, sip->name), <, 0); + + g_assert (sip->dbus_type); + g_assert (g_variant_type_string_is_valid ((const char *) sip->dbus_type)); + + if (!g_hash_table_insert (h_properties, (char *) sip->name, sip->param_spec)) + g_assert_not_reached (); + + if (sip->param_spec) { + nm_auto_unset_gvalue GValue val = G_VALUE_INIT; + + g_assert_cmpstr (sip->name, ==, sip->param_spec->name); + + g_value_init (&val, sip->param_spec->value_type); + g_object_get_property (G_OBJECT (setting), sip->name, &val); + + if (sip->param_spec->value_type == G_TYPE_STRING) { + const char *default_value; + + default_value = ((const GParamSpecString *) sip->param_spec)->default_value; + if (default_value) { + /* having a string property with a default != NULL is really ugly. They + * should be best avoided... */ + if ( meta_type == NM_META_SETTING_TYPE_DCB + && nm_streq (sip->name, NM_SETTING_DCB_APP_FCOE_MODE)) { + /* Whitelist the properties that have a non-NULL default value. */ + g_assert_cmpstr (default_value, ==, NM_SETTING_DCB_FCOE_MODE_FABRIC); + } else + g_assert_not_reached (); + } + + if (nm_streq (sip->name, NM_SETTING_NAME)) + g_assert_cmpstr (g_value_get_string (&val), ==, msi->setting_name); + else + g_assert_cmpstr (g_value_get_string (&val), ==, default_value); + } + } + } + + /* check that all GObject based properties are tracked by the settings. */ + property_specs = g_object_class_list_properties (G_OBJECT_CLASS (sis->setting_class), + &n_property_specs); + g_assert (property_specs); + g_assert_cmpint (n_property_specs, >, 0); + for (prop_idx = 0; prop_idx < n_property_specs; prop_idx++) { + const GParamSpec *pip = property_specs[prop_idx]; + + g_assert (g_hash_table_lookup (h_properties, pip->name) == pip); + } + + /* check that property_infos_sorted is as expected. */ + if (sis->property_infos_sorted) { + gs_unref_hashtable GHashTable *h = g_hash_table_new (nm_direct_hash, NULL); + + /* property_infos_sorted is only implemented for [connection] type */ + g_assert_cmpint (meta_type, ==, NM_META_SETTING_TYPE_CONNECTION); + + /* ensure that there are no duplicates, and that all properties are also + * tracked by sis->property_infos. */ + for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) { + const NMSettInfoProperty *sip = sis->property_infos_sorted[prop_idx]; + + if (!g_hash_table_add (h, (gpointer) sip)) + g_assert_not_reached (); + } + for (prop_idx = 0; prop_idx < sis->property_infos_len; prop_idx++) { + const NMSettInfoProperty *sip = &sis->property_infos[prop_idx]; + + g_assert (g_hash_table_contains (h, sip)); + } + } else + g_assert_cmpint (meta_type, !=, NM_META_SETTING_TYPE_CONNECTION); + + /* consistency check for gendata-info. */ + if (sis->detail.gendata_info) { + g_assert_cmpint (meta_type, ==, NM_META_SETTING_TYPE_ETHTOOL); + g_assert (sis->detail.gendata_info->get_variant_type); + + /* the gendata info based setting has only one regular property: the "name". */ + g_assert_cmpint (sis->property_infos_len, ==, 1); + g_assert_cmpstr (sis->property_infos[0].name, ==, NM_SETTING_NAME); + } else + g_assert_cmpint (meta_type, !=, NM_META_SETTING_TYPE_ETHTOOL); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -3406,5 +3562,7 @@ main (int argc, char **argv) g_test_add_func ("/libnm/test_empty_setting", test_empty_setting); + g_test_add_func ("/libnm/test_setting_metadata", test_setting_metadata); + return g_test_run (); } |