summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-03-20 13:28:02 +0100
committerThomas Haller <thaller@redhat.com>2015-03-20 13:30:22 +0100
commit89c88f24805f6092ea0f9725556fb9944316467f (patch)
treeeedd9bedb25046b5b7d94c56ff8e644fe9e7b979
parent3ef2a5364b1494230f2135f8b642d3a0fd2b2f30 (diff)
parent58f08c8c9ce3602f31d2fdfaa2cc9ecca4713532 (diff)
downloadNetworkManager-89c88f24805f6092ea0f9725556fb9944316467f.tar.gz
libnm/keyfile: sort keyfile entries and nm_connection_for_each_setting_value()
Fix the order for keyfile writer. It is nicer to have a fixed, sensible order with [connection] first. Do this by sorting the order in nm_connection_for_each_setting_value() and nm_setting_enumerate_values(). https://mail.gnome.org/archives/networkmanager-list/2015-March/msg00050.html
-rw-r--r--include/nm-test-utils.h42
-rw-r--r--libnm-core/nm-connection.c44
-rw-r--r--libnm-core/nm-setting.c35
-rw-r--r--libnm-core/tests/test-keyfile.c171
4 files changed, 221 insertions, 71 deletions
diff --git a/include/nm-test-utils.h b/include/nm-test-utils.h
index 187a0f1931..ddea03745d 100644
--- a/include/nm-test-utils.h
+++ b/include/nm-test-utils.h
@@ -32,6 +32,7 @@
#include <errno.h>
#include "nm-utils.h"
+#include "nm-utils-internal.h"
#include "nm-glib-compat.h"
#include "gsystem-local-alloc.h"
@@ -91,13 +92,13 @@ nmtst_initialized (void)
return !!__nmtst_internal.rand0;
}
-#define __NMTST_LOG(cmd, fmt, ...) \
+#define __NMTST_LOG(cmd, ...) \
G_STMT_START { \
g_assert (nmtst_initialized ()); \
if (!__nmtst_internal.assert_logging || __nmtst_internal.no_expect_message) { \
- cmd (fmt, __VA_ARGS__); \
+ cmd (__VA_ARGS__); \
} else { \
- printf (fmt "\n", __VA_ARGS__); \
+ printf (_NM_UTILS_MACRO_FIRST (__VA_ARGS__) "\n" _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
} \
} G_STMT_END
@@ -870,19 +871,40 @@ nmtst_assert_connection_equals (NMConnection *a, gboolean normalize_a, NMConnect
b = b2 = nmtst_connection_duplicate_and_normalize (b);
compare = nm_connection_diff (a, b, NM_SETTING_COMPARE_FLAG_EXACT, &out_settings);
- if (!compare && out_settings) {
+ if (!compare || out_settings) {
const char *name, *pname;
GHashTable *setting;
GHashTableIter iter, iter2;
- g_hash_table_iter_init (&iter, out_settings);
- while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) {
- __NMTST_LOG (g_message, ">>> differences in setting '%s':", name);
+ __NMTST_LOG (g_message, ">>> ASSERTION nmtst_assert_connection_equals() fails");
+ if (out_settings) {
+ g_hash_table_iter_init (&iter, out_settings);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &setting)) {
+ __NMTST_LOG (g_message, ">>> differences in setting '%s':", name);
- g_hash_table_iter_init (&iter2, out_settings);
- while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL))
- __NMTST_LOG (g_message, ">>> differences in setting '%s.%s':", name, pname);
+ g_hash_table_iter_init (&iter2, setting);
+ while (g_hash_table_iter_next (&iter2, (gpointer *) &pname, NULL))
+ __NMTST_LOG (g_message, ">>> differences in setting '%s.%s'", name, pname);
+ }
}
+
+#ifdef __NM_KEYFILE_INTERNAL_H__
+ {
+ gs_unref_keyfile GKeyFile *kf_a = NULL, *kf_b = NULL;
+ gs_free char *str_a = NULL, *str_b = NULL;
+
+ kf_a = nm_keyfile_write (a, NULL, NULL, NULL);
+ kf_b = nm_keyfile_write (b, NULL, NULL, NULL);
+
+ if (kf_a)
+ str_a = g_key_file_to_data (kf_a, NULL, NULL);
+ if (kf_b)
+ str_b = g_key_file_to_data (kf_b, NULL, NULL);
+
+ __NMTST_LOG (g_message, ">>> Connection A as kf (*WARNING: keyfile representation might not show the difference*):\n%s", str_a);
+ __NMTST_LOG (g_message, ">>> Connection B as kf (*WARNING: keyfile representation might not show the difference*):\n%s", str_b);
+ }
+#endif
}
g_assert (compare);
g_assert (!out_settings);
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 79ff31d89d..acdc8b89c7 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -30,6 +30,7 @@
#include "nm-utils.h"
#include "nm-setting-private.h"
#include "nm-core-internal.h"
+#include "gsystem-local-alloc.h"
/**
* SECTION:nm-connection
@@ -1306,6 +1307,19 @@ nm_connection_is_type (NMConnection *connection, const char *type)
return (g_strcmp0 (type2, type) == 0);
}
+static int
+_for_each_sort (NMSetting **p_a, NMSetting **p_b, void *unused)
+{
+ NMSetting *a = *p_a;
+ NMSetting *b = *p_b;
+ int c;
+
+ c = _nm_setting_compare_priority (a, b);
+ if (c != 0)
+ return c;
+ return strcmp (nm_setting_get_name (a), nm_setting_get_name (b));
+}
+
/**
* nm_connection_for_each_setting_value:
* @connection: the #NMConnection
@@ -1320,15 +1334,39 @@ nm_connection_for_each_setting_value (NMConnection *connection,
NMSettingValueIterFn func,
gpointer user_data)
{
+ NMConnectionPrivate *priv;
+ gs_free NMSetting **arr_free = NULL;
+ NMSetting *arr_temp[20], **arr;
GHashTableIter iter;
gpointer value;
+ guint i, size;
g_return_if_fail (NM_IS_CONNECTION (connection));
g_return_if_fail (func != NULL);
- g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
- while (g_hash_table_iter_next (&iter, NULL, &value))
- nm_setting_enumerate_values (NM_SETTING (value), func, user_data);
+ priv = NM_CONNECTION_GET_PRIVATE (connection);
+
+ size = g_hash_table_size (priv->settings);
+ if (!size)
+ return;
+
+ if (size > G_N_ELEMENTS (arr_temp))
+ arr = arr_free = g_new (NMSetting *, size);
+ else
+ arr = arr_temp;
+
+ g_hash_table_iter_init (&iter, priv->settings);
+ for (i = 0; g_hash_table_iter_next (&iter, NULL, &value); i++)
+ arr[i] = NM_SETTING (value);
+ g_assert (i == size);
+
+ /* sort the settings. This has an effect on the order in which keyfile
+ * prints them. */
+ if (size > 1)
+ g_qsort_with_data (arr, size, sizeof (NMSetting *), (GCompareDataFunc) _for_each_sort, NULL);
+
+ for (i = 0; i < size; i++)
+ nm_setting_enumerate_values (arr[i], func, user_data);
}
/**
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 2730742654..a292bfca6e 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -1314,6 +1314,33 @@ nm_setting_diff (NMSetting *a,
return !(*results);
}
+#define CMP_AND_RETURN(n_a, n_b, name) \
+ G_STMT_START { \
+ gboolean _is = (strcmp (n_a, ""name) == 0); \
+ \
+ if (_is || (strcmp (n_b, ""name) == 0)) \
+ return _is ? -1 : 1; \
+ } G_STMT_END;
+
+static int
+_enumerate_values_sort (GParamSpec **p_a, GParamSpec **p_b, GType *p_type)
+{
+ const char *n_a = (*p_a)->name;
+ const char *n_b = (*p_b)->name;
+ int c = strcmp (n_a, n_b);
+
+ if (c) {
+ if (*p_type == NM_TYPE_SETTING_CONNECTION) {
+ /* for [connection], report first id, uuid, type in that order. */
+ CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_ID);
+ CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_UUID);
+ CMP_AND_RETURN (n_a, n_b, NM_SETTING_CONNECTION_TYPE);
+ }
+ }
+ return c;
+}
+#undef CMP_AND_RETURN
+
/**
* nm_setting_enumerate_values:
* @setting: the #NMSetting
@@ -1331,11 +1358,19 @@ nm_setting_enumerate_values (NMSetting *setting,
GParamSpec **property_specs;
guint n_property_specs;
int i;
+ GType type;
g_return_if_fail (NM_IS_SETTING (setting));
g_return_if_fail (func != NULL);
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
+
+ /* sort the properties. This has an effect on the order in which keyfile
+ * prints them. */
+ type = G_OBJECT_TYPE (setting);
+ g_qsort_with_data (property_specs, n_property_specs, sizeof (gpointer),
+ (GCompareDataFunc) _enumerate_values_sort, &type);
+
for (i = 0; i < n_property_specs; i++) {
GParamSpec *prop_spec = property_specs[i];
GValue value = G_VALUE_INIT;
diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c
index 43958cb6bb..0f0548ad85 100644
--- a/libnm-core/tests/test-keyfile.c
+++ b/libnm-core/tests/test-keyfile.c
@@ -114,6 +114,46 @@ _keyfile_equals (GKeyFile *kf_a, GKeyFile *kf_b)
return _keyfile_a_contains_all_in_b (kf_a, kf_b) && _keyfile_a_contains_all_in_b (kf_b, kf_a);
}
+static GKeyFile *
+_nm_keyfile_write (NMConnection *connection,
+ NMKeyfileWriteHandler handler,
+ void *user_data)
+{
+ GError *error = NULL;
+ GKeyFile *kf;
+
+ g_assert (NM_IS_CONNECTION (connection));
+
+ kf = nm_keyfile_write (connection, handler, user_data, &error);
+ g_assert_no_error (error);
+ g_assert (kf);
+ return kf;
+}
+
+static NMConnection *
+_nm_keyfile_read (GKeyFile *keyfile,
+ const char *keyfile_name,
+ const char *base_dir,
+ NMKeyfileReadHandler read_handler,
+ void *read_data,
+ gboolean needs_normalization)
+{
+ GError *error = NULL;
+ NMConnection *con;
+
+ g_assert (keyfile);
+
+ con = nm_keyfile_read (keyfile, keyfile_name, base_dir, read_handler, read_data, &error);
+ g_assert_no_error (error);
+ g_assert (NM_IS_CONNECTION (con));
+ if (needs_normalization)
+ nmtst_assert_connection_verifies_after_normalization (con, 0, 0);
+ else
+ nmtst_assert_connection_verifies_without_normalization (con);
+ return con;
+}
+
+
static void
_keyfile_convert (NMConnection **con,
GKeyFile **keyfile,
@@ -125,10 +165,10 @@ _keyfile_convert (NMConnection **con,
void *write_data,
gboolean needs_normalization)
{
- NMConnection *c, *c2;
- GKeyFile *k, *k2;
- GError *error = NULL;
- NMSetting8021x *s1, *s2;
+ NMConnection *c0;
+ GKeyFile *k0;
+ gs_unref_object NMConnection *c0_k1_c2 = NULL, *k0_c1 = NULL, *k0_c1_k2_c3 = NULL;
+ gs_unref_keyfile GKeyFile *k0_c1_k2 = NULL, *c0_k1 = NULL, *c0_k1_c2_k3 = NULL;
/* convert from @con to @keyfile and check that we can make
* full round trips and obtaining the same result. */
@@ -137,64 +177,79 @@ _keyfile_convert (NMConnection **con,
g_assert (keyfile);
g_assert (*con || *keyfile);
- if (!*keyfile) {
- k = nm_keyfile_write (*con, write_handler, read_data, &error);
- g_assert_no_error (error);
- g_assert (k);
- *keyfile = k;
- } else
- k = *keyfile;
- if (!*con) {
- c = nm_keyfile_read (*keyfile, keyfile_name, base_dir, read_handler, read_data, &error);
- g_assert_no_error (error);
- g_assert (c);
- if (needs_normalization)
- nmtst_assert_connection_verifies_after_normalization (c, 0, 0);
- else
- nmtst_assert_connection_verifies_without_normalization (c);
- *con = c;
- } else
- c = *con;
-
- k2 = nm_keyfile_write (c, write_handler, read_data, &error);
- g_assert_no_error (error);
- g_assert (k2);
+ c0 = *con;
+ k0 = *keyfile;
- c2 = nm_keyfile_read (k, keyfile_name, base_dir, read_handler, read_data, &error);
- g_assert_no_error (error);
- g_assert (c2);
- if (needs_normalization)
- nmtst_assert_connection_verifies_after_normalization (c2, 0, 0);
- else
- nmtst_assert_connection_verifies_without_normalization (c2);
-
- s1 = nm_connection_get_setting_802_1x (*con);
- s2 = nm_connection_get_setting_802_1x (c2);
- if (s1 || s2) {
- g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s1), ==, nm_setting_802_1x_get_ca_cert_scheme (s2));
- switch (nm_setting_802_1x_get_ca_cert_scheme (s1)) {
- case NM_SETTING_802_1X_CK_SCHEME_PATH:
- nmtst_assert_resolve_relative_path_equals (nm_setting_802_1x_get_ca_cert_path (s1), nm_setting_802_1x_get_ca_cert_path (s2));
- break;
- case NM_SETTING_802_1X_CK_SCHEME_BLOB: {
- GBytes *b1, *b2;
-
- b1 = nm_setting_802_1x_get_ca_cert_blob (s1);
- b2 = nm_setting_802_1x_get_ca_cert_blob (s2);
- g_assert_cmpint (g_bytes_get_size (b1), ==, g_bytes_get_size (b2));
- g_assert (memcmp (g_bytes_get_data (b1, NULL), g_bytes_get_data (b2, NULL), g_bytes_get_size (b1)) == 0);
- break;
- }
- default:
- break;
- }
+ if (c0) {
+ c0_k1 = _nm_keyfile_write (c0, write_handler, write_data);
+ c0_k1_c2 = _nm_keyfile_read (c0_k1, keyfile_name, base_dir, read_handler, read_data, FALSE);
+ c0_k1_c2_k3 = _nm_keyfile_write (c0_k1_c2, write_handler, write_data);
+
+ _keyfile_equals (c0_k1, c0_k1_c2_k3);
}
+ if (k0) {
+ NMSetting8021x *s1, *s2;
+
+ k0_c1 = _nm_keyfile_read (k0, keyfile_name, base_dir, read_handler, read_data, needs_normalization);
+ k0_c1_k2 = _nm_keyfile_write (k0_c1, write_handler, write_data);
+ k0_c1_k2_c3 = _nm_keyfile_read (k0_c1_k2, keyfile_name, base_dir, read_handler, read_data, FALSE);
+
+ /* It is a expeced behavior, that if @k0 contains a relative path ca-cert, @k0_c1 will
+ * contain that path as relative. But @k0_c1_k2 and @k0_c1_k2_c3 will have absolute paths.
+ * In this case, hack up @k0_c1_k2_c3 to contain the same relative path. */
+ s1 = nm_connection_get_setting_802_1x (k0_c1);
+ s2 = nm_connection_get_setting_802_1x (k0_c1_k2_c3);
+ if (s1 || s2) {
+ g_assert_cmpint (nm_setting_802_1x_get_ca_cert_scheme (s1), ==, nm_setting_802_1x_get_ca_cert_scheme (s2));
+ switch (nm_setting_802_1x_get_ca_cert_scheme (s1)) {
+ case NM_SETTING_802_1X_CK_SCHEME_PATH:
+ {
+ const char *p1 = nm_setting_802_1x_get_ca_cert_path (s1);
+ const char *p2 = nm_setting_802_1x_get_ca_cert_path (s2);
+
+ nmtst_assert_resolve_relative_path_equals (p1, p2);
+ if (strcmp (p1, p2) != 0) {
+ gs_free char *puri = NULL;
+ gs_unref_bytes GBytes *pfile = NULL;
+
+ g_assert (p1[0] != '/' && p2[0] == '/');
+
+ /* one of the paths is a relative path and the other is absolute. This is an
+ * expected difference.
+ * Make the paths of s2 identical to s1... */
+ puri = g_strconcat (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, p1, NULL);
+ pfile = g_bytes_new (puri, strlen (puri) + 1);
+ g_object_set (s2, NM_SETTING_802_1X_CA_CERT, pfile, NULL);
+ }
+ }
+ break;
+ case NM_SETTING_802_1X_CK_SCHEME_BLOB: {
+ GBytes *b1, *b2;
+
+ b1 = nm_setting_802_1x_get_ca_cert_blob (s1);
+ b2 = nm_setting_802_1x_get_ca_cert_blob (s2);
+ g_assert_cmpint (g_bytes_get_size (b1), ==, g_bytes_get_size (b2));
+ g_assert (memcmp (g_bytes_get_data (b1, NULL), g_bytes_get_data (b2, NULL), g_bytes_get_size (b1)) == 0);
+ break;
+ }
+ default:
+ break;
+ }
+ }
- nmtst_assert_connection_equals (c2, FALSE, *con, FALSE);
- _keyfile_equals (k2, *keyfile);
+ nmtst_assert_connection_equals (k0_c1, FALSE, k0_c1_k2_c3, FALSE);
+ }
- g_object_unref (c2);
- g_key_file_unref (k2);
+ if (!k0)
+ *keyfile = g_key_file_ref (c0_k1);
+ else if (!c0)
+ *con = g_object_ref (k0_c1);
+ else {
+ /* finally, if both a keyfile and a connection are given, assert that they are equal
+ * after a round of conversion. */
+ _keyfile_equals (c0_k1, k0_c1_k2);
+ nmtst_assert_connection_equals (k0_c1, FALSE, c0_k1_c2, FALSE);
+ }
}
/******************************************************************************/