Page MenuHomeClusterLabs Projects

No OneTemporary

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 = "&#x0A;abc&#x0A;def&#x0A;";
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 = "&#x09;abc&#x09;def&#x09;";
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 = "&#x0D;abc&#x0D;def&#x0D;";
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 = "&#x07;&#x7F;&#x1B;";
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

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)

Event Timeline