summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-09-21 20:35:18 +0200
committerThomas Haller <thaller@redhat.com>2019-09-21 22:01:29 +0200
commitd19a403faa480b20f9ca6c9ce9e66a015b16cf46 (patch)
treea0e74971e6fb81619cc744ad152798aa719a8eb5
parentbf8118b8290d498f71068d9b77628cf7cb668400 (diff)
downloadNetworkManager-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.h2
-rw-r--r--libnm-core/nm-setting.c6
-rw-r--r--libnm-core/tests/test-setting.c158
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 ();
}