pacemaker  3.0.0-d8340737c4
Scalable High-Availability cluster resource manager
pcmk__xe_sort_attrs_test.c
Go to the documentation of this file.
1 /*
2  * Copyright 2024 the Pacemaker project contributors
3  *
4  * The version control history for this file may have further details.
5  *
6  * This source code is licensed under the GNU General Public License version 2
7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
8  */
9 
10 #include <crm_internal.h>
11 
13 
14 #include <glib.h> // GHashTable, etc.
15 
16 #include "crmcommon_private.h" // xml_node_private_t
17 
30 static void
31 assert_order(xmlNode *test_xml, const xmlNode *reference_xml)
32 {
33  GHashTable *attr_flags = pcmk__strkey_table(free, NULL);
34  xmlAttr *test_attr = NULL;
35  xmlAttr *ref_attr = NULL;
36 
37  // Save original flags
38  for (xmlAttr *attr = pcmk__xe_first_attr(test_xml); attr != NULL;
39  attr = attr->next) {
40 
41  xml_node_private_t *nodepriv = attr->_private;
42  uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none;
43 
44  g_hash_table_insert(attr_flags,
45  pcmk__str_copy((const char *) attr->name),
46  GUINT_TO_POINTER((guint) flags));
47  }
48 
49  pcmk__xe_sort_attrs(test_xml);
50 
51  test_attr = pcmk__xe_first_attr(test_xml);
52  ref_attr = pcmk__xe_first_attr(reference_xml);
53 
54  for (; (test_attr != NULL) && (ref_attr != NULL);
55  test_attr = test_attr->next, ref_attr = ref_attr->next) {
56 
57  const char *test_name = (const char *) test_attr->name;
58  xml_node_private_t *nodepriv = test_attr->_private;
59  uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none;
60 
61  gpointer old_flags_ptr = g_hash_table_lookup(attr_flags, test_name);
62  uint32_t old_flags = pcmk__xf_none;
63 
64  if (old_flags_ptr != NULL) {
65  old_flags = GPOINTER_TO_UINT(old_flags_ptr);
66  }
67 
68  // Flags must not change
69  assert_true(flags == old_flags);
70 
71  // Attributes must be in expected order with expected values
72  assert_string_equal(test_name, (const char *) ref_attr->name);
73  assert_string_equal(pcmk__xml_attr_value(test_attr),
74  pcmk__xml_attr_value(ref_attr));
75  }
76 
77  // Attribute lists must be the same length
78  assert_null(test_attr);
79  assert_null(ref_attr);
80 
81  g_hash_table_destroy(attr_flags);
82 }
83 
84 static void
85 null_arg(void **state)
86 {
87  // Ensure it doesn't crash
88  pcmk__xe_sort_attrs(NULL);
89 }
90 
91 static void
92 nothing_to_sort(void **state)
93 {
94  xmlNode *test_xml = pcmk__xe_create(NULL, "test");
95  xmlNode *reference_xml = NULL;
96 
97  // No attributes
98  reference_xml = pcmk__xml_copy(NULL, test_xml);
99  assert_order(test_xml, reference_xml);
100  pcmk__xml_free(reference_xml);
101 
102  // Only one attribute
103  crm_xml_add(test_xml, "name", "value");
104  reference_xml = pcmk__xml_copy(NULL, test_xml);
105  assert_order(test_xml, reference_xml);
106  pcmk__xml_free(reference_xml);
107 
108  pcmk__xml_free(test_xml);
109 }
110 
111 static void
112 already_sorted(void **state)
113 {
114  xmlNode *test_xml = pcmk__xe_create(NULL, "test");
115  xmlNode *reference_xml = pcmk__xe_create(NULL, "test");
116 
117  xmlAttr *attr = NULL;
118 
119  crm_xml_add(test_xml, "admin", "john");
120  crm_xml_add(test_xml, "dummy", "value");
121  crm_xml_add(test_xml, "location", "usa");
122 
123  // Set flags in test_xml's attributes for testing flag preservation
124  attr = xmlHasProp(test_xml, (pcmkXmlStr) "admin");
125  if (attr != NULL) {
126  xml_node_private_t *nodepriv = attr->_private;
127 
128  if (nodepriv != NULL) {
130  }
131  }
132 
133  attr = xmlHasProp(test_xml, (pcmkXmlStr) "location");
134  if (attr != NULL) {
135  xml_node_private_t *nodepriv = attr->_private;
136 
137  if (nodepriv != NULL) {
139  }
140  }
141 
142  pcmk__xe_set_props(reference_xml,
143  "admin", "john",
144  "dummy", "value",
145  "location", "usa",
146  NULL);
147 
148  assert_order(test_xml, reference_xml);
149 
150  pcmk__xml_free(test_xml);
151  pcmk__xml_free(reference_xml);
152 }
153 
154 static void
155 need_sort(void **state)
156 {
157  xmlNode *test_xml = pcmk__xe_create(NULL, "test");
158  xmlNode *reference_xml = pcmk__xe_create(NULL, "test");
159 
160  xmlAttr *attr = NULL;
161 
162  crm_xml_add(test_xml, "location", "usa");
163  crm_xml_add(test_xml, "admin", "john");
164  crm_xml_add(test_xml, "dummy", "value");
165 
166  // Set flags in test_xml's attributes for testing flag preservation
167  attr = xmlHasProp(test_xml, (pcmkXmlStr) "location");
168  if (attr != NULL) {
169  xml_node_private_t *nodepriv = attr->_private;
170 
171  if (nodepriv != NULL) {
173  }
174  }
175 
176  attr = xmlHasProp(test_xml, (pcmkXmlStr) "admin");
177  if (attr != NULL) {
178  xml_node_private_t *nodepriv = attr->_private;
179 
180  if (nodepriv != NULL) {
182  }
183  }
184 
185  pcmk__xe_set_props(reference_xml,
186  "admin", "john",
187  "dummy", "value",
188  "location", "usa",
189  NULL);
190 
191  assert_order(test_xml, reference_xml);
192 
193  pcmk__xml_free(test_xml);
194  pcmk__xml_free(reference_xml);
195 }
196 
198  cmocka_unit_test(null_arg),
199  cmocka_unit_test(nothing_to_sort),
200  cmocka_unit_test(already_sorted),
201  cmocka_unit_test(need_sort))
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition: xml.c:805
void pcmk__xe_sort_attrs(xmlNode *xml)
Definition: xml_element.c:312
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
Definition: xml_element.c:407
void pcmk__xml_free(xmlNode *xml)
Definition: xml.c:789
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition: xml_element.c:1015
int pcmk__xml_test_setup_group(void **state)
Definition: unittest.c:85
#define pcmk__str_copy(str)
int pcmk__xml_test_teardown_group(void **state)
Definition: unittest.c:104
const xmlChar * pcmkXmlStr
Definition: xml.h:41
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
Definition: xml_element.c:970
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:685
#define pcmk__set_xml_flags(xml_priv, flags_to_set)
#define pcmk__clear_xml_flags(xml_priv, flags_to_clear)
uint64_t flags
Definition: remote.c:211