pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk__xe_sort_attrs_test.c
Go to the documentation of this file.
1/*
2 * Copyright 2024-2025 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#include <libxml/tree.h> // xmlNode
16#include <libxml/xmlstring.h> // xmlChar
17
18#include "crmcommon_private.h" // xml_node_private_t
19
32static void
33assert_order(xmlNode *test_xml, const xmlNode *reference_xml)
34{
35 GHashTable *attr_flags = pcmk__strkey_table(free, NULL);
36 xmlAttr *test_attr = NULL;
37 xmlAttr *ref_attr = NULL;
38
39 // Save original flags
40 for (xmlAttr *attr = pcmk__xe_first_attr(test_xml); attr != NULL;
41 attr = attr->next) {
42
43 xml_node_private_t *nodepriv = attr->_private;
44 uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none;
45
46 g_hash_table_insert(attr_flags,
47 pcmk__str_copy((const char *) attr->name),
48 GUINT_TO_POINTER((guint) flags));
49 }
50
51 pcmk__xe_sort_attrs(test_xml);
52
53 test_attr = pcmk__xe_first_attr(test_xml);
54 ref_attr = pcmk__xe_first_attr(reference_xml);
55
56 for (; (test_attr != NULL) && (ref_attr != NULL);
57 test_attr = test_attr->next, ref_attr = ref_attr->next) {
58
59 const char *test_name = (const char *) test_attr->name;
60 xml_node_private_t *nodepriv = test_attr->_private;
61 uint32_t flags = (nodepriv != NULL)? nodepriv->flags : pcmk__xf_none;
62
63 gpointer old_flags_ptr = g_hash_table_lookup(attr_flags, test_name);
64 uint32_t old_flags = pcmk__xf_none;
65
66 if (old_flags_ptr != NULL) {
67 old_flags = GPOINTER_TO_UINT(old_flags_ptr);
68 }
69
70 // Flags must not change
71 assert_true(flags == old_flags);
72
73 // Attributes must be in expected order with expected values
74 assert_string_equal(test_name, (const char *) ref_attr->name);
75 assert_string_equal(pcmk__xml_attr_value(test_attr),
76 pcmk__xml_attr_value(ref_attr));
77 }
78
79 // Attribute lists must be the same length
80 assert_null(test_attr);
81 assert_null(ref_attr);
82
83 g_hash_table_destroy(attr_flags);
84}
85
86static void
87null_arg(void **state)
88{
89 // Ensure it doesn't crash
91}
92
93static void
94nothing_to_sort(void **state)
95{
96 xmlNode *test_xml = pcmk__xe_create(NULL, "test");
97 xmlNode *reference_xml = NULL;
98
99 // No attributes
100 reference_xml = pcmk__xml_copy(NULL, test_xml);
101 assert_order(test_xml, reference_xml);
102 pcmk__xml_free(reference_xml);
103
104 // Only one attribute
105 crm_xml_add(test_xml, "name", "value");
106 reference_xml = pcmk__xml_copy(NULL, test_xml);
107 assert_order(test_xml, reference_xml);
108 pcmk__xml_free(reference_xml);
109
110 pcmk__xml_free(test_xml);
111}
112
113static void
114already_sorted(void **state)
115{
116 xmlNode *test_xml = pcmk__xe_create(NULL, "test");
117 xmlNode *reference_xml = pcmk__xe_create(NULL, "test");
118
119 xmlAttr *attr = NULL;
120
121 crm_xml_add(test_xml, "admin", "john");
122 crm_xml_add(test_xml, "dummy", "value");
123 crm_xml_add(test_xml, "location", "usa");
124
125 // Set flags in test_xml's attributes for testing flag preservation
126 attr = xmlHasProp(test_xml, (const xmlChar *) "admin");
127 if (attr != NULL) {
128 xml_node_private_t *nodepriv = attr->_private;
129
130 if (nodepriv != NULL) {
132 }
133 }
134
135 attr = xmlHasProp(test_xml, (const xmlChar *) "location");
136 if (attr != NULL) {
137 xml_node_private_t *nodepriv = attr->_private;
138
139 if (nodepriv != NULL) {
141 }
142 }
143
144 pcmk__xe_set_props(reference_xml,
145 "admin", "john",
146 "dummy", "value",
147 "location", "usa",
148 NULL);
149
150 assert_order(test_xml, reference_xml);
151
152 pcmk__xml_free(test_xml);
153 pcmk__xml_free(reference_xml);
154}
155
156static void
157need_sort(void **state)
158{
159 xmlNode *test_xml = pcmk__xe_create(NULL, "test");
160 xmlNode *reference_xml = pcmk__xe_create(NULL, "test");
161
162 xmlAttr *attr = NULL;
163
164 crm_xml_add(test_xml, "location", "usa");
165 crm_xml_add(test_xml, "admin", "john");
166 crm_xml_add(test_xml, "dummy", "value");
167
168 // Set flags in test_xml's attributes for testing flag preservation
169 attr = xmlHasProp(test_xml, (const xmlChar *) "location");
170 if (attr != NULL) {
171 xml_node_private_t *nodepriv = attr->_private;
172
173 if (nodepriv != NULL) {
175 }
176 }
177
178 attr = xmlHasProp(test_xml, (const xmlChar *) "admin");
179 if (attr != NULL) {
180 xml_node_private_t *nodepriv = attr->_private;
181
182 if (nodepriv != NULL) {
184 }
185 }
186
187 pcmk__xe_set_props(reference_xml,
188 "admin", "john",
189 "dummy", "value",
190 "location", "usa",
191 NULL);
192
193 assert_order(test_xml, reference_xml);
194
195 pcmk__xml_free(test_xml);
196 pcmk__xml_free(reference_xml);
197}
198
200 cmocka_unit_test(null_arg),
201 cmocka_unit_test(nothing_to_sort),
202 cmocka_unit_test(already_sorted),
203 cmocka_unit_test(need_sort))
uint64_t flags
Definition remote.c:3
#define pcmk__set_xml_flags(xml_priv, flags_to_set)
#define pcmk__clear_xml_flags(xml_priv, flags_to_clear)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition strings.c:685
#define pcmk__str_copy(str)
uint32_t flags
Group of enum pcmk__xml_flags
int pcmk__xml_test_teardown_group(void **state)
Definition unittest.c:105
#define PCMK__UNIT_TEST(group_setup, group_teardown,...)
int pcmk__xml_test_setup_group(void **state)
Definition unittest.c:87
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
xmlNode * pcmk__xe_create(xmlNode *parent, const char *name)
void pcmk__xe_set_props(xmlNodePtr node,...) G_GNUC_NULL_TERMINATED
void pcmk__xe_sort_attrs(xmlNode *xml)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
Definition xml.c:832
@ pcmk__xf_created
Node was created.
@ pcmk__xf_ignore_attr_pos
Ignore attribute moves within an element (set for document only)
@ pcmk__xf_dirty
@ pcmk__xf_none
This flag has no effect.
void pcmk__xml_free(xmlNode *xml)
Definition xml.c:816