Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3687174
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
252 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/include/crm/common/unittest_internal.h b/include/crm/common/unittest_internal.h
index 4e4fc8f8ec..769e87217e 100644
--- a/include/crm/common/unittest_internal.h
+++ b/include/crm/common/unittest_internal.h
@@ -1,207 +1,198 @@
/*
* Copyright 2022-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cmocka.h>
#include <crm/common/xml.h>
#ifndef CRM_COMMON_UNITTEST_INTERNAL__H
#define CRM_COMMON_UNITTEST_INTERNAL__H
/* internal unit testing related utilities */
#if (PCMK__WITH_COVERAGE == 1)
/* This function isn't exposed anywhere. The following prototype was taken from
* /usr/lib/gcc/x86_64-redhat-linux/??/include/gcov.h
*/
extern void __gcov_dump(void);
#else
#define __gcov_dump()
#endif
/*!
* \internal
* \brief Assert that the XML output from an API function is valid
*
* \param[in] xml The XML output of some public pacemaker API function
*
* Run the given XML through xmllint and attempt to validate it against the
* api-result.rng schema file. Assert if validation fails.
*
* \note PCMK_schema_directory needs to be set to the directory containing
* the built schema files before calling this function. Typically,
* this will be done in Makefile.am.
*/
void pcmk__assert_validates(xmlNode *xml);
-/*!
- * \internal
- * \brief Perform setup for a group of unit tests that will manipulate XML
- *
- * This function is suitable for being passed as the first argument to the
- * \c PCMK__UNIT_TEST macro.
- *
- * \param[in] state The cmocka state object, currently unused by this
- * function
- */
int pcmk__xml_test_setup_group(void **state);
+int pcmk__xml_test_teardown_group(void **state);
/*!
* \internal
* \brief Copy the given CIB file to a temporary file so it can be modified
* as part of doing unit tests, returning the full temporary file or
* \c NULL on error.
*
* This function should be called as part of the process of setting up any
* single unit test that would access and modify a CIB. That is, it should
* be called from whatever function is the second argument to
* cmocka_unit_test_setup_teardown.
*
* \param[in] in_file The filename of the input CIB file, which must
* exist in the \c $PCMK_CTS_CLI_DIR directory. This
* should only be the filename, not the complete
* path.
*/
char *pcmk__cib_test_copy_cib(const char *in_file);
/*!
* \internal
* \brief Clean up whatever was done by a previous call to
* \c pcmk__cib_test_copy_cib.
*
* This function should be called as part of the process of tearing down
* any single unit test that accessed a CIB. That is, it should be called
* from whatever function is the third argument to
* \c cmocka_unit_test_setup_teardown.
*
* \param[in] out_path The complete path to the temporary CIB location.
* This is the return value of
* \c pcmk__cib_test_copy_cib.
*/
void pcmk__cib_test_cleanup(char *out_path);
void pcmk__test_init_logging(const char *name, const char *filename);
/*!
* \internal
* \brief Assert that a statement aborts through CRM_ASSERT().
*
* \param[in] stmt Statement to execute; can be an expression.
*
* A cmocka-like assert macro for use in unit testing. This one verifies that a
* statement aborts through CRM_ASSERT(), erroring out if that is not the case.
*
* This macro works by running the statement in a forked child process with core
* dumps disabled (CRM_ASSERT() calls \c abort(), which will write out a core
* dump). The parent waits for the child to exit and checks why. If the child
* received a \c SIGABRT, the test passes. For all other cases, the test fails.
*
* \note If cmocka's expect_*() or will_return() macros are called along with
* pcmk__assert_asserts(), they must be called within a block that is
* passed as the \c stmt argument. That way, the values are added only to
* the child's queue. Otherwise, values added to the parent's queue will
* never be popped, and the test will fail.
*/
#define pcmk__assert_asserts(stmt) \
do { \
pid_t p = fork(); \
if (p == 0) { \
struct rlimit cores = { 0, 0 }; \
setrlimit(RLIMIT_CORE, &cores); \
stmt; \
__gcov_dump(); \
_exit(0); \
} else if (p > 0) { \
int wstatus = 0; \
if (waitpid(p, &wstatus, 0) == -1) { \
fail_msg("waitpid failed"); \
} \
if (!(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT)) { \
fail_msg("statement terminated in child without asserting"); \
} \
} else { \
fail_msg("unable to fork for assert test"); \
} \
} while (0);
/*!
* \internal
* \brief Assert that a statement aborts
*
* This is exactly the same as pcmk__assert_asserts (CRM_ASSERT() is implemented
* with abort()), but given a different name for clarity.
*/
#define pcmk__assert_aborts(stmt) pcmk__assert_asserts(stmt)
/*!
* \internal
* \brief Assert that a statement exits with the expected exit status.
*
* \param[in] stmt Statement to execute; can be an expression.
* \param[in] rc The expected exit status.
*
* This functions just like \c pcmk__assert_asserts, except that it tests for
* an expected exit status. Abnormal termination or incorrect exit status is
* treated as a failure of the test.
*
* In the event that stmt does not exit at all, the special code \c CRM_EX_NONE
* will be returned. It is expected that this code is not used anywhere, thus
* always causing an error.
*/
#define pcmk__assert_exits(rc, stmt) \
do { \
pid_t p = fork(); \
if (p == 0) { \
struct rlimit cores = { 0, 0 }; \
setrlimit(RLIMIT_CORE, &cores); \
stmt; \
__gcov_dump(); \
_exit(CRM_EX_NONE); \
} else if (p > 0) { \
int wstatus = 0; \
if (waitpid(p, &wstatus, 0) == -1) { \
fail_msg("waitpid failed"); \
} \
if (!WIFEXITED(wstatus)) { \
fail_msg("statement terminated abnormally"); \
} else if (WEXITSTATUS(wstatus) != rc) { \
fail_msg("statement exited with %d, not expected %d", WEXITSTATUS(wstatus), rc); \
} \
} else { \
fail_msg("unable to fork for assert test"); \
} \
} while (0);
/* Generate the main function of most unit test files. Typically, group_setup
* and group_teardown will be NULL. The rest of the arguments are a list of
* calls to cmocka_unit_test or cmocka_unit_test_setup_teardown to run the
* individual unit tests.
*/
#define PCMK__UNIT_TEST(group_setup, group_teardown, ...) \
int \
main(int argc, char **argv) \
{ \
const struct CMUnitTest t[] = { \
__VA_ARGS__ \
}; \
cmocka_set_message_output(CM_OUTPUT_TAP); \
return cmocka_run_group_tests(t, group_setup, group_teardown); \
}
#endif /* CRM_COMMON_UNITTEST_INTERNAL__H */
diff --git a/lib/common/tests/acl/xml_acl_denied_test.c b/lib/common/tests/acl/xml_acl_denied_test.c
index 7c5457e63a..04054ac9ee 100644
--- a/lib/common/tests/acl/xml_acl_denied_test.c
+++ b/lib/common/tests/acl/xml_acl_denied_test.c
@@ -1,61 +1,61 @@
/*
* Copyright 2020-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/acl.h>
#include "../../crmcommon_private.h"
static void
is_xml_acl_denied_without_node(void **state)
{
xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml");
assert_false(xml_acl_denied(test_xml));
test_xml->doc->_private = NULL;
assert_false(xml_acl_denied(test_xml));
test_xml->doc = NULL;
assert_false(xml_acl_denied(test_xml));
test_xml = NULL;
assert_false(xml_acl_denied(test_xml));
}
static void
is_xml_acl_denied_with_node(void **state)
{
xml_doc_private_t *docpriv;
xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml");
// allocate memory for _private, which is NULL by default
test_xml->doc->_private = pcmk__assert_alloc(1, sizeof(xml_doc_private_t));
assert_false(xml_acl_denied(test_xml));
// cast _private from void* to xml_doc_private_t*
docpriv = test_xml->doc->_private;
// enable an irrelevant flag
docpriv->flags |= pcmk__xf_acl_enabled;
assert_false(xml_acl_denied(test_xml));
// enable pcmk__xf_acl_denied
docpriv->flags |= pcmk__xf_acl_denied;
assert_true(xml_acl_denied(test_xml));
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(is_xml_acl_denied_without_node),
cmocka_unit_test(is_xml_acl_denied_with_node))
diff --git a/lib/common/tests/acl/xml_acl_enabled_test.c b/lib/common/tests/acl/xml_acl_enabled_test.c
index 97e361ecf9..6a920a3c73 100644
--- a/lib/common/tests/acl/xml_acl_enabled_test.c
+++ b/lib/common/tests/acl/xml_acl_enabled_test.c
@@ -1,61 +1,61 @@
/*
* Copyright 2020-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/acl.h>
#include "../../crmcommon_private.h"
static void
is_xml_acl_enabled_without_node(void **state)
{
xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml");
assert_false(xml_acl_enabled(test_xml));
test_xml->doc->_private = NULL;
assert_false(xml_acl_enabled(test_xml));
test_xml->doc = NULL;
assert_false(xml_acl_enabled(test_xml));
test_xml = NULL;
assert_false(xml_acl_enabled(test_xml));
}
static void
is_xml_acl_enabled_with_node(void **state)
{
xml_doc_private_t *docpriv;
xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml");
// allocate memory for _private, which is NULL by default
test_xml->doc->_private = pcmk__assert_alloc(1, sizeof(xml_doc_private_t));
assert_false(xml_acl_enabled(test_xml));
// cast _private from void* to xml_doc_private_t*
docpriv = test_xml->doc->_private;
// enable an irrelevant flag
docpriv->flags |= pcmk__xf_acl_denied;
assert_false(xml_acl_enabled(test_xml));
// enable pcmk__xf_acl_enabled
docpriv->flags |= pcmk__xf_acl_enabled;
assert_true(xml_acl_enabled(test_xml));
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(is_xml_acl_enabled_without_node),
cmocka_unit_test(is_xml_acl_enabled_with_node))
diff --git a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c
index 60a71c0ef6..299eeefaa8 100644
--- a/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c
+++ b/lib/common/tests/iso8601/pcmk__add_time_from_xml_test.c
@@ -1,243 +1,243 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <libxml/tree.h> // xmlNode
#include <crm/common/unittest_internal.h>
#include <crm/common/iso8601.h>
#include <crm/common/iso8601_internal.h>
#include <crm/common/xml.h>
#include "../../crmcommon_private.h"
#define ALL_VALID "<duration id=\"duration1\" years=\"1\" months=\"2\" " \
"weeks=\"3\" days=\"-1\" hours=\"1\" minutes=\"1\" " \
"seconds=\"1\" />"
#define YEARS_INVALID "<duration id=\"duration1\" years=\"not-a-number\" />"
#define YEARS_TOO_BIG "<duration id=\"duration1\" years=\"2222222222\" />"
#define YEARS_TOO_SMALL "<duration id=\"duration1\" years=\"-2222222222\" />"
static void
null_time_invalid(void **state)
{
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(NULL, pcmk__time_years, xml),
EINVAL);
free_xml(xml);
}
static void
null_xml_ok(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = pcmk_copy_time(t);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, NULL),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
}
static void
invalid_component(void **state)
{
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(NULL, pcmk__time_unknown, xml),
EINVAL);
free_xml(xml);
}
static void
missing_attr(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = pcmk_copy_time(t);
xmlNode *xml = pcmk__xml_parse(YEARS_INVALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_months, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
invalid_attr(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = pcmk_copy_time(t);
xmlNode *xml = pcmk__xml_parse(YEARS_INVALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml),
pcmk_rc_unpack_error);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
out_of_range_attr(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = pcmk_copy_time(t);
xmlNode *xml = NULL;
xml = pcmk__xml_parse(YEARS_TOO_BIG);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), ERANGE);
assert_int_equal(crm_time_compare(t, reference), 0);
free_xml(xml);
xml = pcmk__xml_parse(YEARS_TOO_SMALL);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml), ERANGE);
assert_int_equal(crm_time_compare(t, reference), 0);
free_xml(xml);
crm_time_free(t);
crm_time_free(reference);
}
static void
add_years(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2025-01-01 15:00:00");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_years, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
add_months(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2024-03-01 15:00:00");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_months, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
add_weeks(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2024-01-22 15:00:00");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_weeks, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
add_days(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2023-12-31 15:00:00");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_days, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
add_hours(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2024-01-01 16:00:00");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_hours, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
add_minutes(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2024-01-01 15:01:00");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_minutes, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
add_seconds(void **state)
{
crm_time_t *t = crm_time_new("2024-01-01 15:00:00");
crm_time_t *reference = crm_time_new("2024-01-01 15:00:01");
xmlNode *xml = pcmk__xml_parse(ALL_VALID);
assert_int_equal(pcmk__add_time_from_xml(t, pcmk__time_seconds, xml),
pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_time_invalid),
cmocka_unit_test(null_xml_ok),
cmocka_unit_test(invalid_component),
cmocka_unit_test(missing_attr),
cmocka_unit_test(invalid_attr),
cmocka_unit_test(out_of_range_attr),
cmocka_unit_test(add_years),
cmocka_unit_test(add_months),
cmocka_unit_test(add_weeks),
cmocka_unit_test(add_days),
cmocka_unit_test(add_hours),
cmocka_unit_test(add_minutes),
cmocka_unit_test(add_seconds));
diff --git a/lib/common/tests/nodes/pcmk__xe_add_node_test.c b/lib/common/tests/nodes/pcmk__xe_add_node_test.c
index dd77527b88..6200307a62 100644
--- a/lib/common/tests/nodes/pcmk__xe_add_node_test.c
+++ b/lib/common/tests/nodes/pcmk__xe_add_node_test.c
@@ -1,71 +1,71 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/xml.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
static void
bad_input(void **state) {
xmlNode *node = NULL;
pcmk__assert_asserts(pcmk__xe_add_node(NULL, NULL, 0));
node = pcmk__xe_create(NULL, "test");
pcmk__xe_add_node(node, NULL, 0);
assert_null(xmlHasProp(node, (pcmkXmlStr) PCMK__XA_ATTR_HOST));
assert_null(xmlHasProp(node, (pcmkXmlStr) PCMK__XA_ATTR_HOST_ID));
pcmk__xe_add_node(node, NULL, -100);
assert_null(xmlHasProp(node, (pcmkXmlStr) PCMK__XA_ATTR_HOST));
assert_null(xmlHasProp(node, (pcmkXmlStr) PCMK__XA_ATTR_HOST_ID));
free_xml(node);
}
static void
expected_input(void **state) {
xmlNode *node = pcmk__xe_create(NULL, "test");
int i;
pcmk__xe_add_node(node, "somenode", 47);
assert_string_equal("somenode",
crm_element_value(node, PCMK__XA_ATTR_HOST));
assert_int_equal(pcmk_rc_ok,
crm_element_value_int(node, PCMK__XA_ATTR_HOST_ID, &i));
assert_int_equal(i, 47);
free_xml(node);
}
static void
repeated_use(void **state) {
xmlNode *node = pcmk__xe_create(NULL, "test");
int i;
/* Later calls override settings from earlier calls. */
pcmk__xe_add_node(node, "nodeA", 1);
pcmk__xe_add_node(node, "nodeB", 2);
pcmk__xe_add_node(node, "nodeC", 3);
assert_string_equal("nodeC", crm_element_value(node, PCMK__XA_ATTR_HOST));
assert_int_equal(pcmk_rc_ok,
crm_element_value_int(node, PCMK__XA_ATTR_HOST_ID, &i));
assert_int_equal(i, 3);
free_xml(node);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(bad_input),
cmocka_unit_test(expected_input),
cmocka_unit_test(repeated_use))
diff --git a/lib/common/tests/nvpair/pcmk__xe_attr_is_true_test.c b/lib/common/tests/nvpair/pcmk__xe_attr_is_true_test.c
index 84187da754..c36515bfc6 100644
--- a/lib/common/tests/nvpair/pcmk__xe_attr_is_true_test.c
+++ b/lib/common/tests/nvpair/pcmk__xe_attr_is_true_test.c
@@ -1,50 +1,50 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
static void
empty_input(void **state)
{
xmlNode *node = pcmk__xml_parse("<node/>");
assert_false(pcmk__xe_attr_is_true(NULL, NULL));
assert_false(pcmk__xe_attr_is_true(NULL, "whatever"));
assert_false(pcmk__xe_attr_is_true(node, NULL));
free_xml(node);
}
static void
attr_missing(void **state)
{
xmlNode *node = pcmk__xml_parse("<node a=\"true\" b=\"false\"/>");
assert_false(pcmk__xe_attr_is_true(node, "c"));
free_xml(node);
}
static void
attr_present(void **state)
{
xmlNode *node = pcmk__xml_parse("<node a=\"true\" b=\"false\"/>");
assert_true(pcmk__xe_attr_is_true(node, "a"));
assert_false(pcmk__xe_attr_is_true(node, "b"));
free_xml(node);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(empty_input),
cmocka_unit_test(attr_missing),
cmocka_unit_test(attr_present))
diff --git a/lib/common/tests/nvpair/pcmk__xe_get_bool_attr_test.c b/lib/common/tests/nvpair/pcmk__xe_get_bool_attr_test.c
index 4823f6a73b..2f7827c000 100644
--- a/lib/common/tests/nvpair/pcmk__xe_get_bool_attr_test.c
+++ b/lib/common/tests/nvpair/pcmk__xe_get_bool_attr_test.c
@@ -1,60 +1,60 @@
/*
* Copyright 2021-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
static void
empty_input(void **state)
{
xmlNode *node = pcmk__xml_parse("<node/>");
bool value;
assert_int_equal(pcmk__xe_get_bool_attr(NULL, NULL, &value), ENODATA);
assert_int_equal(pcmk__xe_get_bool_attr(NULL, "whatever", &value), ENODATA);
assert_int_equal(pcmk__xe_get_bool_attr(node, NULL, &value), EINVAL);
assert_int_equal(pcmk__xe_get_bool_attr(node, "whatever", NULL), EINVAL);
free_xml(node);
}
static void
attr_missing(void **state)
{
xmlNode *node = pcmk__xml_parse("<node a=\"true\" b=\"false\"/>");
bool value;
assert_int_equal(pcmk__xe_get_bool_attr(node, "c", &value), ENODATA);
free_xml(node);
}
static void
attr_present(void **state)
{
xmlNode *node = pcmk__xml_parse("<node a=\"true\" b=\"false\" "
"c=\"blah\"/>");
bool value;
value = false;
assert_int_equal(pcmk__xe_get_bool_attr(node, "a", &value), pcmk_rc_ok);
assert_true(value);
value = true;
assert_int_equal(pcmk__xe_get_bool_attr(node, "b", &value), pcmk_rc_ok);
assert_false(value);
assert_int_equal(pcmk__xe_get_bool_attr(node, "c", &value), pcmk_rc_bad_input);
free_xml(node);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(empty_input),
cmocka_unit_test(attr_missing),
cmocka_unit_test(attr_present))
diff --git a/lib/common/tests/nvpair/pcmk__xe_get_datetime_test.c b/lib/common/tests/nvpair/pcmk__xe_get_datetime_test.c
index 6da1e237f5..36ebdc2297 100644
--- a/lib/common/tests/nvpair/pcmk__xe_get_datetime_test.c
+++ b/lib/common/tests/nvpair/pcmk__xe_get_datetime_test.c
@@ -1,108 +1,108 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <errno.h>
#include <libxml/tree.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/iso8601.h>
#include <crm/common/xml.h>
#include <crm/common/nvpair_internal.h>
#define REFERENCE_ISO8601 "2024-001"
#define ATTR_PRESENT "start"
#define ATTR_MISSING "end"
#define REFERENCE_XML "<date_expression id=\"id1\" " \
ATTR_PRESENT "=\"" REFERENCE_ISO8601 "\"" \
" operation=\"gt\">"
#define BAD_XML "<date_expression id=\"id1\" " \
ATTR_PRESENT "=\"not_a_time\"" \
" operation=\"gt\">"
static void
null_invalid(void **state)
{
xmlNode *xml = pcmk__xml_parse(REFERENCE_XML);
crm_time_t *t = NULL;
assert_int_equal(pcmk__xe_get_datetime(NULL, NULL, NULL), EINVAL);
assert_int_equal(pcmk__xe_get_datetime(xml, NULL, NULL), EINVAL);
assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, NULL), EINVAL);
assert_int_equal(pcmk__xe_get_datetime(xml, NULL, &t), EINVAL);
assert_null(t);
assert_int_equal(pcmk__xe_get_datetime(NULL, ATTR_PRESENT, NULL), EINVAL);
assert_int_equal(pcmk__xe_get_datetime(NULL, ATTR_PRESENT, &t), EINVAL);
assert_null(t);
assert_int_equal(pcmk__xe_get_datetime(NULL, NULL, &t), EINVAL);
assert_null(t);
free_xml(xml);
}
static void
nonnull_time_invalid(void **state)
{
xmlNode *xml = pcmk__xml_parse(REFERENCE_XML);
crm_time_t *t = crm_time_new_undefined();
assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t), EINVAL);
crm_time_free(t);
free_xml(xml);
}
static void
attr_missing(void **state)
{
xmlNode *xml = pcmk__xml_parse(REFERENCE_XML);
crm_time_t *t = NULL;
assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_MISSING, &t), pcmk_rc_ok);
assert_null(t);
free_xml(xml);
}
static void
attr_valid(void **state)
{
xmlNode *xml = pcmk__xml_parse(REFERENCE_XML);
crm_time_t *t = NULL;
crm_time_t *reference = crm_time_new(REFERENCE_ISO8601);
assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t), pcmk_rc_ok);
assert_int_equal(crm_time_compare(t, reference), 0);
crm_time_free(t);
crm_time_free(reference);
free_xml(xml);
}
static void
attr_invalid(void **state)
{
xmlNode *xml = pcmk__xml_parse(BAD_XML);
crm_time_t *t = NULL;
assert_int_equal(pcmk__xe_get_datetime(xml, ATTR_PRESENT, &t),
pcmk_rc_unpack_error);
assert_null(t);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(nonnull_time_invalid),
cmocka_unit_test(attr_missing),
cmocka_unit_test(attr_valid),
cmocka_unit_test(attr_invalid))
diff --git a/lib/common/tests/nvpair/pcmk__xe_set_bool_attr_test.c b/lib/common/tests/nvpair/pcmk__xe_set_bool_attr_test.c
index dda2878c20..e8250319d1 100644
--- a/lib/common/tests/nvpair/pcmk__xe_set_bool_attr_test.c
+++ b/lib/common/tests/nvpair/pcmk__xe_set_bool_attr_test.c
@@ -1,31 +1,31 @@
/*
* Copyright 2021-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
#include <crm/common/xml.h>
static void
set_attr(void **state)
{
xmlNode *node = pcmk__xml_parse("<node/>");
pcmk__xe_set_bool_attr(node, "a", true);
pcmk__xe_set_bool_attr(node, "b", false);
assert_string_equal(crm_element_value(node, "a"), PCMK_VALUE_TRUE);
assert_string_equal(crm_element_value(node, "b"), PCMK_VALUE_FALSE);
free_xml(node);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(set_attr))
diff --git a/lib/common/tests/probes/pcmk_xe_is_probe_test.c b/lib/common/tests/probes/pcmk_xe_is_probe_test.c
index e42476aa27..b10c53884a 100644
--- a/lib/common/tests/probes/pcmk_xe_is_probe_test.c
+++ b/lib/common/tests/probes/pcmk_xe_is_probe_test.c
@@ -1,54 +1,54 @@
/*
* Copyright 2021-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
static void
op_is_probe_test(void **state)
{
xmlNode *node = NULL;
assert_false(pcmk_xe_is_probe(NULL));
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP "/>");
assert_false(pcmk_xe_is_probe(node));
free_xml(node);
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP " "
PCMK__XA_OPERATION_KEY "=\"blah\" "
PCMK_META_INTERVAL "=\"30s\"/>");
assert_false(pcmk_xe_is_probe(node));
free_xml(node);
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION
"=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"30s\"/>");
assert_false(pcmk_xe_is_probe(node));
free_xml(node);
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION
"=\"" PCMK_ACTION_START "\" "
PCMK_META_INTERVAL "=\"0\"/>");
assert_false(pcmk_xe_is_probe(node));
free_xml(node);
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION
"=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\"/>");
assert_true(pcmk_xe_is_probe(node));
free_xml(node);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(op_is_probe_test))
diff --git a/lib/common/tests/probes/pcmk_xe_mask_probe_failure_test.c b/lib/common/tests/probes/pcmk_xe_mask_probe_failure_test.c
index ad378bf6fd..9279f279ae 100644
--- a/lib/common/tests/probes/pcmk_xe_mask_probe_failure_test.c
+++ b/lib/common/tests/probes/pcmk_xe_mask_probe_failure_test.c
@@ -1,333 +1,333 @@
/*
* Copyright 2021-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
static void
op_is_not_probe_test(void **state) {
xmlNode *node = NULL;
/* Not worth testing this thoroughly since it's just a duplicate of whether
* pcmk_op_is_probe works or not.
*/
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION
"=\"" PCMK_ACTION_START "\" "
PCMK_META_INTERVAL "=\"0\"/>");
assert_false(pcmk_xe_mask_probe_failure(node));
free_xml(node);
}
static void
op_does_not_have_right_values_test(void **state) {
xmlNode *node = NULL;
char *s = NULL;
node = pcmk__xml_parse("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION
"=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\"/>");
assert_false(pcmk_xe_mask_probe_failure(node));
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"\"/>",
PCMK_OCF_OK);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
}
static void
check_values_test(void **state) {
xmlNode *node = NULL;
char *s = NULL;
/* PCMK_EXEC_NOT_SUPPORTED */
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_OK, PCMK_EXEC_NOT_SUPPORTED);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_INSTALLED, PCMK_EXEC_NOT_SUPPORTED);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
/* PCMK_EXEC_DONE */
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_OK, PCMK_EXEC_DONE);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_INVALID_PARAM, PCMK_EXEC_DONE);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_INSTALLED, PCMK_EXEC_DONE);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_DONE);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_RUNNING, PCMK_EXEC_DONE);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
/* PCMK_EXEC_NOT_INSTALLED */
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_OK, PCMK_EXEC_NOT_INSTALLED);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_INSTALLED, PCMK_EXEC_NOT_INSTALLED);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
/* PCMK_EXEC_ERROR */
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_OK, PCMK_EXEC_ERROR);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_INVALID_PARAM, PCMK_EXEC_ERROR);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_INSTALLED, PCMK_EXEC_ERROR);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_RUNNING, PCMK_EXEC_ERROR);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
/* PCMK_EXEC_ERROR_HARD */
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_OK, PCMK_EXEC_ERROR_HARD);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_INVALID_PARAM, PCMK_EXEC_ERROR_HARD);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_INSTALLED, PCMK_EXEC_ERROR_HARD);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_HARD);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_RUNNING, PCMK_EXEC_ERROR_HARD);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
/* PCMK_EXEC_ERROR_FATAL */
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_OK, PCMK_EXEC_ERROR_FATAL);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_INVALID_PARAM, PCMK_EXEC_ERROR_FATAL);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_INSTALLED, PCMK_EXEC_ERROR_FATAL);
node = pcmk__xml_parse(s);
assert_true(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_CONFIGURED, PCMK_EXEC_ERROR_FATAL);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
s = crm_strdup_printf("<" PCMK__XE_LRM_RSC_OP " "
PCMK_XA_OPERATION "=\"" PCMK_ACTION_MONITOR "\" "
PCMK_META_INTERVAL "=\"0\" "
PCMK__XA_RC_CODE "=\"%d\" "
PCMK__XA_OP_STATUS "=\"%d\"/>",
PCMK_OCF_NOT_RUNNING, PCMK_EXEC_ERROR_FATAL);
node = pcmk__xml_parse(s);
assert_false(pcmk_xe_mask_probe_failure(node));
free(s);
free_xml(node);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(op_is_not_probe_test),
cmocka_unit_test(op_does_not_have_right_values_test),
cmocka_unit_test(check_values_test))
diff --git a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c
index d28cb1197b..44f2e2eb71 100644
--- a/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c
+++ b/lib/common/tests/rules/pcmk__evaluate_attr_expression_test.c
@@ -1,831 +1,831 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
#include "crmcommon_private.h"
/*
* Shared data
*/
#define MATCHED_STRING "server-north"
static const regmatch_t submatches[] = {
{ .rm_so = 0, .rm_eo = 12 }, // %0 = Entire string
{ .rm_so = 7, .rm_eo = 12 }, // %1 = "north"
};
static pcmk_rule_input_t rule_input = {
// These are the only members used to evaluate attribute expressions
// Used to replace submatches in attribute name
.rsc_id = MATCHED_STRING,
.rsc_id_submatches = submatches,
.rsc_id_nmatches = 2,
// Used when source is instance attributes
.rsc_params = NULL,
// Used when source is meta-attributes
.rsc_meta = NULL,
// Used to get actual value of node attribute
.node_attrs = NULL,
};
static int
setup(void **state)
{
rule_input.rsc_params = pcmk__strkey_table(free, free);
pcmk__insert_dup(rule_input.rsc_params, "foo-param", "bar");
pcmk__insert_dup(rule_input.rsc_params, "myparam", "different");
rule_input.rsc_meta = pcmk__strkey_table(free, free);
pcmk__insert_dup(rule_input.rsc_meta, "foo-meta", "bar");
pcmk__insert_dup(rule_input.rsc_params, "mymeta", "different");
rule_input.node_attrs = pcmk__strkey_table(free, free);
pcmk__insert_dup(rule_input.node_attrs, "foo", "bar");
pcmk__insert_dup(rule_input.node_attrs, "num", "10");
pcmk__insert_dup(rule_input.node_attrs, "ver", "3.5.0");
pcmk__insert_dup(rule_input.node_attrs, "prefer-north", "100");
return 0;
}
static int
teardown(void **state)
{
g_hash_table_destroy(rule_input.rsc_params);
g_hash_table_destroy(rule_input.rsc_meta);
g_hash_table_destroy(rule_input.node_attrs);
return 0;
}
/*!
* \internal
* \brief Run one test, comparing return value
*
* \param[in] xml_string Node attribute expression XML as string
* \param[in] reference_rc Assert that evaluation result equals this
*/
static void
assert_attr_expression(const char *xml_string, int reference_rc)
{
xmlNode *xml = pcmk__xml_parse(xml_string);
assert_int_equal(pcmk__evaluate_attr_expression(xml, &rule_input),
reference_rc);
free_xml(xml);
}
/*
* Invalid arguments
*/
#define EXPR_SOURCE_LITERAL_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
static void
null_invalid(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_SOURCE_LITERAL_PASSES);
assert_int_equal(pcmk__evaluate_attr_expression(NULL, NULL), EINVAL);
assert_int_equal(pcmk__evaluate_attr_expression(xml, NULL), EINVAL);
assert_int_equal(pcmk__evaluate_attr_expression(NULL, &rule_input), EINVAL);
free_xml(xml);
}
/*
* Test PCMK_XA_ID
*/
#define EXPR_ID_MISSING \
"<" PCMK_XE_EXPRESSION " " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' />"
static void
id_missing(void **state)
{
// Currently acceptable
assert_attr_expression(EXPR_ID_MISSING, pcmk_rc_ok);
}
/*
* Test PCMK_XA_ATTRIBUTE
*/
#define EXPR_ATTR_MISSING \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' />"
static void
attr_missing(void **state)
{
assert_attr_expression(EXPR_ATTR_MISSING, pcmk_rc_unpack_error);
}
#define EXPR_ATTR_SUBMATCH_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='prefer-%1' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
static void
attr_with_submatch_passes(void **state)
{
assert_attr_expression(EXPR_ATTR_SUBMATCH_PASSES, pcmk_rc_ok);
}
#define EXPR_ATTR_SUBMATCH_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='undefined-%1' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
static void
attr_with_submatch_fails(void **state)
{
assert_attr_expression(EXPR_ATTR_SUBMATCH_FAILS, pcmk_rc_op_unsatisfied);
}
/*
* Test PCMK_XA_VALUE_SOURCE
*/
#define EXPR_SOURCE_MISSING \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_VALUE "='bar' />"
static void
source_missing(void **state)
{
// Defaults to literal
assert_attr_expression(EXPR_SOURCE_MISSING, pcmk_rc_ok);
}
#define EXPR_SOURCE_INVALID \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' " \
PCMK_XA_VALUE_SOURCE "='not-a-source' />"
static void
source_invalid(void **state)
{
// Currently treated as literal
assert_attr_expression(EXPR_SOURCE_INVALID, pcmk_rc_ok);
}
static void
source_literal_passes(void **state)
{
assert_attr_expression(EXPR_SOURCE_LITERAL_PASSES, pcmk_rc_ok);
}
#define EXPR_SOURCE_LITERAL_VALUE_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='wrong-value' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
static void
source_literal_value_fails(void **state)
{
assert_attr_expression(EXPR_SOURCE_LITERAL_VALUE_FAILS,
pcmk_rc_op_unsatisfied);
}
#define EXPR_SOURCE_LITERAL_ATTR_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='not-an-attribute' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
static void
source_literal_attr_fails(void **state)
{
assert_attr_expression(EXPR_SOURCE_LITERAL_ATTR_FAILS,
pcmk_rc_op_unsatisfied);
}
#define EXPR_SOURCE_PARAM_MISSING \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='not-a-param' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
static void
source_params_missing(void **state)
{
assert_attr_expression(EXPR_SOURCE_PARAM_MISSING, pcmk_rc_op_unsatisfied);
}
#define EXPR_SOURCE_PARAM_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='foo-param' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
static void
source_params_passes(void **state)
{
assert_attr_expression(EXPR_SOURCE_PARAM_PASSES, pcmk_rc_ok);
}
#define EXPR_SOURCE_PARAM_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='myparam' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_PARAM "' />"
static void
source_params_fails(void **state)
{
assert_attr_expression(EXPR_SOURCE_PARAM_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_SOURCE_META_MISSING \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='not-a-meta' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
static void
source_meta_missing(void **state)
{
assert_attr_expression(EXPR_SOURCE_META_MISSING, pcmk_rc_op_unsatisfied);
}
#define EXPR_SOURCE_META_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='foo-meta' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
static void
source_meta_passes(void **state)
{
assert_attr_expression(EXPR_SOURCE_META_PASSES, pcmk_rc_ok);
}
#define EXPR_SOURCE_META_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='mymeta' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_META "' />"
static void
source_meta_fails(void **state)
{
assert_attr_expression(EXPR_SOURCE_META_FAILS, pcmk_rc_op_unsatisfied);
}
/*
* Test PCMK_XA_TYPE
*/
#define EXPR_TYPE_DEFAULT_NUMBER \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='2.5' />"
static void
type_default_number(void **state)
{
// Defaults to number for "gt" if either value contains a decimal point
assert_attr_expression(EXPR_TYPE_DEFAULT_NUMBER, pcmk_rc_ok);
}
#define EXPR_TYPE_DEFAULT_INT \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='2' />"
static void
type_default_int(void **state)
{
// Defaults to integer for "gt" if neither value contains a decimal point
assert_attr_expression(EXPR_TYPE_DEFAULT_INT, pcmk_rc_ok);
}
#define EXPR_TYPE_STRING_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_VALUE "='bar' />"
static void
type_string_passes(void **state)
{
assert_attr_expression(EXPR_TYPE_STRING_PASSES, pcmk_rc_ok);
}
#define EXPR_TYPE_STRING_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_VALUE "='bat' />"
static void
type_string_fails(void **state)
{
assert_attr_expression(EXPR_TYPE_STRING_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_TYPE_INTEGER_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10' />"
static void
type_integer_passes(void **state)
{
assert_attr_expression(EXPR_TYPE_INTEGER_PASSES, pcmk_rc_ok);
}
#define EXPR_TYPE_INTEGER_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='11' />"
static void
type_integer_fails(void **state)
{
assert_attr_expression(EXPR_TYPE_INTEGER_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_TYPE_INTEGER_TRUNCATION \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10.5' />"
static void
type_integer_truncation(void **state)
{
assert_attr_expression(EXPR_TYPE_INTEGER_TRUNCATION, pcmk_rc_ok);
}
#define EXPR_TYPE_NUMBER_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10.0' />"
static void
type_number_passes(void **state)
{
assert_attr_expression(EXPR_TYPE_NUMBER_PASSES, pcmk_rc_ok);
}
#define EXPR_TYPE_NUMBER_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10.1' />"
static void
type_number_fails(void **state)
{
assert_attr_expression(EXPR_TYPE_NUMBER_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_TYPE_VERSION_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_ATTRIBUTE "='ver' " \
PCMK_XA_VALUE "='3.4.9' />"
static void
type_version_passes(void **state)
{
assert_attr_expression(EXPR_TYPE_VERSION_PASSES, pcmk_rc_ok);
}
#define EXPR_TYPE_VERSION_EQUALITY \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='ver' " \
PCMK_XA_VALUE "='3.5' />"
static void
type_version_equality(void **state)
{
assert_attr_expression(EXPR_TYPE_VERSION_EQUALITY, pcmk_rc_ok);
}
#define EXPR_TYPE_VERSION_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_VERSION "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' " \
PCMK_XA_ATTRIBUTE "='ver' " \
PCMK_XA_VALUE "='4.0' />"
static void
type_version_fails(void **state)
{
assert_attr_expression(EXPR_TYPE_VERSION_FAILS, pcmk_rc_before_range);
}
/*
* Test PCMK_XA_OPERATION
*/
#define EXPR_OP_MISSING \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_VALUE "='bar' />"
static void
op_missing(void **state)
{
assert_attr_expression(EXPR_OP_MISSING, pcmk_rc_unpack_error);
}
#define EXPR_OP_INVALID \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='not-an-operation' " \
PCMK_XA_VALUE "='bar' />"
static void
op_invalid(void **state)
{
assert_attr_expression(EXPR_OP_INVALID, pcmk_rc_unpack_error);
}
#define EXPR_OP_LT_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='20' />"
static void
op_lt_passes(void **state)
{
assert_attr_expression(EXPR_OP_LT_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_LT_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='2' />"
static void
op_lt_fails(void **state)
{
assert_attr_expression(EXPR_OP_LT_FAILS, pcmk_rc_after_range);
}
#define EXPR_OP_GT_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='2' />"
static void
op_gt_passes(void **state)
{
assert_attr_expression(EXPR_OP_GT_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_GT_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='20' />"
static void
op_gt_fails(void **state)
{
assert_attr_expression(EXPR_OP_GT_FAILS, pcmk_rc_before_range);
}
#define EXPR_OP_LTE_LT_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='20' />"
static void
op_lte_lt_passes(void **state)
{
assert_attr_expression(EXPR_OP_LTE_LT_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_LTE_EQ_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10' />"
static void
op_lte_eq_passes(void **state)
{
assert_attr_expression(EXPR_OP_LTE_EQ_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_LTE_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LTE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='9' />"
static void
op_lte_fails(void **state)
{
assert_attr_expression(EXPR_OP_LTE_FAILS, pcmk_rc_after_range);
}
#define EXPR_OP_GTE_GT_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='1' />"
static void
op_gte_gt_passes(void **state)
{
assert_attr_expression(EXPR_OP_GTE_GT_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_GTE_EQ_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10' />"
static void
op_gte_eq_passes(void **state)
{
assert_attr_expression(EXPR_OP_GTE_EQ_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_GTE_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GTE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='11' />"
static void
op_gte_fails(void **state)
{
assert_attr_expression(EXPR_OP_GTE_FAILS, pcmk_rc_before_range);
}
// This also tests that string is used if values aren't parseable as numbers
#define EXPR_OP_EQ_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_NUMBER "' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
static void
op_eq_passes(void **state)
{
assert_attr_expression(EXPR_OP_EQ_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_EQ_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='bar' />"
static void
op_eq_fails(void **state)
{
assert_attr_expression(EXPR_OP_EQ_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_OP_NE_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_STRING "' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_NE "' " \
PCMK_XA_VALUE "='bat' " \
PCMK_XA_VALUE_SOURCE "='" PCMK_VALUE_LITERAL "' />"
static void
op_ne_passes(void **state)
{
assert_attr_expression(EXPR_OP_NE_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_NE_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_TYPE "='" PCMK_VALUE_INTEGER "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_NE "' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_VALUE "='10' />"
static void
op_ne_fails(void **state)
{
assert_attr_expression(EXPR_OP_NE_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_OP_DEFINED_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
static void
op_defined_passes(void **state)
{
assert_attr_expression(EXPR_OP_DEFINED_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_DEFINED_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='boo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
static void
op_defined_fails(void **state)
{
assert_attr_expression(EXPR_OP_DEFINED_FAILS, pcmk_rc_op_unsatisfied);
}
#define EXPR_OP_DEFINED_WITH_VALUE \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_VALUE "='bar' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
static void
op_defined_with_value(void **state)
{
// Ill-formed but currently accepted
assert_attr_expression(EXPR_OP_DEFINED_WITH_VALUE, pcmk_rc_ok);
}
#define EXPR_OP_UNDEFINED_PASSES \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='boo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
static void
op_undefined_passes(void **state)
{
assert_attr_expression(EXPR_OP_UNDEFINED_PASSES, pcmk_rc_ok);
}
#define EXPR_OP_UNDEFINED_FAILS \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_NOT_DEFINED "' />"
static void
op_undefined_fails(void **state)
{
assert_attr_expression(EXPR_OP_DEFINED_FAILS, pcmk_rc_op_unsatisfied);
}
/*
* Test PCMK_XA_VALUE
*/
#define EXPR_VALUE_MISSING_DEFINED_OK \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='num' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DEFINED "' />"
static void
value_missing_defined_ok(void **state)
{
assert_attr_expression(EXPR_VALUE_MISSING_DEFINED_OK, pcmk_rc_ok);
}
#define EXPR_VALUE_MISSING_EQ_OK \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='not-an-attr' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' />"
static void
value_missing_eq_ok(void **state)
{
// Currently treated as NULL reference value
assert_attr_expression(EXPR_VALUE_MISSING_EQ_OK, pcmk_rc_ok);
}
#define expr_test(f) cmocka_unit_test_setup_teardown(f, setup, teardown)
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
expr_test(id_missing),
expr_test(attr_missing),
expr_test(attr_with_submatch_passes),
expr_test(attr_with_submatch_fails),
expr_test(source_missing),
expr_test(source_invalid),
expr_test(source_literal_passes),
expr_test(source_literal_value_fails),
expr_test(source_literal_attr_fails),
expr_test(source_params_missing),
expr_test(source_params_passes),
expr_test(source_params_fails),
expr_test(source_meta_missing),
expr_test(source_meta_passes),
expr_test(source_meta_fails),
expr_test(type_default_number),
expr_test(type_default_int),
expr_test(type_string_passes),
expr_test(type_string_fails),
expr_test(type_integer_passes),
expr_test(type_integer_fails),
expr_test(type_integer_truncation),
expr_test(type_number_passes),
expr_test(type_number_fails),
expr_test(type_version_passes),
expr_test(type_version_equality),
expr_test(type_version_fails),
expr_test(op_missing),
expr_test(op_invalid),
expr_test(op_lt_passes),
expr_test(op_lt_fails),
expr_test(op_gt_passes),
expr_test(op_gt_fails),
expr_test(op_lte_lt_passes),
expr_test(op_lte_eq_passes),
expr_test(op_lte_fails),
expr_test(op_gte_gt_passes),
expr_test(op_gte_eq_passes),
expr_test(op_gte_fails),
expr_test(op_eq_passes),
expr_test(op_eq_fails),
expr_test(op_ne_passes),
expr_test(op_ne_fails),
expr_test(op_defined_passes),
expr_test(op_defined_fails),
expr_test(op_defined_with_value),
expr_test(op_undefined_passes),
expr_test(op_undefined_fails),
expr_test(value_missing_defined_ok),
expr_test(value_missing_eq_ok))
diff --git a/lib/common/tests/rules/pcmk__evaluate_condition_test.c b/lib/common/tests/rules/pcmk__evaluate_condition_test.c
index bcb13a0ea6..68cf1f1eb0 100644
--- a/lib/common/tests/rules/pcmk__evaluate_condition_test.c
+++ b/lib/common/tests/rules/pcmk__evaluate_condition_test.c
@@ -1,197 +1,197 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
/*
* Shared data
*/
static pcmk_rule_input_t rule_input = {
.rsc_standard = PCMK_RESOURCE_CLASS_OCF,
.rsc_provider = "heartbeat",
.rsc_agent = "IPaddr2",
.op_name = PCMK_ACTION_MONITOR,
.op_interval_ms = 10000,
};
/*
* Test invalid arguments
*/
#define EXPR_ATTRIBUTE \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='foo' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='bar' />"
static void
null_invalid(void **state)
{
xmlNode *xml = NULL;
crm_time_t *next_change = crm_time_new_undefined();
assert_int_equal(pcmk__evaluate_condition(NULL, NULL, next_change), EINVAL);
xml = pcmk__xml_parse(EXPR_ATTRIBUTE);
assert_int_equal(pcmk__evaluate_condition(xml, NULL, next_change), EINVAL);
free_xml(xml);
assert_int_equal(pcmk__evaluate_condition(NULL, &rule_input, next_change),
EINVAL);
crm_time_free(next_change);
}
#define EXPR_INVALID "<not_an_expression " PCMK_XA_ID "='e' />"
static void
invalid_expression(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_INVALID);
crm_time_t *next_change = crm_time_new_undefined();
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, next_change),
pcmk_rc_unpack_error);
crm_time_free(next_change);
free_xml(xml);
}
/* Each expression type function already has unit tests, so we just need to test
* that they are called correctly (essentially, one of each one's own tests).
*/
static void
attribute_expression(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_ATTRIBUTE);
rule_input.node_attrs = pcmk__strkey_table(free, free);
pcmk__insert_dup(rule_input.node_attrs, "foo", "bar");
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, NULL),
pcmk_rc_ok);
g_hash_table_destroy(rule_input.node_attrs);
rule_input.node_attrs = NULL;
free_xml(xml);
}
#define EXPR_LOCATION \
"<" PCMK_XE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_ATTRIBUTE "='" CRM_ATTR_UNAME "' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_EQ "' " \
PCMK_XA_VALUE "='node1' />"
static void
location_expression(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_LOCATION);
rule_input.node_attrs = pcmk__strkey_table(free, free);
pcmk__insert_dup(rule_input.node_attrs, CRM_ATTR_UNAME, "node1");
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, NULL),
pcmk_rc_ok);
g_hash_table_destroy(rule_input.node_attrs);
rule_input.node_attrs = NULL;
free_xml(xml);
}
#define EXPR_DATE \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00' " \
PCMK_XA_END "='2024-02-01 15:00:00' />"
static void
date_expression(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_DATE);
crm_time_t *now = crm_time_new("2024-02-01 11:59:59");
crm_time_t *next_change = crm_time_new("2024-02-01 14:00:00");
crm_time_t *reference = crm_time_new("2024-02-01 12:00:00");
rule_input.now = now;
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, next_change),
pcmk_rc_before_range);
assert_int_equal(crm_time_compare(next_change, reference), 0);
rule_input.now = NULL;
crm_time_free(reference);
crm_time_free(next_change);
crm_time_free(now);
}
#define EXPR_RESOURCE \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_TYPE "='IPaddr2' />"
static void
resource_expression(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_RESOURCE);
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, NULL),
pcmk_rc_ok);
free_xml(xml);
}
#define EXPR_OP \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />"
static void
op_expression(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_OP);
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, NULL),
pcmk_rc_ok);
free_xml(xml);
}
#define EXPR_SUBRULE \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' /> />"
static void
subrule(void **state)
{
xmlNode *xml = pcmk__xml_parse(EXPR_SUBRULE);
assert_int_equal(pcmk__evaluate_condition(xml, &rule_input, NULL),
pcmk_rc_ok);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(invalid_expression),
cmocka_unit_test(attribute_expression),
cmocka_unit_test(location_expression),
cmocka_unit_test(date_expression),
cmocka_unit_test(resource_expression),
cmocka_unit_test(op_expression),
cmocka_unit_test(subrule))
diff --git a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c
index df8dcbfd42..482e922912 100644
--- a/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c
+++ b/lib/common/tests/rules/pcmk__evaluate_date_expression_test.c
@@ -1,684 +1,684 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
#include "crmcommon_private.h"
/*!
* \internal
* \brief Run one test, comparing return value and output argument
*
* \param[in] xml Date expression XML
* \param[in] now_s Time to evaluate expression with (as string)
* \param[in] next_change_s If this and \p reference_s are not NULL, initialize
* next change time with this time (as string),
* and assert that its value after evaluation is the
* reference
* \param[in] reference_s If not NULL, time (as string) that next change
* should be after expression evaluation
* \param[in] reference_rc Assert that evaluation result equals this
*/
static void
assert_date_expression(const xmlNode *xml, const char *now_s,
const char *next_change_s, const char *reference_s,
int reference_rc)
{
crm_time_t *now = NULL;
crm_time_t *next_change = NULL;
bool check_next_change = (next_change_s != NULL) && (reference_s != NULL);
if (check_next_change) {
next_change = crm_time_new(next_change_s);
}
now = crm_time_new(now_s);
assert_int_equal(pcmk__evaluate_date_expression(xml, now, next_change),
reference_rc);
crm_time_free(now);
if (check_next_change) {
crm_time_t *reference = crm_time_new(reference_s);
assert_int_equal(crm_time_compare(next_change, reference), 0);
crm_time_free(reference);
crm_time_free(next_change);
}
}
#define EXPR_LT_VALID \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' " \
PCMK_XA_END "='2024-02-01 15:00:00' />"
static void
null_invalid(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
crm_time_t *t = crm_time_new("2024-02-01");
assert_int_equal(pcmk__evaluate_date_expression(NULL, NULL, NULL), EINVAL);
assert_int_equal(pcmk__evaluate_date_expression(xml, NULL, NULL), EINVAL);
assert_int_equal(pcmk__evaluate_date_expression(NULL, t, NULL), EINVAL);
crm_time_free(t);
free_xml(xml);
}
static void
null_next_change_ok(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_within_range);
free_xml(xml);
}
#define EXPR_ID_MISSING \
"<" PCMK_XE_DATE_EXPRESSION " " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' " \
PCMK_XA_END "='2024-02-01 15:00:00' />"
static void
id_missing(void **state)
{
// Currently acceptable
xmlNodePtr xml = pcmk__xml_parse(EXPR_ID_MISSING);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_within_range);
free_xml(xml);
}
#define EXPR_OP_INVALID \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='not-a-choice' />"
static void
op_invalid(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_OP_INVALID);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_LT_MISSING_END \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' />"
static void
lt_missing_end(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_MISSING_END);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_LT_INVALID_END \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_LT "' " \
PCMK_XA_END "='not-a-datetime' />"
static void
lt_invalid_end(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_INVALID_END);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
static void
lt_valid(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_LT_VALID);
// Now and next change are both before end
assert_date_expression(xml, "2023-01-01 05:00:00", "2024-02-01 10:00:00",
"2024-02-01 10:00:00", pcmk_rc_within_range);
// Now is before end, next change is after end
assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
"2024-02-01 15:00:00", pcmk_rc_within_range);
// Now is equal to end, next change is after end
assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 20:00:00",
"2024-02-01 20:00:00", pcmk_rc_after_range);
// Now and next change are both after end
assert_date_expression(xml, "2024-03-01 12:00:00", "2024-02-01 20:00:00",
"2024-02-01 20:00:00", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_GT_MISSING_START \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' />"
static void
gt_missing_start(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_MISSING_START);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_GT_INVALID_START \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_START "='not-a-datetime' />"
static void
gt_invalid_start(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_INVALID_START);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_GT_VALID \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_GT "' " \
PCMK_XA_START "='2024-02-01 12:00:00' />"
static void
gt_valid(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_GT_VALID);
// Now and next change are both before start
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is after start
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
"2024-02-01 12:00:01", pcmk_rc_before_range);
// Now is equal to start, next change is after start
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
"2024-02-01 12:00:01", pcmk_rc_before_range);
// Now is one second after start, next change is after start
assert_date_expression(xml, "2024-02-01 12:00:01", "2024-02-01 18:00:00",
"2024-02-01 18:00:00", pcmk_rc_within_range);
// t is after start, next change is after start
assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
"2024-04-04 04:04:04", pcmk_rc_within_range);
free_xml(xml);
}
#define EXPR_RANGE_MISSING \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' />"
static void
range_missing(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_MISSING);
crm_time_t *t = crm_time_new("2024-01-01");
assert_int_equal(pcmk__evaluate_date_expression(xml, t, NULL),
pcmk_rc_undetermined);
crm_time_free(t);
free_xml(xml);
}
#define EXPR_RANGE_INVALID_START_INVALID_END \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='not-a-date' " \
PCMK_XA_END "='not-a-date' />"
static void
range_invalid_start_invalid_end(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_INVALID_END);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_RANGE_INVALID_START_ONLY \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='not-a-date' />"
static void
range_invalid_start_only(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_ONLY);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_RANGE_VALID_START_ONLY \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00' />"
static void
range_valid_start_only(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_ONLY);
// Now and next change are before start
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is after start
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
"2024-02-01 12:00:00", pcmk_rc_before_range);
// Now is equal to start, next change is after start
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
"2024-02-01 18:00:00", pcmk_rc_within_range);
// Now and next change are after start
assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
"2024-04-04 04:04:04", pcmk_rc_within_range);
free_xml(xml);
}
#define EXPR_RANGE_INVALID_END_ONLY \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_END "='not-a-date' />"
static void
range_invalid_end_only(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_END_ONLY);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_RANGE_VALID_END_ONLY \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_END "='2024-02-01 15:00:00' />"
static void
range_valid_end_only(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_END_ONLY);
// Now and next change are before end
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_within_range);
// Now is before end, next change is after end
assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now is equal to end, next change is after end
assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now and next change are after end
assert_date_expression(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04",
"2024-04-04 04:04:04", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_RANGE_VALID_START_INVALID_END \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00' " \
PCMK_XA_END "='not-a-date' />"
static void
range_valid_start_invalid_end(void **state)
{
// Currently treated same as start without end
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_END);
// Now and next change are before start
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is after start
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
"2024-02-01 12:00:00", pcmk_rc_before_range);
// Now is equal to start, next change is after start
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 18:00:00",
"2024-02-01 18:00:00", pcmk_rc_within_range);
// Now and next change are after start
assert_date_expression(xml, "2024-03-01 05:03:11", "2024-04-04 04:04:04",
"2024-04-04 04:04:04", pcmk_rc_within_range);
free_xml(xml);
}
#define EXPR_RANGE_INVALID_START_VALID_END \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='not-a-date' " \
PCMK_XA_END "='2024-02-01 15:00:00' />"
static void
range_invalid_start_valid_end(void **state)
{
// Currently treated same as end without start
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_INVALID_START_VALID_END);
// Now and next change are before end
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_within_range);
// Now is before end, next change is after end
assert_date_expression(xml, "2024-02-01 14:59:59", "2024-02-01 18:00:00",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now is equal to end, next change is after end
assert_date_expression(xml, "2024-02-01 15:00:00", "2024-02-01 18:00:00",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now and next change are after end
assert_date_expression(xml, "2024-02-01 15:00:01", "2024-04-04 04:04:04",
"2024-04-04 04:04:04", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_RANGE_VALID_START_VALID_END \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00' " \
PCMK_XA_END "='2024-02-01 15:00:00' />"
static void
range_valid_start_valid_end(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_END);
// Now and next change are before start
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is between start and end
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
"2024-02-01 12:00:00", pcmk_rc_before_range);
// Now is equal to start, next change is between start and end
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
"2024-02-01 14:30:00", pcmk_rc_within_range);
// Now is between start and end, next change is after end
assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now is equal to end, next change is after end
assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now and next change are after end
assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
"2028-04-04 04:04:04", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_RANGE_VALID_START_INVALID_DURATION \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00'>" \
"<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' " \
PCMK_XA_HOURS "='not-a-number' />" \
"</" PCMK_XE_DATE_EXPRESSION ">"
static void
range_valid_start_invalid_duration(void **state)
{
// Currently treated same as end equals start
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_INVALID_DURATION);
// Now and next change are before start
assert_date_expression(xml, "2024-02-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is after start
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 18:00:00",
"2024-02-01 12:00:00", pcmk_rc_before_range);
// Now is equal to start, next change is after start
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
"2024-02-01 12:00:01", pcmk_rc_within_range);
// Now and next change are after start
assert_date_expression(xml, "2024-02-01 12:00:01", "2024-02-01 14:30:00",
"2024-02-01 14:30:00", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_RANGE_VALID_START_VALID_DURATION \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00'>" \
"<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' " \
PCMK_XA_HOURS "='3' />" \
"</" PCMK_XE_DATE_EXPRESSION ">"
static void
range_valid_start_valid_duration(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_VALID_DURATION);
// Now and next change are before start
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is between start and end
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
"2024-02-01 12:00:00", pcmk_rc_before_range);
// Now is equal to start, next change is between start and end
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
"2024-02-01 14:30:00", pcmk_rc_within_range);
// Now is between start and end, next change is after end
assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now is equal to end, next change is after end
assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now and next change are after end
assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
"2028-04-04 04:04:04", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_RANGE_VALID_START_DURATION_MISSING_ID \
"<" PCMK_XE_DATE_EXPRESSION " " \
PCMK_XA_OPERATION "='" PCMK_VALUE_IN_RANGE "' " \
PCMK_XA_START "='2024-02-01 12:00:00'>" \
"<" PCMK_XE_DURATION " " PCMK_XA_ID "='d' " \
PCMK_XA_HOURS "='3' />" \
"</" PCMK_XE_DATE_EXPRESSION ">"
static void
range_valid_start_duration_missing_id(void **state)
{
// Currently acceptable
xmlNodePtr xml = NULL;
xml = pcmk__xml_parse(EXPR_RANGE_VALID_START_DURATION_MISSING_ID);
// Now and next change are before start
assert_date_expression(xml, "2024-01-01 04:30:05", "2024-01-01 11:00:00",
"2024-01-01 11:00:00", pcmk_rc_before_range);
// Now is before start, next change is between start and end
assert_date_expression(xml, "2024-02-01 11:59:59", "2024-02-01 14:00:00",
"2024-02-01 12:00:00", pcmk_rc_before_range);
// Now is equal to start, next change is between start and end
assert_date_expression(xml, "2024-02-01 12:00:00", "2024-02-01 14:30:00",
"2024-02-01 14:30:00", pcmk_rc_within_range);
// Now is between start and end, next change is after end
assert_date_expression(xml, "2024-02-01 14:03:11", "2024-04-04 04:04:04",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now is equal to end, next change is after end
assert_date_expression(xml, "2024-02-01 15:00:00", "2028-04-04 04:04:04",
"2024-02-01 15:00:01", pcmk_rc_within_range);
// Now and next change are after end
assert_date_expression(xml, "2024-02-01 15:00:01", "2028-04-04 04:04:04",
"2028-04-04 04:04:04", pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_SPEC_MISSING \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "' />"
static void
spec_missing(void **state)
{
xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_undetermined);
free_xml(xml);
}
#define EXPR_SPEC_INVALID \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>" \
"<" PCMK_XE_DATE_SPEC " " PCMK_XA_ID "='s' " \
PCMK_XA_MONTHS "='not-a-number'/>" \
"</" PCMK_XE_DATE_EXPRESSION ">"
static void
spec_invalid(void **state)
{
// Currently treated as date_spec with no ranges (which passes)
xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_INVALID);
assert_date_expression(xml, "2024-01-01", NULL, NULL, pcmk_rc_ok);
free_xml(xml);
}
#define EXPR_SPEC_VALID \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>" \
"<" PCMK_XE_DATE_SPEC " " PCMK_XA_ID "='s' " \
PCMK_XA_MONTHS "='2'/>" \
"</" PCMK_XE_DATE_EXPRESSION ">"
static void
spec_valid(void **state)
{
// date_spec does not currently support next_change
xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_VALID);
// Now is just before spec start
assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL,
pcmk_rc_before_range);
// Now matches spec start
assert_date_expression(xml, "2024-02-01 00:00:00", NULL, NULL, pcmk_rc_ok);
// Now is within spec range
assert_date_expression(xml, "2024-02-22 22:22:22", NULL, NULL, pcmk_rc_ok);
// Now matches spec end
assert_date_expression(xml, "2024-02-29 23:59:59", NULL, NULL, pcmk_rc_ok);
// Now is just past spec end
assert_date_expression(xml, "2024-03-01 00:00:00", NULL, NULL,
pcmk_rc_after_range);
free_xml(xml);
}
#define EXPR_SPEC_MISSING_ID \
"<" PCMK_XE_DATE_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_OPERATION "='" PCMK_VALUE_DATE_SPEC "'>" \
"<" PCMK_XE_DATE_SPEC " " \
PCMK_XA_MONTHS "='2'/>" \
"</" PCMK_XE_DATE_EXPRESSION ">"
static void
spec_missing_id(void **state)
{
// Currently acceptable; date_spec does not currently support next_change
xmlNodePtr xml = pcmk__xml_parse(EXPR_SPEC_MISSING_ID);
// Now is just before spec start
assert_date_expression(xml, "2024-01-01 23:59:59", NULL, NULL,
pcmk_rc_before_range);
// Now matches spec start
assert_date_expression(xml, "2024-02-01 00:00:00", NULL, NULL, pcmk_rc_ok);
// Now is within spec range
assert_date_expression(xml, "2024-02-22 22:22:22", NULL, NULL, pcmk_rc_ok);
// Now matches spec end
assert_date_expression(xml, "2024-02-29 23:59:59", NULL, NULL, pcmk_rc_ok);
// Now is just past spec end
assert_date_expression(xml, "2024-03-01 00:00:00", NULL, NULL,
pcmk_rc_after_range);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(null_next_change_ok),
cmocka_unit_test(id_missing),
cmocka_unit_test(op_invalid),
cmocka_unit_test(lt_missing_end),
cmocka_unit_test(lt_invalid_end),
cmocka_unit_test(lt_valid),
cmocka_unit_test(gt_missing_start),
cmocka_unit_test(gt_invalid_start),
cmocka_unit_test(gt_valid),
cmocka_unit_test(range_missing),
cmocka_unit_test(range_invalid_start_invalid_end),
cmocka_unit_test(range_invalid_start_only),
cmocka_unit_test(range_valid_start_only),
cmocka_unit_test(range_invalid_end_only),
cmocka_unit_test(range_valid_end_only),
cmocka_unit_test(range_valid_start_invalid_end),
cmocka_unit_test(range_invalid_start_valid_end),
cmocka_unit_test(range_valid_start_valid_end),
cmocka_unit_test(range_valid_start_invalid_duration),
cmocka_unit_test(range_valid_start_valid_duration),
cmocka_unit_test(range_valid_start_duration_missing_id),
cmocka_unit_test(spec_missing),
cmocka_unit_test(spec_invalid),
cmocka_unit_test(spec_valid),
cmocka_unit_test(spec_missing_id))
diff --git a/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c b/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c
index 6048adf300..a641ab1487 100644
--- a/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c
+++ b/lib/common/tests/rules/pcmk__evaluate_date_spec_test.c
@@ -1,231 +1,231 @@
/*
* Copyright 2020-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <errno.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
#include "crmcommon_private.h"
static void
run_one_test(const char *t, const char *x, int expected)
{
crm_time_t *tm = crm_time_new(t);
xmlNodePtr xml = pcmk__xml_parse(x);
assert_int_equal(pcmk__evaluate_date_spec(xml, tm), expected);
crm_time_free(tm);
free_xml(xml);
}
static void
null_invalid(void **state)
{
xmlNodePtr xml = pcmk__xml_parse("<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2019'/>");
crm_time_t *tm = crm_time_new(NULL);
assert_int_equal(pcmk__evaluate_date_spec(NULL, NULL), EINVAL);
assert_int_equal(pcmk__evaluate_date_spec(xml, NULL), EINVAL);
assert_int_equal(pcmk__evaluate_date_spec(NULL, tm), EINVAL);
crm_time_free(tm);
free_xml(xml);
}
static void
spec_id_missing(void **state)
{
// Currently acceptable
run_one_test("2020-01-01", "<date_spec years='2020'/>", pcmk_rc_ok);
}
static void
invalid_range(void **state)
{
// Currently acceptable
run_one_test("2020-01-01", "<date_spec years='not-a-year' months='1'/>",
pcmk_rc_ok);
}
static void
time_satisfies_year_spec(void **state)
{
run_one_test("2020-01-01",
"<date_spec " PCMK_XA_ID "='spec' years='2020'/>",
pcmk_rc_ok);
}
static void
time_after_year_spec(void **state)
{
run_one_test("2020-01-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2019'/>",
pcmk_rc_after_range);
}
static void
time_satisfies_year_range(void **state)
{
run_one_test("2020-01-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2010-2030'/>",
pcmk_rc_ok);
}
static void
time_before_year_range(void **state)
{
run_one_test("2000-01-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2010-2030'/>",
pcmk_rc_before_range);
}
static void
time_after_year_range(void **state)
{
run_one_test("2020-01-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2010-2015'/>",
pcmk_rc_after_range);
}
static void
range_without_start_year_passes(void **state)
{
run_one_test("2010-01-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='-2020'/>",
pcmk_rc_ok);
}
static void
range_without_end_year_passes(void **state)
{
run_one_test("2010-01-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2000-'/>",
pcmk_rc_ok);
run_one_test("2000-10-01",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2000-'/>",
pcmk_rc_ok);
}
static void
yeardays_satisfies(void **state)
{
run_one_test("2020-01-30",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARDAYS "='30'/>",
pcmk_rc_ok);
}
static void
time_after_yeardays_spec(void **state)
{
run_one_test("2020-02-15",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARDAYS "='40'/>",
pcmk_rc_after_range);
}
static void
yeardays_feb_29_satisfies(void **state)
{
run_one_test("2016-02-29",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARDAYS "='60'/>",
pcmk_rc_ok);
}
static void
exact_ymd_satisfies(void **state)
{
run_one_test("2001-12-31",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2001' "
PCMK_XA_MONTHS "='12' "
PCMK_XA_MONTHDAYS "='31'/>",
pcmk_rc_ok);
}
static void
range_in_month_satisfies(void **state)
{
run_one_test("2001-06-10",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2001' "
PCMK_XA_MONTHS "='6' "
PCMK_XA_MONTHDAYS "='1-10'/>",
pcmk_rc_ok);
}
static void
exact_ymd_after_range(void **state)
{
run_one_test("2001-12-31",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2001' "
PCMK_XA_MONTHS "='12' "
PCMK_XA_MONTHDAYS "='30'/>",
pcmk_rc_after_range);
}
static void
time_after_monthdays_range(void **state)
{
run_one_test("2001-06-10",
"<" PCMK_XE_DATE_SPEC " "
PCMK_XA_ID "='spec' "
PCMK_XA_YEARS "='2001' "
PCMK_XA_MONTHS "='6' "
PCMK_XA_MONTHDAYS "='11-15'/>",
pcmk_rc_before_range);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(spec_id_missing),
cmocka_unit_test(invalid_range),
cmocka_unit_test(time_satisfies_year_spec),
cmocka_unit_test(time_after_year_spec),
cmocka_unit_test(time_satisfies_year_range),
cmocka_unit_test(time_before_year_range),
cmocka_unit_test(time_after_year_range),
cmocka_unit_test(range_without_start_year_passes),
cmocka_unit_test(range_without_end_year_passes),
cmocka_unit_test(yeardays_satisfies),
cmocka_unit_test(time_after_yeardays_spec),
cmocka_unit_test(yeardays_feb_29_satisfies),
cmocka_unit_test(exact_ymd_satisfies),
cmocka_unit_test(range_in_month_satisfies),
cmocka_unit_test(exact_ymd_after_range),
cmocka_unit_test(time_after_monthdays_range))
diff --git a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c
index d1cb35fa77..59e00c4a23 100644
--- a/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c
+++ b/lib/common/tests/rules/pcmk__evaluate_op_expression_test.c
@@ -1,207 +1,207 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
#include "crmcommon_private.h"
/*
* Shared data
*/
static pcmk_rule_input_t rule_input = {
// These are the only members used to evaluate operation expressions
.op_name = PCMK_ACTION_MONITOR,
.op_interval_ms = 10000,
};
/*!
* \internal
* \brief Run one test, comparing return value
*
* \param[in] xml_string Operation expression XML as string
* \param[in] reference_rc Assert that evaluation result equals this
*/
static void
assert_op_expression(const char *xml_string, int reference_rc)
{
xmlNode *xml = pcmk__xml_parse(xml_string);
assert_int_equal(pcmk__evaluate_op_expression(xml, &rule_input),
reference_rc);
free_xml(xml);
}
/*
* Invalid arguments
*/
#define EXPR_FAIL_BOTH \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_START "' " \
PCMK_XA_INTERVAL "='0' />"
static void
null_invalid(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk__evaluate_op_expression(NULL, NULL), EINVAL);
xml = pcmk__xml_parse(EXPR_FAIL_BOTH);
assert_int_equal(pcmk__evaluate_op_expression(xml, NULL), EINVAL);
free_xml(xml);
assert_op_expression(NULL, EINVAL);
}
/*
* Test PCMK_XA_ID
*/
#define EXPR_ID_MISSING \
"<" PCMK_XE_OP_EXPRESSION " " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />"
#define EXPR_ID_EMPTY \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />"
static void
id_missing(void **state)
{
// Currently acceptable
assert_op_expression(EXPR_ID_MISSING, pcmk_rc_ok);
assert_op_expression(EXPR_ID_EMPTY, pcmk_rc_ok);
}
/*
* Test PCMK_XA_NAME
*/
#define EXPR_NAME_MISSING \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_INTERVAL "='10s' />"
static void
name_missing(void **state)
{
assert_op_expression(EXPR_NAME_MISSING, pcmk_rc_unpack_error);
}
#define EXPR_MATCH_BOTH \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />"
#define EXPR_EMPTY_NAME \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='' " PCMK_XA_INTERVAL "='10s' />"
static void
input_name_missing(void **state)
{
rule_input.op_name = NULL;
assert_op_expression(EXPR_MATCH_BOTH, pcmk_rc_op_unsatisfied);
assert_op_expression(EXPR_EMPTY_NAME, pcmk_rc_op_unsatisfied);
rule_input.op_name = PCMK_ACTION_MONITOR;
}
#define EXPR_FAIL_NAME \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_START "' " \
PCMK_XA_INTERVAL "='10s' />"
static void
fail_name(void **state)
{
assert_op_expression(EXPR_FAIL_NAME, pcmk_rc_op_unsatisfied);
// An empty name is meaningless but accepted, so not an unpack error
assert_op_expression(EXPR_EMPTY_NAME, pcmk_rc_op_unsatisfied);
}
/*
* Test PCMK_XA_INTERVAL
*/
#define EXPR_EMPTY_INTERVAL \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='' />"
#define EXPR_INVALID_INTERVAL \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='not-an-interval' />"
static void
invalid_interval(void **state)
{
assert_op_expression(EXPR_EMPTY_INTERVAL, pcmk_rc_unpack_error);
assert_op_expression(EXPR_INVALID_INTERVAL, pcmk_rc_unpack_error);
}
#define EXPR_DEFAULT_INTERVAL \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' />"
static void
default_interval(void **state)
{
assert_op_expression(EXPR_DEFAULT_INTERVAL, pcmk_rc_ok);
}
#define EXPR_FAIL_INTERVAL \
"<" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='9s' />"
static void
fail_interval(void **state)
{
assert_op_expression(EXPR_FAIL_INTERVAL, pcmk_rc_op_unsatisfied);
}
static void
match_both(void **state)
{
assert_op_expression(EXPR_MATCH_BOTH, pcmk_rc_ok);
}
static void
fail_both(void **state)
{
assert_op_expression(EXPR_FAIL_BOTH, pcmk_rc_op_unsatisfied);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(id_missing),
cmocka_unit_test(name_missing),
cmocka_unit_test(input_name_missing),
cmocka_unit_test(fail_name),
cmocka_unit_test(invalid_interval),
cmocka_unit_test(default_interval),
cmocka_unit_test(fail_interval),
cmocka_unit_test(match_both),
cmocka_unit_test(fail_both))
diff --git a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c
index c3a164e778..d146e9bd8c 100644
--- a/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c
+++ b/lib/common/tests/rules/pcmk__evaluate_rsc_expression_test.c
@@ -1,227 +1,227 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
#include "crmcommon_private.h"
/*
* Shared data
*/
static pcmk_rule_input_t rule_input = {
// These are the only members used to evaluate resource expressions
.rsc_standard = PCMK_RESOURCE_CLASS_OCF,
.rsc_provider = "heartbeat",
.rsc_agent = "IPaddr2",
};
/*!
* \internal
* \brief Run one test, comparing return value
*
* \param[in] xml_string Resource expression XML as string
* \param[in] reference_rc Assert that evaluation result equals this
*/
static void
assert_rsc_expression(const char *xml_string, int reference_rc)
{
xmlNode *xml = pcmk__xml_parse(xml_string);
assert_int_equal(pcmk__evaluate_rsc_expression(xml, &rule_input),
reference_rc);
free_xml(xml);
}
/*
* Invalid arguments
*/
#define EXPR_ALL_MATCH \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='heartbeat' " \
PCMK_XA_TYPE "='IPaddr2' />"
static void
null_invalid(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk__evaluate_rsc_expression(NULL, NULL), EINVAL);
xml = pcmk__xml_parse(EXPR_ALL_MATCH);
assert_int_equal(pcmk__evaluate_rsc_expression(xml, NULL), EINVAL);
free_xml(xml);
assert_rsc_expression(NULL, EINVAL);
}
/*
* Test PCMK_XA_ID
*/
#define EXPR_ID_MISSING \
"<" PCMK_XE_RSC_EXPRESSION " " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='heartbeat' " \
PCMK_XA_TYPE "='IPaddr2' />"
#define EXPR_ID_EMPTY \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='heartbeat' " \
PCMK_XA_TYPE "='IPaddr2' />"
static void
id_missing(void **state)
{
// Currently acceptable
assert_rsc_expression(EXPR_ID_MISSING, pcmk_rc_ok);
assert_rsc_expression(EXPR_ID_EMPTY, pcmk_rc_ok);
}
/*
* Test standard, provider, and agent
*/
#define EXPR_FAIL_STANDARD \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_LSB "' />"
#define EXPR_EMPTY_STANDARD \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='' />"
static void
fail_standard(void **state)
{
assert_rsc_expression(EXPR_FAIL_STANDARD, pcmk_rc_op_unsatisfied);
assert_rsc_expression(EXPR_EMPTY_STANDARD, pcmk_rc_op_unsatisfied);
rule_input.rsc_standard = NULL;
assert_rsc_expression(EXPR_FAIL_STANDARD, pcmk_rc_op_unsatisfied);
assert_rsc_expression(EXPR_EMPTY_STANDARD, pcmk_rc_op_unsatisfied);
rule_input.rsc_standard = PCMK_RESOURCE_CLASS_OCF;
}
#define EXPR_FAIL_PROVIDER \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='pacemaker' " \
PCMK_XA_TYPE "='IPaddr2' />"
#define EXPR_EMPTY_PROVIDER \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='' " PCMK_XA_TYPE "='IPaddr2' />"
static void
fail_provider(void **state)
{
assert_rsc_expression(EXPR_FAIL_PROVIDER, pcmk_rc_op_unsatisfied);
assert_rsc_expression(EXPR_EMPTY_PROVIDER, pcmk_rc_op_unsatisfied);
rule_input.rsc_provider = NULL;
assert_rsc_expression(EXPR_FAIL_PROVIDER, pcmk_rc_op_unsatisfied);
assert_rsc_expression(EXPR_EMPTY_PROVIDER, pcmk_rc_op_unsatisfied);
rule_input.rsc_provider = "heartbeat";
}
#define EXPR_FAIL_AGENT \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='heartbeat' " \
PCMK_XA_TYPE "='IPaddr3' />"
#define EXPR_EMPTY_AGENT \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='heartbeat' " PCMK_XA_TYPE "='' />"
static void
fail_agent(void **state)
{
assert_rsc_expression(EXPR_FAIL_AGENT, pcmk_rc_op_unsatisfied);
assert_rsc_expression(EXPR_EMPTY_AGENT, pcmk_rc_op_unsatisfied);
rule_input.rsc_agent = NULL;
assert_rsc_expression(EXPR_FAIL_AGENT, pcmk_rc_op_unsatisfied);
assert_rsc_expression(EXPR_EMPTY_AGENT, pcmk_rc_op_unsatisfied);
rule_input.rsc_agent = "IPaddr2";
}
#define EXPR_NO_STANDARD_MATCHES \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_PROVIDER "='heartbeat' " \
PCMK_XA_TYPE "='IPaddr2' />"
static void
no_standard_matches(void **state)
{
assert_rsc_expression(EXPR_NO_STANDARD_MATCHES, pcmk_rc_ok);
}
#define EXPR_NO_PROVIDER_MATCHES \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_TYPE "='IPaddr2' />"
static void
no_provider_matches(void **state)
{
assert_rsc_expression(EXPR_NO_PROVIDER_MATCHES, pcmk_rc_ok);
}
#define EXPR_NO_AGENT_MATCHES \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_CLASS "='" PCMK_RESOURCE_CLASS_OCF "' " \
PCMK_XA_PROVIDER "='heartbeat' />"
static void
no_agent_matches(void **state)
{
assert_rsc_expression(EXPR_NO_AGENT_MATCHES, pcmk_rc_ok);
}
#define EXPR_NO_CRITERIA_MATCHES \
"<" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e' />"
static void
no_criteria_matches(void **state)
{
assert_rsc_expression(EXPR_NO_CRITERIA_MATCHES, pcmk_rc_ok);
}
static void
all_match(void **state)
{
assert_rsc_expression(EXPR_ALL_MATCH, pcmk_rc_ok);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(id_missing),
cmocka_unit_test(fail_standard),
cmocka_unit_test(fail_provider),
cmocka_unit_test(fail_agent),
cmocka_unit_test(no_standard_matches),
cmocka_unit_test(no_provider_matches),
cmocka_unit_test(no_agent_matches),
cmocka_unit_test(no_criteria_matches),
cmocka_unit_test(all_match))
diff --git a/lib/common/tests/rules/pcmk__unpack_duration_test.c b/lib/common/tests/rules/pcmk__unpack_duration_test.c
index e82546ce2d..ee9867c932 100644
--- a/lib/common/tests/rules/pcmk__unpack_duration_test.c
+++ b/lib/common/tests/rules/pcmk__unpack_duration_test.c
@@ -1,120 +1,120 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <glib.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/iso8601.h>
#include <crm/common/xml.h>
#include "../../crmcommon_private.h"
#define MONTHS_TO_SECONDS "months=\"2\" weeks=\"3\" days=\"-1\" " \
"hours=\"1\" minutes=\"1\" seconds=\"1\" />"
#define ALL_VALID "<duration id=\"duration1\" years=\"1\" " MONTHS_TO_SECONDS
#define NO_ID "<duration years=\"1\" " MONTHS_TO_SECONDS
#define YEARS_INVALID "<duration id=\"duration1\" years=\"not-a-number\" " \
MONTHS_TO_SECONDS
static void
null_invalid(void **state)
{
xmlNode *duration = pcmk__xml_parse(ALL_VALID);
crm_time_t *start = crm_time_new("2024-01-01 15:00:00");
crm_time_t *end = NULL;
assert_int_equal(pcmk__unpack_duration(NULL, NULL, NULL), EINVAL);
assert_int_equal(pcmk__unpack_duration(duration, NULL, NULL), EINVAL);
assert_int_equal(pcmk__unpack_duration(duration, start, NULL), EINVAL);
assert_int_equal(pcmk__unpack_duration(duration, NULL, &end), EINVAL);
assert_int_equal(pcmk__unpack_duration(NULL, start, NULL), EINVAL);
assert_int_equal(pcmk__unpack_duration(NULL, start, &end), EINVAL);
assert_int_equal(pcmk__unpack_duration(NULL, NULL, &end), EINVAL);
crm_time_free(start);
free_xml(duration);
}
static void
nonnull_end_invalid(void **state)
{
xmlNode *duration = pcmk__xml_parse(ALL_VALID);
crm_time_t *start = crm_time_new("2024-01-01 15:00:00");
crm_time_t *end = crm_time_new("2024-01-01 15:00:01");
assert_int_equal(pcmk__unpack_duration(duration, start, &end), EINVAL);
crm_time_free(start);
crm_time_free(end);
free_xml(duration);
}
static void
no_id(void **state)
{
xmlNode *duration = pcmk__xml_parse(NO_ID);
crm_time_t *start = crm_time_new("2024-01-01 15:00:00");
crm_time_t *end = NULL;
crm_time_t *reference = crm_time_new("2025-03-21 16:01:01");
assert_int_equal(pcmk__unpack_duration(duration, start, &end), pcmk_rc_ok);
assert_int_equal(crm_time_compare(end, reference), 0);
crm_time_free(start);
crm_time_free(end);
crm_time_free(reference);
free_xml(duration);
}
static void
years_invalid(void **state)
{
xmlNode *duration = pcmk__xml_parse(YEARS_INVALID);
crm_time_t *start = crm_time_new("2024-01-01 15:00:00");
crm_time_t *end = NULL;
crm_time_t *reference = crm_time_new("2024-03-21 16:01:01");
assert_int_equal(pcmk__unpack_duration(duration, start, &end),
pcmk_rc_unpack_error);
assert_int_equal(crm_time_compare(end, reference), 0);
crm_time_free(start);
crm_time_free(end);
crm_time_free(reference);
free_xml(duration);
}
static void
all_valid(void **state)
{
xmlNode *duration = pcmk__xml_parse(ALL_VALID);
crm_time_t *start = crm_time_new("2024-01-01 15:00:00");
crm_time_t *end = NULL;
crm_time_t *reference = crm_time_new("2025-03-21 16:01:01");
assert_int_equal(pcmk__unpack_duration(duration, start, &end), pcmk_rc_ok);
assert_int_equal(crm_time_compare(end, reference), 0);
crm_time_free(start);
crm_time_free(end);
crm_time_free(reference);
free_xml(duration);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(nonnull_end_invalid),
cmocka_unit_test(no_id),
cmocka_unit_test(years_invalid),
cmocka_unit_test(all_valid))
diff --git a/lib/common/tests/rules/pcmk_evaluate_rule_test.c b/lib/common/tests/rules/pcmk_evaluate_rule_test.c
index 6b6f9eb077..9ee1682e4c 100644
--- a/lib/common/tests/rules/pcmk_evaluate_rule_test.c
+++ b/lib/common/tests/rules/pcmk_evaluate_rule_test.c
@@ -1,379 +1,379 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <stdio.h>
#include <glib.h>
#include <crm/common/xml.h>
#include <crm/common/rules_internal.h>
#include <crm/common/unittest_internal.h>
/*
* Shared data
*/
static pcmk_rule_input_t rule_input = {
.rsc_standard = PCMK_RESOURCE_CLASS_OCF,
.rsc_provider = "heartbeat",
.rsc_agent = "IPaddr2",
.op_name = PCMK_ACTION_MONITOR,
.op_interval_ms = 10000,
};
/*
* Test invalid arguments
*/
#define RULE_OP \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' > " \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
null_invalid(void **state)
{
xmlNode *xml = NULL;
crm_time_t *next_change = crm_time_new_undefined();
assert_int_equal(pcmk_evaluate_rule(NULL, NULL, next_change),
EINVAL);
xml = pcmk__xml_parse(RULE_OP);
assert_int_equal(pcmk_evaluate_rule(xml, NULL, next_change), EINVAL);
free_xml(xml);
assert_int_equal(pcmk_evaluate_rule(NULL, &rule_input, next_change),
EINVAL);
crm_time_free(next_change);
}
#define RULE_OP_MISSING_ID \
"<" PCMK_XE_RULE "> " \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
id_missing(void **state)
{
// Currently acceptable
xmlNode *xml = pcmk__xml_parse(RULE_OP_MISSING_ID);
crm_time_t *next_change = crm_time_new_undefined();
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, next_change),
pcmk_rc_ok);
crm_time_free(next_change);
free_xml(xml);
}
#define RULE_IDREF_PARENT "<" PCMK_XE_CIB ">" RULE_OP "</" PCMK_XE_CIB ">"
static void
good_idref(void **state)
{
xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
crm_time_t *next_change = crm_time_new_undefined();
crm_xml_add(rule_xml, PCMK_XA_ID_REF, "r");
assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
pcmk_rc_ok);
crm_time_free(next_change);
free_xml(parent_xml);
}
static void
bad_idref(void **state)
{
xmlNode *parent_xml = pcmk__xml_parse(RULE_IDREF_PARENT);
xmlNode *rule_xml = pcmk__xe_create(parent_xml, PCMK_XE_RULE);
crm_time_t *next_change = crm_time_new_undefined();
crm_xml_add(rule_xml, PCMK_XA_ID_REF, "x");
assert_int_equal(pcmk_evaluate_rule(rule_xml, &rule_input, next_change),
pcmk_rc_unpack_error);
crm_time_free(next_change);
free_xml(parent_xml);
}
#define RULE_EMPTY "<" PCMK_XE_RULE " " PCMK_XA_ID "='r' />"
static void
empty_default(void **state)
{
// Currently acceptable
xmlNode *xml = pcmk__xml_parse(RULE_EMPTY);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_ok);
free_xml(xml);
}
#define RULE_EMPTY_AND \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' />"
static void
empty_and(void **state)
{
// Currently acceptable
xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_AND);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_ok);
free_xml(xml);
}
#define RULE_EMPTY_OR \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' />"
static void
empty_or(void **state)
{
// Currently treated as unsatisfied
xmlNode *xml = pcmk__xml_parse(RULE_EMPTY_OR);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_op_unsatisfied);
free_xml(xml);
}
#define RULE_DEFAULT_BOOLEAN_OP \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='Dummy' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
default_boolean_op(void **state)
{
// Defaults to PCMK_VALUE_AND
xmlNode *xml = pcmk__xml_parse(RULE_DEFAULT_BOOLEAN_OP);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_op_unsatisfied);
free_xml(xml);
}
#define RULE_INVALID_BOOLEAN_OP \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='not-an-op' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='Dummy' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
invalid_boolean_op(void **state)
{
// Currently defaults to PCMK_VALUE_AND
xmlNode *xml = pcmk__xml_parse(RULE_INVALID_BOOLEAN_OP);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_op_unsatisfied);
free_xml(xml);
}
#define RULE_AND_PASSES \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='IPaddr2' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
and_passes(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_AND_PASSES);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
free_xml(xml);
}
#define RULE_LONELY_AND \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='IPaddr2' />" \
"</" PCMK_XE_RULE ">"
static void
lonely_and_passes(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_LONELY_AND);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
free_xml(xml);
}
#define RULE_AND_ONE_FAILS \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='Dummy' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
and_one_fails(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_AND_ONE_FAILS);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_op_unsatisfied);
free_xml(xml);
}
#define RULE_AND_TWO_FAIL \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_AND "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='Dummy' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='9s' />" \
"</" PCMK_XE_RULE ">"
static void
and_two_fail(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_AND_TWO_FAIL);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_op_unsatisfied);
free_xml(xml);
}
#define RULE_OR_ONE_PASSES \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='Dummy' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
or_one_passes(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_OR_ONE_PASSES);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
free_xml(xml);
}
#define RULE_OR_TWO_PASS \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='IPAddr2' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
or_two_pass(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_OR_TWO_PASS);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
free_xml(xml);
}
#define RULE_LONELY_OR \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='10s' />" \
"</" PCMK_XE_RULE ">"
static void
lonely_or_passes(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_LONELY_OR);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL), pcmk_rc_ok);
free_xml(xml);
}
#define RULE_OR_FAILS \
"<" PCMK_XE_RULE " " PCMK_XA_ID "='r' " \
PCMK_XA_BOOLEAN_OP "='" PCMK_VALUE_OR "' >" \
" <" PCMK_XE_RSC_EXPRESSION " " PCMK_XA_ID "='e1' " \
PCMK_XA_TYPE "='Dummy' />" \
" <" PCMK_XE_OP_EXPRESSION " " PCMK_XA_ID "='e2' " \
PCMK_XA_NAME "='" PCMK_ACTION_MONITOR "' " \
PCMK_XA_INTERVAL "='20s' />" \
"</" PCMK_XE_RULE ">"
static void
or_fails(void **state)
{
xmlNode *xml = pcmk__xml_parse(RULE_OR_FAILS);
assert_int_equal(pcmk_evaluate_rule(xml, &rule_input, NULL),
pcmk_rc_op_unsatisfied);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_invalid),
cmocka_unit_test(id_missing),
cmocka_unit_test(good_idref),
cmocka_unit_test(bad_idref),
cmocka_unit_test(empty_default),
cmocka_unit_test(empty_and),
cmocka_unit_test(empty_or),
cmocka_unit_test(default_boolean_op),
cmocka_unit_test(invalid_boolean_op),
cmocka_unit_test(and_passes),
cmocka_unit_test(lonely_and_passes),
cmocka_unit_test(and_one_fails),
cmocka_unit_test(and_two_fail),
cmocka_unit_test(or_one_passes),
cmocka_unit_test(or_two_pass),
cmocka_unit_test(lonely_or_passes),
cmocka_unit_test(or_fails))
diff --git a/lib/common/tests/schemas/pcmk__build_schema_xml_node_test.c b/lib/common/tests/schemas/pcmk__build_schema_xml_node_test.c
index e4454e2538..1f05962457 100644
--- a/lib/common/tests/schemas/pcmk__build_schema_xml_node_test.c
+++ b/lib/common/tests/schemas/pcmk__build_schema_xml_node_test.c
@@ -1,158 +1,159 @@
/*
* Copyright 2023-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/xml.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/lists_internal.h>
#include <glib.h>
const char *rngs1[] = { "pacemaker-3.0.rng", "status-1.0.rng", "alerts-2.10.rng",
"nvset-2.9.rng", "score.rng", "rule-2.9.rng",
"tags-1.3.rng", "acls-2.0.rng", "fencing-2.4.rng",
"constraints-3.0.rng", "resources-3.0.rng", "nvset-3.0.rng",
"nodes-3.0.rng", "options-3.0.rng", NULL };
const char *rngs2[] = { "pacemaker-2.0.rng", "status-1.0.rng", "tags-1.3.rng",
"acls-2.0.rng", "fencing-1.2.rng", "constraints-1.2.rng",
"rule.rng", "score.rng", "resources-1.3.rng",
"nvset-1.3.rng", "nodes-1.3.rng", "options-1.0.rng",
"nvset.rng", "cib-1.2.rng", NULL };
const char *rngs3[] = { "pacemaker-2.1.rng", "constraints-2.1.rng", NULL };
static int
setup(void **state)
{
setenv("PCMK_schema_directory", PCMK__TEST_SCHEMA_DIR, 1);
crm_schema_init();
pcmk__xml_test_setup_group(state);
return 0;
}
static int
teardown(void **state)
{
+ pcmk__xml_test_teardown_group(state);
crm_schema_cleanup();
unsetenv("PCMK_schema_directory");
return 0;
}
static void
invalid_name(void **state)
{
GList *already_included = NULL;
xmlNode *parent = pcmk__xe_create(NULL, PCMK__XA_SCHEMAS);
pcmk__build_schema_xml_node(parent, "pacemaker-9.0", &already_included);
assert_null(parent->children);
assert_null(already_included);
free_xml(parent);
}
static void
single_schema(void **state)
{
GList *already_included = NULL;
xmlNode *parent = pcmk__xe_create(NULL, PCMK__XA_SCHEMAS);
xmlNode *schema_node = NULL;
xmlNode *file_node = NULL;
int i = 0;
pcmk__build_schema_xml_node(parent, "pacemaker-3.0", &already_included);
assert_non_null(already_included);
assert_non_null(parent->children);
/* Test that the result looks like this:
*
* <schemas>
* <schema version="pacemaker-3.0">
* <file path="pacemaker-3.0.rng">CDATA</file>
* <file path="status-1.0.rng">CDATA</file>
* ...
* </schema>
* </schemas>
*/
schema_node = pcmk__xe_first_child(parent, NULL, NULL, NULL);
assert_string_equal("pacemaker-3.0",
crm_element_value(schema_node, PCMK_XA_VERSION));
file_node = pcmk__xe_first_child(schema_node, NULL, NULL, NULL);
while (file_node != NULL && rngs1[i] != NULL) {
assert_string_equal(rngs1[i],
crm_element_value(file_node, PCMK_XA_PATH));
assert_int_equal(pcmk__xml_first_child(file_node)->type, XML_CDATA_SECTION_NODE);
file_node = pcmk__xe_next(file_node);
i++;
}
g_list_free_full(already_included, free);
free_xml(parent);
}
static void
multiple_schemas(void **state)
{
GList *already_included = NULL;
xmlNode *parent = pcmk__xe_create(NULL, PCMK__XA_SCHEMAS);
xmlNode *schema_node = NULL;
xmlNode *file_node = NULL;
int i = 0;
pcmk__build_schema_xml_node(parent, "pacemaker-2.0", &already_included);
pcmk__build_schema_xml_node(parent, "pacemaker-2.1", &already_included);
assert_non_null(already_included);
assert_non_null(parent->children);
/* Like single_schema, but make sure files aren't included multiple times
* when the function is called repeatedly.
*/
schema_node = pcmk__xe_first_child(parent, NULL, NULL, NULL);
assert_string_equal("pacemaker-2.0",
crm_element_value(schema_node, PCMK_XA_VERSION));
file_node = pcmk__xe_first_child(schema_node, NULL, NULL, NULL);
while (file_node != NULL && rngs2[i] != NULL) {
assert_string_equal(rngs2[i],
crm_element_value(file_node, PCMK_XA_PATH));
assert_int_equal(pcmk__xml_first_child(file_node)->type, XML_CDATA_SECTION_NODE);
file_node = pcmk__xe_next(file_node);
i++;
}
schema_node = pcmk__xe_next(schema_node);
assert_string_equal("pacemaker-2.1",
crm_element_value(schema_node, PCMK_XA_VERSION));
file_node = pcmk__xe_first_child(schema_node, NULL, NULL, NULL);
i = 0;
while (file_node != NULL && rngs3[i] != NULL) {
assert_string_equal(rngs3[i],
crm_element_value(file_node, PCMK_XA_PATH));
assert_int_equal(pcmk__xml_first_child(file_node)->type, XML_CDATA_SECTION_NODE);
file_node = pcmk__xe_next(file_node);
i++;
}
g_list_free_full(already_included, free);
free_xml(parent);
}
PCMK__UNIT_TEST(setup, teardown,
cmocka_unit_test(invalid_name),
cmocka_unit_test(single_schema),
cmocka_unit_test(multiple_schemas))
diff --git a/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c b/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c
index 146317cfb2..5bf3e76b3b 100644
--- a/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c
+++ b/lib/common/tests/xml/pcmk__xe_copy_attrs_test.c
@@ -1,188 +1,188 @@
/*
* Copyright 2022-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <glib.h>
static void
null_args(void **state)
{
// This test dumps core via CRM_CHECK()
xmlNode *xml = pcmk__xe_create(NULL, "test");
assert_int_equal(pcmk__xe_copy_attrs(NULL, NULL, pcmk__xaf_none), EINVAL);
assert_int_equal(pcmk__xe_copy_attrs(NULL, xml, pcmk__xaf_none), EINVAL);
assert_int_equal(pcmk__xe_copy_attrs(xml, NULL, pcmk__xaf_none), EINVAL);
assert_ptr_equal(xml->properties, NULL);
free_xml(xml);
}
static void
no_source_attrs(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
// Ensure copying from empty source doesn't create target properties
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none),
pcmk_rc_ok);
assert_ptr_equal(target->properties, NULL);
// Ensure copying from empty source doesn't delete target attributes
crm_xml_add(target, "attr", "value");
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none),
pcmk_rc_ok);
assert_string_equal(crm_element_value(target, "attr"), "value");
free_xml(src);
free_xml(target);
}
static void
copy_one(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
crm_xml_add(src, "attr", "value");
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none),
pcmk_rc_ok);
assert_string_equal(crm_element_value(src, "attr"),
crm_element_value(target, "attr"));
free_xml(src);
free_xml(target);
}
static void
copy_multiple(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
pcmk__xe_set_props(src,
"attr1", "value1",
"attr2", "value2",
"attr3", "value3",
NULL);
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none),
pcmk_rc_ok);
assert_string_equal(crm_element_value(src, "attr1"),
crm_element_value(target, "attr1"));
assert_string_equal(crm_element_value(src, "attr2"),
crm_element_value(target, "attr2"));
assert_string_equal(crm_element_value(src, "attr3"),
crm_element_value(target, "attr3"));
free_xml(src);
free_xml(target);
}
static void
overwrite(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
crm_xml_add(src, "attr", "src_value");
crm_xml_add(target, "attr", "target_value");
// Overwrite enabled by default
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none),
pcmk_rc_ok);
assert_string_equal(crm_element_value(src, "attr"),
crm_element_value(target, "attr"));
free_xml(src);
free_xml(target);
}
static void
no_overwrite(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
crm_xml_add(src, "attr", "src_value");
crm_xml_add(target, "attr", "target_value");
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_no_overwrite),
pcmk_rc_ok);
assert_string_not_equal(crm_element_value(src, "attr"),
crm_element_value(target, "attr"));
// no_overwrite doesn't prevent copy if there's no conflict
pcmk__xe_remove_attr(target, "attr");
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_no_overwrite),
pcmk_rc_ok);
assert_string_equal(crm_element_value(src, "attr"),
crm_element_value(target, "attr"));
free_xml(src);
free_xml(target);
}
static void
score_update(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
crm_xml_add(src, "plus_plus_attr", "plus_plus_attr++");
crm_xml_add(src, "plus_two_attr", "plus_two_attr+=2");
crm_xml_add(target, "plus_plus_attr", "1");
crm_xml_add(target, "plus_two_attr", "1");
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_score_update),
pcmk_rc_ok);
assert_string_equal(crm_element_value(target, "plus_plus_attr"), "2");
assert_string_equal(crm_element_value(target, "plus_two_attr"), "3");
free_xml(src);
free_xml(target);
}
static void
no_score_update(void **state)
{
xmlNode *src = pcmk__xe_create(NULL, "test");
xmlNode *target = pcmk__xe_create(NULL, "test");
crm_xml_add(src, "plus_plus_attr", "plus_plus_attr++");
crm_xml_add(src, "plus_two_attr", "plus_two_attr+=2");
crm_xml_add(target, "plus_plus_attr", "1");
crm_xml_add(target, "plus_two_attr", "1");
// Score update disabled by default
assert_int_equal(pcmk__xe_copy_attrs(target, src, pcmk__xaf_none),
pcmk_rc_ok);
assert_string_equal(crm_element_value(target, "plus_plus_attr"),
"plus_plus_attr++");
assert_string_equal(crm_element_value(target, "plus_two_attr"),
"plus_two_attr+=2");
free_xml(src);
free_xml(target);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_args),
cmocka_unit_test(no_source_attrs),
cmocka_unit_test(copy_one),
cmocka_unit_test(copy_multiple),
cmocka_unit_test(overwrite),
cmocka_unit_test(no_overwrite),
cmocka_unit_test(score_update),
cmocka_unit_test(no_score_update));
diff --git a/lib/common/tests/xml/pcmk__xe_first_child_test.c b/lib/common/tests/xml/pcmk__xe_first_child_test.c
index 64b90b04dc..7881e643ad 100644
--- a/lib/common/tests/xml/pcmk__xe_first_child_test.c
+++ b/lib/common/tests/xml/pcmk__xe_first_child_test.c
@@ -1,106 +1,106 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/xml.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
const char *str1 =
"<xml>\n"
" <!-- This is an A node -->\n"
" <nodeA attrA=\"123\" " PCMK_XA_ID "=\"1\">\n"
" content\n"
" </nodeA>\n"
" <!-- This is an A node -->\n"
" <nodeA attrA=\"456\" " PCMK_XA_ID "=\"2\">\n"
" content\n"
" </nodeA>\n"
" <!-- This is an A node -->\n"
" <nodeA attrB=\"XYZ\" " PCMK_XA_ID "=\"3\">\n"
" content\n"
" </nodeA>\n"
" <!-- This is a B node -->\n"
" <nodeB attrA=\"123\" " PCMK_XA_ID "=\"4\">\n"
" content\n"
" </nodeA>\n"
" <!-- This is a B node -->\n"
" <nodeB attrB=\"ABC\" " PCMK_XA_ID "=\"5\">\n"
" content\n"
" </nodeA>\n"
"</xml>";
static void
bad_input(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
assert_null(pcmk__xe_first_child(NULL, NULL, NULL, NULL));
assert_null(pcmk__xe_first_child(NULL, NULL, NULL, "attrX"));
free_xml(xml);
}
static void
not_found(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
/* No node with an attrX attribute */
assert_null(pcmk__xe_first_child(xml, NULL, "attrX", NULL));
/* No nodeX node */
assert_null(pcmk__xe_first_child(xml, "nodeX", NULL, NULL));
/* No nodeA node with attrX */
assert_null(pcmk__xe_first_child(xml, "nodeA", "attrX", NULL));
/* No nodeA node with attrA=XYZ */
assert_null(pcmk__xe_first_child(xml, "nodeA", "attrA", "XYZ"));
free_xml(xml);
}
static void
find_attrB(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
xmlNode *result = NULL;
/* Find the first node with attrB */
result = pcmk__xe_first_child(xml, NULL, "attrB", NULL);
assert_non_null(result);
assert_string_equal(crm_element_value(result, PCMK_XA_ID), "3");
/* Find the first nodeB with attrB */
result = pcmk__xe_first_child(xml, "nodeB", "attrB", NULL);
assert_non_null(result);
assert_string_equal(crm_element_value(result, PCMK_XA_ID), "5");
free_xml(xml);
}
static void
find_attrA_matching(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
xmlNode *result = NULL;
/* Find attrA=456 */
result = pcmk__xe_first_child(xml, NULL, "attrA", "456");
assert_non_null(result);
assert_string_equal(crm_element_value(result, PCMK_XA_ID), "2");
/* Find a nodeB with attrA=123 */
result = pcmk__xe_first_child(xml, "nodeB", "attrA", "123");
assert_non_null(result);
assert_string_equal(crm_element_value(result, PCMK_XA_ID), "4");
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(bad_input),
cmocka_unit_test(not_found),
cmocka_unit_test(find_attrB),
cmocka_unit_test(find_attrA_matching));
diff --git a/lib/common/tests/xml/pcmk__xe_foreach_child_test.c b/lib/common/tests/xml/pcmk__xe_foreach_child_test.c
index a833dde4f6..69591d93dc 100644
--- a/lib/common/tests/xml/pcmk__xe_foreach_child_test.c
+++ b/lib/common/tests/xml/pcmk__xe_foreach_child_test.c
@@ -1,216 +1,216 @@
/*
* Copyright 2022-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
static int compare_name_handler(xmlNode *xml, void *userdata) {
function_called();
assert_string_equal((char *) userdata, (const char *) xml->name);
return pcmk_rc_ok;
}
const char *str1 =
"<xml>\n"
" <!-- This is a level 1 node -->\n"
" <level1>\n"
" content\n"
" </level1>\n"
" <!-- This is a level 1 node -->\n"
" <level1>\n"
" content\n"
" </level1>\n"
" <!-- This is a level 1 node -->\n"
" <level1>\n"
" content\n"
" </level1>\n"
"</xml>";
static void
bad_input(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
pcmk__assert_asserts(pcmk__xe_foreach_child(xml, NULL, NULL, NULL));
free_xml(xml);
}
static void
name_given_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
/* The handler should be called once for every <level1> node. */
expect_function_call(compare_name_handler);
expect_function_call(compare_name_handler);
expect_function_call(compare_name_handler);
pcmk__xe_foreach_child(xml, "level1", compare_name_handler, (void *) "level1");
free_xml(xml);
}
static void
no_name_given_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
/* The handler should be called once for every <level1> node. */
expect_function_call(compare_name_handler);
expect_function_call(compare_name_handler);
expect_function_call(compare_name_handler);
pcmk__xe_foreach_child(xml, NULL, compare_name_handler, (void *) "level1");
free_xml(xml);
}
static void
name_doesnt_exist_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str1);
pcmk__xe_foreach_child(xml, "xxx", compare_name_handler, NULL);
free_xml(xml);
}
const char *str2 =
"<xml>\n"
" <level1>\n"
" <!-- Inside a level 1 node -->\n"
" <level2>\n"
" <!-- Inside a level 2 node -->\n"
" </level2>\n"
" </level1>\n"
" <level1>\n"
" <!-- Inside a level 1 node -->\n"
" <level2>\n"
" <!-- Inside a level 2 node -->\n"
" <level3>\n"
" <!-- Inside a level 3 node -->\n"
" </level3>\n"
" </level2>\n"
" <level2>\n"
" <!-- Inside a level 2 node -->\n"
" </level2>\n"
" </level1>\n"
"</xml>";
static void
multiple_levels_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str2);
/* The handler should be called once for every <level1> node. */
expect_function_call(compare_name_handler);
expect_function_call(compare_name_handler);
pcmk__xe_foreach_child(xml, "level1", compare_name_handler, (void *) "level1");
free_xml(xml);
}
static void
multiple_levels_no_name_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str2);
/* The handler should be called once for every <level1> node. */
expect_function_call(compare_name_handler);
expect_function_call(compare_name_handler);
pcmk__xe_foreach_child(xml, NULL, compare_name_handler, (void *) "level1");
free_xml(xml);
}
const char *str3 =
"<xml>\n"
" <!-- This is node #1 -->\n"
" <node1>\n"
" content\n"
" </node1>\n"
" <!-- This is node #2 -->\n"
" <node2>\n"
" content\n"
" </node2>\n"
" <!-- This is node #3 -->\n"
" <node3>\n"
" content\n"
" </node3>\n"
"</xml>";
static int any_of_handler(xmlNode *xml, void *userdata) {
function_called();
assert_true(pcmk__str_any_of((const char *) xml->name,
"node1", "node2", "node3", NULL));
return pcmk_rc_ok;
}
static void
any_of_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str3);
/* The handler should be called once for every <nodeX> node. */
expect_function_call(any_of_handler);
expect_function_call(any_of_handler);
expect_function_call(any_of_handler);
pcmk__xe_foreach_child(xml, NULL, any_of_handler, NULL);
free_xml(xml);
}
static int stops_on_first_handler(xmlNode *xml, void *userdata) {
function_called();
if (pcmk__xe_is(xml, "node1")) {
return pcmk_rc_error;
} else {
return pcmk_rc_ok;
}
}
static int stops_on_second_handler(xmlNode *xml, void *userdata) {
function_called();
if (pcmk__xe_is(xml, "node2")) {
return pcmk_rc_error;
} else {
return pcmk_rc_ok;
}
}
static int stops_on_third_handler(xmlNode *xml, void *userdata) {
function_called();
if (pcmk__xe_is(xml, "node3")) {
return pcmk_rc_error;
} else {
return pcmk_rc_ok;
}
}
static void
one_of_test(void **state) {
xmlNode *xml = pcmk__xml_parse(str3);
/* The handler should be called once. */
expect_function_call(stops_on_first_handler);
assert_int_equal(pcmk__xe_foreach_child(xml, "node1", stops_on_first_handler, NULL), pcmk_rc_error);
expect_function_call(stops_on_second_handler);
assert_int_equal(pcmk__xe_foreach_child(xml, "node2", stops_on_second_handler, NULL), pcmk_rc_error);
expect_function_call(stops_on_third_handler);
assert_int_equal(pcmk__xe_foreach_child(xml, "node3", stops_on_third_handler, NULL), pcmk_rc_error);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(bad_input),
cmocka_unit_test(name_given_test),
cmocka_unit_test(no_name_given_test),
cmocka_unit_test(name_doesnt_exist_test),
cmocka_unit_test(multiple_levels_test),
cmocka_unit_test(multiple_levels_no_name_test),
cmocka_unit_test(any_of_test),
cmocka_unit_test(one_of_test))
diff --git a/lib/common/tests/xml/pcmk__xe_set_score_test.c b/lib/common/tests/xml/pcmk__xe_set_score_test.c
index deb85b071b..3c352f0dd0 100644
--- a/lib/common/tests/xml/pcmk__xe_set_score_test.c
+++ b/lib/common/tests/xml/pcmk__xe_set_score_test.c
@@ -1,188 +1,188 @@
/*
* Copyright 2022-2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <glib.h>
#include "crmcommon_private.h" // pcmk__xe_set_score()
/*!
* \internal
* \brief Update an XML attribute value and check it against a reference value
*
* The attribute name is hard-coded as \c "X".
*
* \param[in] initial Initial value
* \param[in] new Value to set
* \param[in] reference_val Expected attribute value after update
* \param[in] reference_rc Expected return code from \c pcmk__xe_set_score()
*/
static void
assert_set_score(const char *initial, const char *new,
const char *reference_val, int reference_rc)
{
const char *name = "X";
xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml");
crm_xml_add(test_xml, name, initial);
assert_int_equal(pcmk__xe_set_score(test_xml, name, new), reference_rc);
assert_string_equal(crm_element_value(test_xml, name), reference_val);
free_xml(test_xml);
}
static void
value_is_name_plus_plus(void **state)
{
assert_set_score("5", "X++", "6", pcmk_rc_ok);
}
static void
value_is_name_plus_equals_integer(void **state)
{
assert_set_score("5", "X+=2", "7", pcmk_rc_ok);
}
// NULL input
static void
target_is_NULL(void **state)
{
// Dumps core via CRM_CHECK()
assert_int_equal(pcmk__xe_set_score(NULL, "X", "X++"), EINVAL);
}
static void
name_is_NULL(void **state)
{
xmlNode *test_xml = pcmk__xe_create(NULL, "test_xml");
crm_xml_add(test_xml, "X", "5");
// Dumps core via CRM_CHECK()
assert_int_equal(pcmk__xe_set_score(test_xml, NULL, "X++"), EINVAL);
assert_string_equal(crm_element_value(test_xml, "X"), "5");
free_xml(test_xml);
}
static void
value_is_NULL(void **state)
{
assert_set_score("5", NULL, "5", pcmk_rc_ok);
}
// the value input doesn't start with the name input
static void
value_is_wrong_name(void **state)
{
assert_set_score("5", "Y++", "Y++", pcmk_rc_ok);
}
static void
value_is_only_an_integer(void **state)
{
assert_set_score("5", "2", "2", pcmk_rc_ok);
}
// non-integers
static void
variable_is_initialized_to_be_non_numeric(void **state)
{
assert_set_score("hello", "X++", "1", pcmk_rc_ok);
}
static void
variable_is_initialized_to_be_non_numeric_2(void **state)
{
assert_set_score("hello", "X+=2", "2", pcmk_rc_ok);
}
static void
variable_is_initialized_to_be_numeric_and_decimal_point_containing(void **state)
{
assert_set_score("5.01", "X++", "6", pcmk_rc_ok);
}
static void
variable_is_initialized_to_be_numeric_and_decimal_point_containing_2(void **state)
{
assert_set_score("5.50", "X++", "6", pcmk_rc_ok);
}
static void
variable_is_initialized_to_be_numeric_and_decimal_point_containing_3(void **state)
{
assert_set_score("5.99", "X++", "6", pcmk_rc_ok);
}
static void
value_is_non_numeric(void **state)
{
assert_set_score("5", "X+=hello", "5", pcmk_rc_ok);
}
static void
value_is_numeric_and_decimal_point_containing(void **state)
{
assert_set_score("5", "X+=2.01", "7", pcmk_rc_ok);
}
static void
value_is_numeric_and_decimal_point_containing_2(void **state)
{
assert_set_score("5", "X+=1.50", "6", pcmk_rc_ok);
}
static void
value_is_numeric_and_decimal_point_containing_3(void **state)
{
assert_set_score("5", "X+=1.99", "6", pcmk_rc_ok);
}
// undefined input
static void
name_is_undefined(void **state)
{
assert_set_score(NULL, "X++", "X++", pcmk_rc_ok);
}
// large input
static void
assignment_result_is_too_large(void **state)
{
assert_set_score("5", "X+=100000000000", "1000000", pcmk_rc_ok);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(value_is_name_plus_plus),
cmocka_unit_test(value_is_name_plus_equals_integer),
cmocka_unit_test(target_is_NULL),
cmocka_unit_test(name_is_NULL),
cmocka_unit_test(value_is_NULL),
cmocka_unit_test(value_is_wrong_name),
cmocka_unit_test(value_is_only_an_integer),
cmocka_unit_test(variable_is_initialized_to_be_non_numeric),
cmocka_unit_test(variable_is_initialized_to_be_non_numeric_2),
cmocka_unit_test(variable_is_initialized_to_be_numeric_and_decimal_point_containing),
cmocka_unit_test(variable_is_initialized_to_be_numeric_and_decimal_point_containing_2),
cmocka_unit_test(variable_is_initialized_to_be_numeric_and_decimal_point_containing_3),
cmocka_unit_test(value_is_non_numeric),
cmocka_unit_test(value_is_numeric_and_decimal_point_containing),
cmocka_unit_test(value_is_numeric_and_decimal_point_containing_2),
cmocka_unit_test(value_is_numeric_and_decimal_point_containing_3),
cmocka_unit_test(name_is_undefined),
cmocka_unit_test(assignment_result_is_too_large))
diff --git a/lib/common/tests/xml/pcmk__xml_escape_test.c b/lib/common/tests/xml/pcmk__xml_escape_test.c
index 8c6fd218fe..5894aecdef 100644
--- a/lib/common/tests/xml/pcmk__xml_escape_test.c
+++ b/lib/common/tests/xml/pcmk__xml_escape_test.c
@@ -1,213 +1,213 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
#include "crmcommon_private.h"
static void
assert_escape(const char *str, const char *reference,
enum pcmk__xml_escape_type type)
{
gchar *buf = pcmk__xml_escape(str, type);
assert_string_equal(buf, reference);
g_free(buf);
}
static void
null_empty(void **state)
{
assert_null(pcmk__xml_escape(NULL, pcmk__xml_escape_text));
assert_null(pcmk__xml_escape(NULL, pcmk__xml_escape_attr));
assert_null(pcmk__xml_escape(NULL, pcmk__xml_escape_attr_pretty));
assert_escape("", "", pcmk__xml_escape_text);
assert_escape("", "", pcmk__xml_escape_attr);
assert_escape("", "", pcmk__xml_escape_attr_pretty);
}
static void
invalid_type(void **state)
{
const enum pcmk__xml_escape_type type = (enum pcmk__xml_escape_type) -1;
// Easier to ignore invalid type for NULL or empty string
assert_null(pcmk__xml_escape(NULL, type));
assert_escape("", "", type);
// Otherwise, assert if we somehow passed an invalid type
pcmk__assert_asserts(pcmk__xml_escape("he<>llo", type));
}
static void
escape_unchanged(void **state)
{
// No escaped characters (note: this string includes single quote at end)
const char *unchanged = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"`~!@#$%^*()-_=+/|\\[]{}?.,'";
assert_escape(unchanged, unchanged, pcmk__xml_escape_text);
assert_escape(unchanged, unchanged, pcmk__xml_escape_attr);
assert_escape(unchanged, unchanged, pcmk__xml_escape_attr_pretty);
}
// Ensure special characters get escaped at start, middle, and end
static void
escape_left_angle(void **state)
{
const char *l_angle = "<abc<def<";
const char *l_angle_esc = PCMK__XML_ENTITY_LT "abc"
PCMK__XML_ENTITY_LT "def" PCMK__XML_ENTITY_LT;
assert_escape(l_angle, l_angle_esc, pcmk__xml_escape_text);
assert_escape(l_angle, l_angle_esc, pcmk__xml_escape_attr);
assert_escape(l_angle, l_angle, pcmk__xml_escape_attr_pretty);
}
static void
escape_right_angle(void **state)
{
const char *r_angle = ">abc>def>";
const char *r_angle_esc = PCMK__XML_ENTITY_GT "abc"
PCMK__XML_ENTITY_GT "def" PCMK__XML_ENTITY_GT;
assert_escape(r_angle, r_angle_esc, pcmk__xml_escape_text);
assert_escape(r_angle, r_angle_esc, pcmk__xml_escape_attr);
assert_escape(r_angle, r_angle, pcmk__xml_escape_attr_pretty);
}
static void
escape_ampersand(void **state)
{
const char *ampersand = "&abc&def&";
const char *ampersand_esc = PCMK__XML_ENTITY_AMP "abc"
PCMK__XML_ENTITY_AMP "def" PCMK__XML_ENTITY_AMP;
assert_escape(ampersand, ampersand_esc, pcmk__xml_escape_text);
assert_escape(ampersand, ampersand_esc, pcmk__xml_escape_attr);
assert_escape(ampersand, ampersand, pcmk__xml_escape_attr_pretty);
}
static void
escape_double_quote(void **state)
{
const char *double_quote = "\"abc\"def\"";
const char *double_quote_esc_ref = PCMK__XML_ENTITY_QUOT "abc"
PCMK__XML_ENTITY_QUOT "def"
PCMK__XML_ENTITY_QUOT;
const char *double_quote_esc_backslash = "\\\"abc\\\"def\\\"";
assert_escape(double_quote, double_quote, pcmk__xml_escape_text);
assert_escape(double_quote, double_quote_esc_ref, pcmk__xml_escape_attr);
assert_escape(double_quote, double_quote_esc_backslash,
pcmk__xml_escape_attr_pretty);
}
static void
escape_newline(void **state)
{
const char *newline = "\nabc\ndef\n";
const char *newline_esc_ref = "
abc
def
";
const char *newline_esc_backslash = "\\nabc\\ndef\\n";
assert_escape(newline, newline, pcmk__xml_escape_text);
assert_escape(newline, newline_esc_ref, pcmk__xml_escape_attr);
assert_escape(newline, newline_esc_backslash, pcmk__xml_escape_attr_pretty);
}
static void
escape_tab(void **state)
{
const char *tab = "\tabc\tdef\t";
const char *tab_esc_ref = "	abc	def	";
const char *tab_esc_backslash = "\\tabc\\tdef\\t";
assert_escape(tab, tab, pcmk__xml_escape_text);
assert_escape(tab, tab_esc_ref, pcmk__xml_escape_attr);
assert_escape(tab, tab_esc_backslash, pcmk__xml_escape_attr_pretty);
}
static void
escape_carriage_return(void **state)
{
const char *cr = "\rabc\rdef\r";
const char *cr_esc_ref = "
abc
def
";
const char *cr_esc_backslash = "\\rabc\\rdef\\r";
assert_escape(cr, cr_esc_ref, pcmk__xml_escape_text);
assert_escape(cr, cr_esc_ref, pcmk__xml_escape_attr);
assert_escape(cr, cr_esc_backslash, pcmk__xml_escape_attr_pretty);
}
static void
escape_nonprinting(void **state)
{
const char *nonprinting = "\a\x7F\x1B";
const char *nonprinting_esc = "";
assert_escape(nonprinting, nonprinting_esc, pcmk__xml_escape_text);
assert_escape(nonprinting, nonprinting_esc, pcmk__xml_escape_attr);
assert_escape(nonprinting, nonprinting, pcmk__xml_escape_attr_pretty);
}
static void
escape_utf8(void **state)
{
/* Non-ASCII UTF-8 characters may be two, three, or four 8-bit bytes wide
* and should not be escaped.
*/
const char *chinese = "仅高级使用";
const char *two_byte = "abc""\xCF\xA6""d<ef";
const char *two_byte_esc = "abc""\xCF\xA6""d" PCMK__XML_ENTITY_LT "ef";
const char *three_byte = "abc""\xEF\x98\x98""d<ef";
const char *three_byte_esc = "abc""\xEF\x98\x98""d"
PCMK__XML_ENTITY_LT "ef";
const char *four_byte = "abc""\xF0\x94\x81\x90""d<ef";
const char *four_byte_esc = "abc""\xF0\x94\x81\x90""d"
PCMK__XML_ENTITY_LT "ef";
assert_escape(chinese, chinese, pcmk__xml_escape_text);
assert_escape(chinese, chinese, pcmk__xml_escape_attr);
assert_escape(chinese, chinese, pcmk__xml_escape_attr_pretty);
assert_escape(two_byte, two_byte_esc, pcmk__xml_escape_text);
assert_escape(two_byte, two_byte_esc, pcmk__xml_escape_attr);
assert_escape(two_byte, two_byte, pcmk__xml_escape_attr_pretty);
assert_escape(three_byte, three_byte_esc, pcmk__xml_escape_text);
assert_escape(three_byte, three_byte_esc, pcmk__xml_escape_attr);
assert_escape(three_byte, three_byte, pcmk__xml_escape_attr_pretty);
assert_escape(four_byte, four_byte_esc, pcmk__xml_escape_text);
assert_escape(four_byte, four_byte_esc, pcmk__xml_escape_attr);
assert_escape(four_byte, four_byte, pcmk__xml_escape_attr_pretty);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_empty),
cmocka_unit_test(invalid_type),
cmocka_unit_test(escape_unchanged),
cmocka_unit_test(escape_left_angle),
cmocka_unit_test(escape_right_angle),
cmocka_unit_test(escape_ampersand),
cmocka_unit_test(escape_double_quote),
cmocka_unit_test(escape_newline),
cmocka_unit_test(escape_tab),
cmocka_unit_test(escape_carriage_return),
cmocka_unit_test(escape_nonprinting),
cmocka_unit_test(escape_utf8));
diff --git a/lib/common/tests/xml/pcmk__xml_needs_escape_test.c b/lib/common/tests/xml/pcmk__xml_needs_escape_test.c
index 612f61bef7..a1c1326003 100644
--- a/lib/common/tests/xml/pcmk__xml_needs_escape_test.c
+++ b/lib/common/tests/xml/pcmk__xml_needs_escape_test.c
@@ -1,337 +1,337 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml_internal.h>
#include "crmcommon_private.h"
static void
null_empty(void **state)
{
assert_false(pcmk__xml_needs_escape(NULL, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(NULL, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(NULL, pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape("", pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape("", pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape("", pcmk__xml_escape_attr_pretty));
}
static void
invalid_type(void **state)
{
const enum pcmk__xml_escape_type type = (enum pcmk__xml_escape_type) -1;
// Easier to ignore invalid type for NULL or empty string
assert_false(pcmk__xml_needs_escape(NULL, type));
assert_false(pcmk__xml_needs_escape("", type));
// Otherwise, assert if we somehow passed an invalid type
pcmk__assert_asserts(pcmk__xml_needs_escape("he<>llo", type));
}
static void
escape_unchanged(void **state)
{
// No escaped characters (note: this string includes single quote at end)
const char *unchanged = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"`~!@#$%^*()-_=+/|\\[]{}?.,'";
assert_false(pcmk__xml_needs_escape(unchanged, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(unchanged, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(unchanged,
pcmk__xml_escape_attr_pretty));
}
// Ensure special characters get escaped at start, middle, and end
static void
escape_left_angle(void **state)
{
const char *l_angle_left = "<abcdef";
const char *l_angle_mid = "abc<def";
const char *l_angle_right = "abcdef<";
assert_true(pcmk__xml_needs_escape(l_angle_left, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(l_angle_mid, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(l_angle_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(l_angle_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(l_angle_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(l_angle_right, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(l_angle_left,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(l_angle_mid,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(l_angle_right,
pcmk__xml_escape_attr_pretty));
}
static void
escape_right_angle(void **state)
{
const char *r_angle_left = ">abcdef";
const char *r_angle_mid = "abc>def";
const char *r_angle_right = "abcdef>";
assert_true(pcmk__xml_needs_escape(r_angle_left, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(r_angle_mid, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(r_angle_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(r_angle_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(r_angle_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(r_angle_right, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(r_angle_left,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(r_angle_mid,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(r_angle_right,
pcmk__xml_escape_attr_pretty));
}
static void
escape_ampersand(void **state)
{
const char *ampersand_left = "&abcdef";
const char *ampersand_mid = "abc&def";
const char *ampersand_right = "abcdef&";
assert_true(pcmk__xml_needs_escape(ampersand_left, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(ampersand_mid, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(ampersand_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(ampersand_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(ampersand_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(ampersand_right, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(ampersand_left,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(ampersand_mid,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(ampersand_right,
pcmk__xml_escape_attr_pretty));
}
static void
escape_double_quote(void **state)
{
const char *double_quote_left = "\"abcdef";
const char *double_quote_mid = "abc\"def";
const char *double_quote_right = "abcdef\"";
assert_false(pcmk__xml_needs_escape(double_quote_left,
pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(double_quote_mid,
pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(double_quote_right,
pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(double_quote_left,
pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(double_quote_mid,
pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(double_quote_right,
pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(double_quote_left,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(double_quote_mid,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(double_quote_right,
pcmk__xml_escape_attr_pretty));
}
static void
escape_newline(void **state)
{
const char *newline_left = "\nabcdef";
const char *newline_mid = "abc\ndef";
const char *newline_right = "abcdef\n";
assert_false(pcmk__xml_needs_escape(newline_left, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(newline_mid, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(newline_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(newline_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(newline_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(newline_right, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(newline_left,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(newline_mid,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(newline_right,
pcmk__xml_escape_attr_pretty));
}
static void
escape_tab(void **state)
{
const char *tab_left = "\tabcdef";
const char *tab_mid = "abc\tdef";
const char *tab_right = "abcdef\t";
assert_false(pcmk__xml_needs_escape(tab_left, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(tab_mid, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(tab_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(tab_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(tab_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(tab_right, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(tab_left, pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(tab_mid, pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(tab_right,
pcmk__xml_escape_attr_pretty));
}
static void
escape_carriage_return(void **state)
{
const char *cr_left = "\rabcdef";
const char *cr_mid = "abc\rdef";
const char *cr_right = "abcdef\r";
assert_true(pcmk__xml_needs_escape(cr_left, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(cr_mid, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(cr_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(cr_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(cr_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(cr_right, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(cr_left, pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(cr_mid, pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(cr_right, pcmk__xml_escape_attr_pretty));
}
static void
escape_nonprinting(void **state)
{
const char *alert_left = "\aabcdef";
const char *alert_mid = "abc\adef";
const char *alert_right = "abcdef\a";
const char *delete_left = "\x7F""abcdef";
const char *delete_mid = "abc\x7F""def";
const char *delete_right = "abcdef\x7F";
const char *nonprinting_all = "\a\x7F\x1B";
assert_true(pcmk__xml_needs_escape(alert_left, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(alert_mid, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(alert_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(alert_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(alert_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(alert_right, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(alert_left,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(alert_mid,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(alert_right,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(delete_left, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(delete_mid, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(delete_right, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(delete_left, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(delete_mid, pcmk__xml_escape_attr));
assert_true(pcmk__xml_needs_escape(delete_right, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(delete_left,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(delete_mid,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(delete_right,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(nonprinting_all, pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(nonprinting_all, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(nonprinting_all,
pcmk__xml_escape_attr_pretty));
}
static void
escape_utf8(void **state)
{
/* Non-ASCII UTF-8 characters may be two, three, or four 8-bit bytes wide
* and should not be escaped.
*/
const char *chinese = "仅高级使用";
const char *two_byte = "abc""\xCF\xA6""def";
const char *two_byte_special = "abc""\xCF\xA6""d<ef";
const char *three_byte = "abc""\xEF\x98\x98""def";
const char *three_byte_special = "abc""\xEF\x98\x98""d<ef";
const char *four_byte = "abc""\xF0\x94\x81\x90""def";
const char *four_byte_special = "abc""\xF0\x94\x81\x90""d<ef";
assert_false(pcmk__xml_needs_escape(chinese, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(chinese, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(chinese, pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(two_byte, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(two_byte, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(two_byte,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(two_byte_special,
pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(two_byte_special,
pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(two_byte_special,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(three_byte, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(three_byte, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(three_byte,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(three_byte_special,
pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(three_byte_special,
pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(three_byte_special,
pcmk__xml_escape_attr_pretty));
assert_false(pcmk__xml_needs_escape(four_byte, pcmk__xml_escape_text));
assert_false(pcmk__xml_needs_escape(four_byte, pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(four_byte,
pcmk__xml_escape_attr_pretty));
assert_true(pcmk__xml_needs_escape(four_byte_special,
pcmk__xml_escape_text));
assert_true(pcmk__xml_needs_escape(four_byte_special,
pcmk__xml_escape_attr));
assert_false(pcmk__xml_needs_escape(four_byte_special,
pcmk__xml_escape_attr_pretty));
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(null_empty),
cmocka_unit_test(invalid_type),
cmocka_unit_test(escape_unchanged),
cmocka_unit_test(escape_left_angle),
cmocka_unit_test(escape_right_angle),
cmocka_unit_test(escape_ampersand),
cmocka_unit_test(escape_double_quote),
cmocka_unit_test(escape_newline),
cmocka_unit_test(escape_tab),
cmocka_unit_test(escape_carriage_return),
cmocka_unit_test(escape_nonprinting),
cmocka_unit_test(escape_utf8));
diff --git a/lib/common/unittest.c b/lib/common/unittest.c
index 6cbecf461e..37416d06ea 100644
--- a/lib/common/unittest.c
+++ b/lib/common/unittest.c
@@ -1,147 +1,177 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU Lesser General Public License
* version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/common/unittest_internal.h>
#include <stdlib.h>
#include <unistd.h>
// LCOV_EXCL_START
void
pcmk__assert_validates(xmlNode *xml)
{
const char *schema_dir = NULL;
char *cmd = NULL;
gchar *out = NULL;
gchar *err = NULL;
gint status;
GError *gerr = NULL;
char *xmllint_input = crm_strdup_printf("%s/test-xmllint.XXXXXX",
pcmk__get_tmpdir());
int fd;
int rc;
fd = mkstemp(xmllint_input);
if (fd < 0) {
fail_msg("Could not create temp file: %s", strerror(errno));
}
rc = pcmk__xml2fd(fd, xml);
if (rc != pcmk_rc_ok) {
unlink(xmllint_input);
fail_msg("Could not write temp file: %s", pcmk_rc_str(rc));
}
close(fd);
/* This should be set as part of AM_TESTS_ENVIRONMENT in Makefile.am. */
schema_dir = getenv("PCMK_schema_directory");
if (schema_dir == NULL) {
unlink(xmllint_input);
fail_msg("PCMK_schema_directory is not set in test environment");
}
cmd = crm_strdup_printf("xmllint --relaxng %s/api/api-result.rng %s",
schema_dir, xmllint_input);
if (!g_spawn_command_line_sync(cmd, &out, &err, &status, &gerr)) {
unlink(xmllint_input);
fail_msg("Error occurred when performing validation: %s", gerr->message);
}
if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
unlink(xmllint_input);
fail_msg("XML validation failed: %s\n%s\n", out, err);
}
free(cmd);
g_free(out);
g_free(err);
unlink(xmllint_input);
free(xmllint_input);
}
+/*!
+ * \internal
+ * \brief Perform setup for a group of unit tests that manipulate XML
+ *
+ * This function is suitable for being passed as the first argument to the
+ * \c PCMK__UNIT_TEST macro.
+ *
+ * \param[in] state Ignored
+ *
+ * \return 0
+ */
int
pcmk__xml_test_setup_group(void **state)
{
/* This needs to be run before we run unit tests that manipulate XML.
* Without it, document private data won't get created, which can cause
* segmentation faults or assertions in functions related to change
* tracking and ACLs. There's no harm in doing this before all tests.
*/
crm_xml_init();
return 0;
}
+/*!
+ * \internal
+ * \brief Perform teardown for a group of unit tests that manipulate XML
+ *
+ * This function is suitable for being passed as the second argument to the
+ * \c PCMK__UNIT_TEST macro.
+ *
+ * \param[in] state Ignored
+ *
+ * \return 0
+ */
+int
+pcmk__xml_test_teardown_group(void **state)
+{
+ // Clean up schemas and libxml2 global memory
+ crm_xml_cleanup();
+ return 0;
+}
+
char *
pcmk__cib_test_copy_cib(const char *in_file)
{
char *in_path = crm_strdup_printf("%s/%s", getenv("PCMK_CTS_CLI_DIR"), in_file);
char *out_path = NULL;
char *contents = NULL;
int fd;
/* Copy the CIB over to a temp location so we can modify it. */
out_path = crm_strdup_printf("%s/test-cib.XXXXXX", pcmk__get_tmpdir());
fd = mkstemp(out_path);
if (fd < 0) {
free(out_path);
return NULL;
}
if (pcmk__file_contents(in_path, &contents) != pcmk_rc_ok) {
free(out_path);
close(fd);
return NULL;
}
if (pcmk__write_sync(fd, contents) != pcmk_rc_ok) {
free(out_path);
free(in_path);
free(contents);
close(fd);
return NULL;
}
setenv("CIB_file", out_path, 1);
return out_path;
}
void
pcmk__cib_test_cleanup(char *out_path)
{
unlink(out_path);
free(out_path);
unsetenv("CIB_file");
}
/*!
* \internal
* \brief Initialize logging for unit testing purposes
*
* \param[in] name What to use as system name for logging
* \param[in] filename If not NULL, enable debug logs to this file (intended
* for debugging during development rather than committed
* unit tests)
*/
void
pcmk__test_init_logging(const char *name, const char *filename)
{
pcmk__cli_init_logging(name, 0);
if (filename != NULL) {
pcmk__add_logfile(filename);
set_crm_log_level(LOG_DEBUG);
}
}
// LCOV_EXCL_STOP
diff --git a/lib/pacemaker/tests/pcmk_resource/pcmk_resource_delete_test.c b/lib/pacemaker/tests/pcmk_resource/pcmk_resource_delete_test.c
index e841bfe527..14ef2a1255 100644
--- a/lib/pacemaker/tests/pcmk_resource/pcmk_resource_delete_test.c
+++ b/lib/pacemaker/tests/pcmk_resource/pcmk_resource_delete_test.c
@@ -1,156 +1,156 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
/* Without any special setup, cib_new() in pcmk_resource_delete will use the
* native CIB which means IPC calls. But there's nothing listening for those
* calls, so signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk_resource_delete(&xml, "rsc", "primitive"), ENOTCONN);
pcmk__assert_validates(xml);
free_xml(xml);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("crm_mon.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_input(void **state)
{
xmlNode *xml = NULL;
/* There is a primitive resource named "Fencing", so we're just checking
* that it returns EINVAL if both parameters aren't given.
*/
assert_int_equal(pcmk_resource_delete(&xml, "Fencing", NULL), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
assert_int_equal(pcmk_resource_delete(&xml, NULL, "primitive"), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
}
static xmlNode *
find_rsc(const char *rsc)
{
GString *xpath = g_string_sized_new(1024);
xmlNode *xml_search = NULL;
cib_t *cib = NULL;
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
pcmk__g_strcat(xpath,
pcmk_cib_xpath_for(PCMK_XE_RESOURCES),
"//*[@" PCMK_XA_ID "=\"", rsc, "\"]", NULL);
cib->cmds->query(cib, (const char *) xpath->str, &xml_search,
cib_xpath|cib_scope_local);
g_string_free(xpath, TRUE);
cib__clean_up_connection(&cib);
return xml_search;
}
static void
incorrect_type(void **state)
{
xmlNode *xml = NULL;
xmlNode *result = NULL;
/* cib_process_delete returns pcmk_ok even if given the wrong type so
* we have to do an xpath query of the CIB to make sure it's still
* there.
*/
assert_int_equal(pcmk_resource_delete(&xml, "Fencing", "clone"), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
result = find_rsc("Fencing");
assert_non_null(result);
free_xml(result);
}
static void
correct_type(void **state)
{
xmlNode *xml = NULL;
xmlNode *result = NULL;
assert_int_equal(pcmk_resource_delete(&xml, "Fencing", "primitive"), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
result = find_rsc("Fencing");
assert_null(result);
free_xml(result);
}
static void
unknown_resource(void **state)
{
xmlNode *xml = NULL;
/* cib_process_delete returns pcmk_ok even if asked to delete something
* that doesn't exist.
*/
assert_int_equal(pcmk_resource_delete(&xml, "no_such_resource", "primitive"), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(cib_not_connected),
cmocka_unit_test_setup_teardown(bad_input, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(incorrect_type, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(correct_type, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_resource, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk__get_ticket_state_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk__get_ticket_state_test.c
index 3f363c2b8f..348772355c 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk__get_ticket_state_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk__get_ticket_state_test.c
@@ -1,178 +1,178 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
#include <pacemaker-internal.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
cib_t *cib = cib_new();
/* Without any special setup, cib_new() here will use the native CIB which
* means IPC calls. But there's nothing listening for those calls, so
* signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk__get_ticket_state(cib, "ticketA", &xml), ENOTCONN);
cib__clean_up_connection(&cib);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
xmlNode *xml = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
pcmk__assert_asserts(pcmk__get_ticket_state(NULL, "ticketA", &xml));
pcmk__assert_asserts(pcmk__get_ticket_state(cib, "ticketA", NULL));
cib__clean_up_connection(&cib);
}
static void
unknown_ticket(void **state)
{
xmlNode *xml = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
assert_int_equal(pcmk__get_ticket_state(cib, "XYZ", &xml), ENXIO);
free_xml(xml);
cib__clean_up_connection(&cib);
}
static void
ticket_exists(void **state)
{
xmlNode *xml = NULL;
xmlXPathObject *xpath_obj = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
assert_int_equal(pcmk__get_ticket_state(cib, "ticketA", &xml), pcmk_rc_ok);
/* Verify that the XML result has only one <ticket>, and that its ID is
* what we asked for.
*/
xpath_obj = xpath_search(xml, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]");
assert_int_equal(numXpathResults(xpath_obj), 1);
freeXpathObject(xpath_obj);
free_xml(xml);
cib__clean_up_connection(&cib);
}
static void
multiple_tickets(void **state)
{
xmlNode *xml = NULL;
xmlNode *ticket_node = NULL;
xmlXPathObject *xpath_obj = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
assert_int_equal(pcmk__get_ticket_state(cib, NULL, &xml), pcmk_rc_ok);
/* Verify that the XML result has four <ticket> elements, and that their
* IDs are as expected.
*/
xpath_obj = xpath_search(xml, "//" PCMK__XE_TICKET_STATE);
assert_int_equal(numXpathResults(xpath_obj), 4);
ticket_node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketA");
ticket_node = getXpathResult(xpath_obj, 1);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketB");
ticket_node = getXpathResult(xpath_obj, 2);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketC");
ticket_node = getXpathResult(xpath_obj, 3);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketC");
freeXpathObject(xpath_obj);
free_xml(xml);
cib__clean_up_connection(&cib);
}
static void
duplicate_tickets(void **state)
{
xmlNode *xml = NULL;
xmlXPathObject *xpath_obj = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
assert_int_equal(pcmk__get_ticket_state(cib, "ticketC", &xml), pcmk_rc_duplicate_id);
/* Verify that the XML result has two <ticket> elements, and that their
* IDs are as expected.
*/
xpath_obj = xpath_search(xml, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketC\"]");
assert_int_equal(numXpathResults(xpath_obj), 2);
freeXpathObject(xpath_obj);
free_xml(xml);
cib__clean_up_connection(&cib);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test_setup_teardown(cib_not_connected, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(ticket_exists, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(multiple_tickets, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(duplicate_tickets, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_constraints_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_constraints_test.c
index 08fe0ea7ea..0f59eb28dd 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_constraints_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_constraints_test.c
@@ -1,130 +1,130 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
/* Without any special setup, cib_new() in pcmk_ticket_constraints will use the
* native CIB which means IPC calls. But there's nothing listening for those
* calls, so signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk_ticket_constraints(&xml, NULL), ENOTCONN);
pcmk__assert_validates(xml);
free_xml(xml);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
invalid_argument(void **state)
{
assert_int_equal(pcmk_ticket_constraints(NULL, "ticketA"), EINVAL);
}
static void
unknown_ticket(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_constraints(&xml, "XYZ"), ENXIO);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
ticket_exists(void **state)
{
xmlNode *xml = NULL;
xmlXPathObject *xpath_obj = NULL;
assert_int_equal(pcmk_ticket_constraints(&xml, "ticketA"), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify that the XML result has only one <ticket>, and that its ID is
* what we asked for.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketA\"]");
assert_int_equal(numXpathResults(xpath_obj), 1);
freeXpathObject(xpath_obj);
free_xml(xml);
}
static void
multiple_tickets(void **state)
{
xmlNode *xml = NULL;
xmlNode *ticket_node = NULL;
xmlXPathObject *xpath_obj = NULL;
assert_int_equal(pcmk_ticket_constraints(&xml, NULL), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify that the XML result has two <ticket> elements, and that their
* IDs are as expected.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS "/" PCMK_XE_TICKET);
assert_int_equal(numXpathResults(xpath_obj), 2);
ticket_node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketA");
ticket_node = getXpathResult(xpath_obj, 1);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketB");
freeXpathObject(xpath_obj);
free_xml(xml);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(cib_not_connected),
cmocka_unit_test_setup_teardown(invalid_argument, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(ticket_exists, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(multiple_tickets, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_delete_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_delete_test.c
index 8810039dd4..8e6c11b1b5 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_delete_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_delete_test.c
@@ -1,170 +1,170 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
/* Without any special setup, cib_new() in pcmk_ticket_delete will use the
* native CIB which means IPC calls. But there's nothing listening for those
* calls, so signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk_ticket_delete(&xml, "ticketA", false), ENOTCONN);
pcmk__assert_validates(xml);
free_xml(xml);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_delete(NULL, "ticketA", false), EINVAL);
assert_int_equal(pcmk_ticket_delete(&xml, NULL, false), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
unknown_ticket(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_delete(&xml, "XYZ", false), ENXIO);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
assert_int_equal(pcmk_ticket_delete(&xml, "XYZ", true), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
ticket_granted(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_delete(&xml, "ticketB", false), EACCES);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
ticket_exists(void **state)
{
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
assert_int_equal(pcmk_ticket_delete(&xml, "ticketA", false), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify there's no <ticket_state id="ticketA"> */
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
free_xml(xml);
cib__clean_up_connection(&cib);
}
static void
force_delete_ticket(void **state)
{
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
assert_int_equal(pcmk_ticket_delete(&xml, "ticketB", true), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify there's no <ticket_state id="ticketB"> */
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketB\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
free_xml(xml);
cib__clean_up_connection(&cib);
}
static void
duplicate_tickets(void **state)
{
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
assert_int_equal(pcmk_ticket_delete(&xml, "ticketC", true), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify there's no <ticket_state id="ticketC"> */
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketC\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
free_xml(xml);
cib__clean_up_connection(&cib);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(cib_not_connected),
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(ticket_granted, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(ticket_exists, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(force_delete_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(duplicate_tickets, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_get_attr_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_get_attr_test.c
index 0d86127663..7a49a69f59 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_get_attr_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_get_attr_test.c
@@ -1,150 +1,150 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_get_attr(NULL, "ticketA", "XYZ", NULL), EINVAL);
assert_int_equal(pcmk_ticket_get_attr(&xml, NULL, "attrA", NULL), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
assert_int_equal(pcmk_ticket_get_attr(&xml, "ticketA", NULL, NULL), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
unknown_ticket(void **state)
{
xmlNode *xml = NULL;
/* Both an unknown ticket and an unknown attribute on a known ticket
* return ENXIO so we can't really differentiate between the two here.
* Still, we'd better test both.
*/
assert_int_equal(pcmk_ticket_get_attr(&xml, "XYZ", "attrA", NULL), ENXIO);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
assert_int_equal(pcmk_ticket_get_attr(&xml, "ticketA", "XYZ", NULL), ENXIO);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
verify_results(xmlNode *xml, const char *ticket_id, const char *attr_name,
const char *attr_value)
{
xmlNode *node = NULL;
xmlXPathObject *xpath_obj = NULL;
/* Verify that the XML result has only one <ticket>, and that its ID is
* what we asked for.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS "/" PCMK_XE_TICKET);
assert_int_equal(numXpathResults(xpath_obj), 1);
node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(node, PCMK_XA_ID), ticket_id);
freeXpathObject(xpath_obj);
/* Verify that it has an <attribute> child whose name and value are what
* we expect.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS "/" PCMK_XE_TICKET
"/" PCMK_XE_ATTRIBUTE);
assert_int_equal(numXpathResults(xpath_obj), 1);
node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(node, PCMK_XA_NAME), attr_name);
assert_string_equal(crm_element_value(node, PCMK_XA_VALUE), attr_value);
freeXpathObject(xpath_obj);
}
static void
attribute_exists(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_get_attr(&xml, "ticketA", "owner", NULL), pcmk_rc_ok);
pcmk__assert_validates(xml);
verify_results(xml, "ticketA", "owner", "1");
free_xml(xml);
}
static void
default_no_ticket(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_get_attr(&xml, "ticketX", "ABC", "DEFAULT"), pcmk_rc_ok);
pcmk__assert_validates(xml);
verify_results(xml, "ticketX", "ABC", "DEFAULT");
free_xml(xml);
}
static void
default_no_attribute(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_get_attr(&xml, "ticketA", "ABC", "DEFAULT"), pcmk_rc_ok);
pcmk__assert_validates(xml);
verify_results(xml, "ticketA", "ABC", "DEFAULT");
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(attribute_exists, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(default_no_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(default_no_attribute, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_info_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_info_test.c
index 3ecb050d05..ec02fcc06c 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_info_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_info_test.c
@@ -1,138 +1,138 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
assert_int_equal(pcmk_ticket_info(NULL, "ticketA"), EINVAL);
}
static void
unknown_ticket(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_info(&xml, "XYZ"), ENXIO);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
all_tickets(void **state)
{
xmlNode *node = NULL;
xmlXPathObject *xpath_obj = NULL;
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_info(&xml, NULL), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify that the XML result has three <ticket> elements, with the attributes
* we expect. The input has four tickets, but when they are loaded into the
* scheduler's hash table, the duplicate IDs will collide leaving us with
* three.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS "/" PCMK_XE_TICKET);
assert_int_equal(numXpathResults(xpath_obj), 3);
freeXpathObject(xpath_obj);
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketA\"]");
node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(node, PCMK_XA_STATUS), PCMK_VALUE_REVOKED);
assert_string_equal(crm_element_value(node, PCMK__XA_GRANTED), "false");
assert_string_equal(crm_element_value(node, PCMK_XA_STANDBY), PCMK_VALUE_FALSE);
assert_string_equal(crm_element_value(node, "owner"), "1");
freeXpathObject(xpath_obj);
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketB\"]");
node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(node, PCMK_XA_STATUS), PCMK_VALUE_GRANTED);
assert_string_equal(crm_element_value(node, PCMK__XA_GRANTED), "true");
assert_string_equal(crm_element_value(node, PCMK_XA_STANDBY), PCMK_VALUE_FALSE);
assert_null(crm_element_value(node, "owner"));
freeXpathObject(xpath_obj);
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketC\"]");
node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(node, PCMK_XA_STATUS), PCMK_VALUE_GRANTED);
assert_string_equal(crm_element_value(node, PCMK__XA_GRANTED), "true");
assert_string_equal(crm_element_value(node, PCMK_XA_STANDBY), PCMK_VALUE_FALSE);
assert_null(crm_element_value(node, "owner"));
freeXpathObject(xpath_obj);
free_xml(xml);
}
static void
single_ticket(void **state)
{
xmlNode *node = NULL;
xmlXPathObject *xpath_obj = NULL;
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_info(&xml, "ticketA"), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify that the XML result has only one <ticket>, with the attributes
* we expect.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketA\"]");
assert_int_equal(numXpathResults(xpath_obj), 1);
node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(node, PCMK_XA_STATUS), PCMK_VALUE_REVOKED);
assert_string_equal(crm_element_value(node, PCMK__XA_GRANTED), "false");
assert_string_equal(crm_element_value(node, PCMK_XA_STANDBY), PCMK_VALUE_FALSE);
assert_string_equal(crm_element_value(node, "owner"), "1");
freeXpathObject(xpath_obj);
free_xml(xml);
}
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(all_tickets, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(single_ticket, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_remove_attr_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_remove_attr_test.c
index c024f9a96e..03322d6f0e 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_remove_attr_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_remove_attr_test.c
@@ -1,231 +1,231 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
/* Without any special setup, cib_new() in pcmk_ticket_remove_attr will use the
* native CIB which means IPC calls. But there's nothing listening for those
* calls, so signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk_ticket_remove_attr(&xml, NULL, NULL, false), ENOTCONN);
pcmk__assert_validates(xml);
free_xml(xml);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_remove_attr(NULL, "ticketA", NULL, false), EINVAL);
assert_int_equal(pcmk_ticket_remove_attr(&xml, NULL, NULL, false), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
no_attrs(void **state)
{
GList *attrs = NULL;
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
/* Deleting no attributes on a ticket that doesn't exist is a no-op */
assert_int_equal(pcmk_ticket_remove_attr(&xml, "XYZ", NULL, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"XYZ\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
/* Deleting no attributes on a ticket that exists is also a no-op */
assert_int_equal(pcmk_ticket_remove_attr(&xml, "ticketA", NULL, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("1", crm_element_value(xml_search, "owner"));
free_xml(xml_search);
/* Another way of specifying no attributes */
assert_int_equal(pcmk_ticket_remove_attr(&xml, "XYZ", attrs, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"XYZ\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
g_list_free(attrs);
cib__clean_up_connection(&cib);
}
static void
remove_missing_attrs(void **state)
{
GList *attrs = NULL;
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
attrs = g_list_append(attrs, strdup("XYZ"));
/* Deleting an attribute that doesn't exist is a no-op */
assert_int_equal(pcmk_ticket_remove_attr(&xml, "ticketA", attrs, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("1", crm_element_value(xml_search, "owner"));
assert_null(crm_element_value(xml_search, "XYZ"));
free_xml(xml_search);
g_list_free_full(attrs, free);
cib__clean_up_connection(&cib);
}
static void
remove_existing_attr(void **state)
{
GList *attrs = NULL;
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
attrs = g_list_append(attrs, strdup("owner"));
assert_int_equal(pcmk_ticket_remove_attr(&xml, "ticketA", attrs, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(crm_element_value(xml_search, "owner"));
free_xml(xml_search);
g_list_free_full(attrs, free);
cib__clean_up_connection(&cib);
}
static void
remove_granted_without_force(void **state)
{
GList *attrs = NULL;
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
attrs = g_list_append(attrs, strdup(PCMK__XA_GRANTED));
assert_int_equal(pcmk_ticket_remove_attr(&xml, "ticketB", attrs, false), EACCES);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketB\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("true", crm_element_value(xml_search, PCMK__XA_GRANTED));
free_xml(xml_search);
g_list_free_full(attrs, free);
cib__clean_up_connection(&cib);
}
static void
remove_granted_with_force(void **state)
{
GList *attrs = NULL;
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
attrs = g_list_append(attrs, strdup(PCMK__XA_GRANTED));
assert_int_equal(pcmk_ticket_remove_attr(&xml, "ticketB", attrs, true), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketB\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(crm_element_value(xml_search, PCMK__XA_GRANTED));
free_xml(xml_search);
g_list_free_full(attrs, free);
cib__clean_up_connection(&cib);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(cib_not_connected),
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(no_attrs, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(remove_missing_attrs, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(remove_existing_attr, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(remove_granted_without_force, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(remove_granted_with_force, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_set_attr_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_set_attr_test.c
index 100d05c04b..7a4bbcbfbc 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_set_attr_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_set_attr_test.c
@@ -1,281 +1,281 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
/* Without any special setup, cib_new() in pcmk_ticket_set_attr will use the
* native CIB which means IPC calls. But there's nothing listening for those
* calls, so signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk_ticket_set_attr(&xml, NULL, NULL, false), ENOTCONN);
pcmk__assert_validates(xml);
free_xml(xml);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_set_attr(NULL, "ticketA", NULL, false), EINVAL);
assert_int_equal(pcmk_ticket_set_attr(&xml, NULL, NULL, false), EINVAL);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
unknown_ticket_no_attrs(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
/* Setting no attributes on a ticket that doesn't exist is a no-op */
assert_int_equal(pcmk_ticket_set_attr(&xml, "XYZ", NULL, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
xml = NULL;
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"XYZ\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
/* Another way of specifying no attributes */
assert_int_equal(pcmk_ticket_set_attr(&xml, "XYZ", attrs, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"XYZ\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_null(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
static void
unknown_ticket_with_attrs(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
pcmk__insert_dup(attrs, "attrA", "123");
pcmk__insert_dup(attrs, "attrB", "456");
/* Setting attributes on a ticket that doesn't exist causes the ticket to
* be created with the given attributes
*/
assert_int_equal(pcmk_ticket_set_attr(&xml, "XYZ", attrs, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"XYZ\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("123", crm_element_value(xml_search, "attrA"));
assert_string_equal("456", crm_element_value(xml_search, "attrB"));
free_xml(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
static void
overwrite_existing_attr(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
pcmk__insert_dup(attrs, "owner", "2");
assert_int_equal(pcmk_ticket_set_attr(&xml, "ticketA", attrs, false), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("2", crm_element_value(xml_search, "owner"));
free_xml(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
static void
not_granted_to_granted_without_force(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
pcmk__insert_dup(attrs, PCMK__XA_GRANTED, "true");
assert_int_equal(pcmk_ticket_set_attr(&xml, "ticketA", attrs, false), EACCES);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("false", crm_element_value(xml_search, PCMK__XA_GRANTED));
assert_null(crm_element_value(xml_search, PCMK_XA_LAST_GRANTED));
free_xml(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
static void
not_granted_to_granted_with_force(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
pcmk__insert_dup(attrs, PCMK__XA_GRANTED, "true");
assert_int_equal(pcmk_ticket_set_attr(&xml, "ticketA", attrs, true), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketA\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("true", crm_element_value(xml_search, PCMK__XA_GRANTED));
assert_non_null(crm_element_value(xml_search, PCMK_XA_LAST_GRANTED));
free_xml(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
static void
granted_to_not_granted_without_force(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
pcmk__insert_dup(attrs, PCMK__XA_GRANTED, "false");
assert_int_equal(pcmk_ticket_set_attr(&xml, "ticketB", attrs, false), EACCES);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketB\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("true", crm_element_value(xml_search, PCMK__XA_GRANTED));
assert_null(crm_element_value(xml_search, PCMK_XA_LAST_GRANTED));
free_xml(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
static void
granted_to_not_granted_with_force(void **state)
{
GHashTable *attrs = pcmk__strkey_table(free, free);
xmlNode *xml = NULL;
xmlNode *xml_search = NULL;
cib_t *cib;
pcmk__insert_dup(attrs, PCMK__XA_GRANTED, "false");
assert_int_equal(pcmk_ticket_set_attr(&xml, "ticketB", attrs, true), pcmk_rc_ok);
pcmk__assert_validates(xml);
free_xml(xml);
cib = cib_new();
cib->cmds->signon(cib, crm_system_name, cib_command);
cib->cmds->query(cib, "//" PCMK__XE_TICKET_STATE "[@" PCMK_XA_ID "=\"ticketB\"]",
&xml_search, cib_xpath | cib_scope_local);
assert_string_equal("false", crm_element_value(xml_search, PCMK__XA_GRANTED));
assert_null(crm_element_value(xml_search, PCMK_XA_LAST_GRANTED));
free_xml(xml_search);
g_hash_table_destroy(attrs);
cib__clean_up_connection(&cib);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(cib_not_connected),
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket_no_attrs, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket_with_attrs, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(overwrite_existing_attr, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(not_granted_to_granted_without_force, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(not_granted_to_granted_with_force, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(granted_to_not_granted_without_force, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(granted_to_not_granted_with_force, setup_test, teardown_test))
diff --git a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_state_test.c b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_state_test.c
index 4ea018b68f..d8f020e858 100644
--- a/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_state_test.c
+++ b/lib/pacemaker/tests/pcmk_ticket/pcmk_ticket_state_test.c
@@ -1,156 +1,156 @@
/*
* Copyright 2024 the Pacemaker project contributors
*
* The version control history for this file may have further details.
*
* This source code is licensed under the GNU General Public License version 2
* or later (GPLv2+) WITHOUT ANY WARRANTY.
*/
#include <crm_internal.h>
#include <crm/cib/internal.h>
#include <crm/common/unittest_internal.h>
#include <crm/common/xml.h>
#include <pacemaker.h>
static char *cib_path = NULL;
static void
cib_not_connected(void **state)
{
xmlNode *xml = NULL;
/* Without any special setup, cib_new() in pcmk_ticket_state will use the
* native CIB which means IPC calls. But there's nothing listening for those
* calls, so signon() will return ENOTCONN. Check that we handle that.
*/
assert_int_equal(pcmk_ticket_state(&xml, "ticketA"), ENOTCONN);
pcmk__assert_validates(xml);
free_xml(xml);
}
static int
setup_test(void **state)
{
cib_path = pcmk__cib_test_copy_cib("tickets.xml");
if (cib_path == NULL) {
return -1;
}
return 0;
}
static int
teardown_test(void **state)
{
pcmk__cib_test_cleanup(cib_path);
cib_path = NULL;
return 0;
}
static void
bad_arguments(void **state)
{
assert_int_equal(pcmk_ticket_state(NULL, "ticketA"), EINVAL);
}
static void
unknown_ticket(void **state)
{
xmlNode *xml = NULL;
assert_int_equal(pcmk_ticket_state(&xml, "XYZ"), ENXIO);
pcmk__assert_validates(xml);
free_xml(xml);
}
static void
ticket_exists(void **state)
{
xmlNode *xml = NULL;
xmlXPathObject *xpath_obj = NULL;
assert_int_equal(pcmk_ticket_state(&xml, "ticketA"), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify that the XML result has only one <ticket>, and that its ID is
* what we asked for.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketA\"]");
assert_int_equal(numXpathResults(xpath_obj), 1);
freeXpathObject(xpath_obj);
free_xml(xml);
}
static void
multiple_tickets(void **state)
{
xmlNode *xml = NULL;
xmlNode *ticket_node = NULL;
xmlXPathObject *xpath_obj = NULL;
assert_int_equal(pcmk_ticket_state(&xml, NULL), pcmk_rc_ok);
pcmk__assert_validates(xml);
/* Verify that the XML result has four <ticket> elements, and that their
* IDs are as expected.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS "/" PCMK_XE_TICKET);
assert_int_equal(numXpathResults(xpath_obj), 4);
ticket_node = getXpathResult(xpath_obj, 0);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketA");
ticket_node = getXpathResult(xpath_obj, 1);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketB");
ticket_node = getXpathResult(xpath_obj, 2);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketC");
ticket_node = getXpathResult(xpath_obj, 3);
assert_string_equal(crm_element_value(ticket_node, PCMK_XA_ID), "ticketC");
freeXpathObject(xpath_obj);
free_xml(xml);
}
static void
duplicate_tickets(void **state)
{
xmlNode *xml = NULL;
xmlXPathObject *xpath_obj = NULL;
assert_int_equal(pcmk_ticket_state(&xml, "ticketC"), pcmk_rc_duplicate_id);
/* Verify that the XML result has two <ticket> elements, and that their
* IDs are as expected.
*/
xpath_obj = xpath_search(xml, "//" PCMK_XE_PACEMAKER_RESULT "/" PCMK_XE_TICKETS
"/" PCMK_XE_TICKET "[@" PCMK_XA_ID "=\"ticketC\"]");
assert_int_equal(numXpathResults(xpath_obj), 2);
freeXpathObject(xpath_obj);
free_xml(xml);
}
/* There are two kinds of tests in this file:
*
* (1) Those that test what happens if the CIB is not set up correctly, and
* (2) Those that test what happens when run against a CIB.
*
* Therefore, we need two kinds of setup/teardown functions. We only do
* minimal overall setup for the entire group, and then setup the CIB for
* those tests that need it.
*/
-PCMK__UNIT_TEST(pcmk__xml_test_setup_group, NULL,
+PCMK__UNIT_TEST(pcmk__xml_test_setup_group, pcmk__xml_test_teardown_group,
cmocka_unit_test(cib_not_connected),
cmocka_unit_test_setup_teardown(bad_arguments, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(unknown_ticket, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(ticket_exists, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(multiple_tickets, setup_test, teardown_test),
cmocka_unit_test_setup_teardown(duplicate_tickets, setup_test, teardown_test))
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Apr 21, 7:03 PM (20 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1663735
Default Alt Text
(252 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment