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 #include #include #include #include #include #include #include #include #include #include #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 #include #include #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 #include #include #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 #include // xmlNode #include #include #include #include #include "../../crmcommon_private.h" #define ALL_VALID "" #define YEARS_INVALID "" #define YEARS_TOO_BIG "" #define YEARS_TOO_SMALL "" 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 #include #include #include 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 #include #include static void empty_input(void **state) { xmlNode *node = pcmk__xml_parse(""); 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(""); assert_false(pcmk__xe_attr_is_true(node, "c")); free_xml(node); } static void attr_present(void **state) { xmlNode *node = pcmk__xml_parse(""); 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 #include #include static void empty_input(void **state) { xmlNode *node = pcmk__xml_parse(""); 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(""); 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(""); 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 #include #include #include #include #include #include #define REFERENCE_ISO8601 "2024-001" #define ATTR_PRESENT "start" #define ATTR_MISSING "end" #define REFERENCE_XML "" #define BAD_XML "" 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 #include #include #include static void set_attr(void **state) { xmlNode *node = pcmk__xml_parse(""); 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 #include 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 #include 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 #include #include #include #include #include #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 #include #include #include #include #include /* * 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 "" 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 #include #include #include #include #include #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' />" \ "" 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' />" \ "" 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' />" \ "" 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'/>" \ "" 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'/>" \ "" 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'/>" \ "" 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 #include #include #include #include #include #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", "", pcmk_rc_ok); } static void invalid_range(void **state) { // Currently acceptable run_one_test("2020-01-01", "", pcmk_rc_ok); } static void time_satisfies_year_spec(void **state) { run_one_test("2020-01-01", "", 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 #include #include #include #include #include #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 #include #include #include #include #include #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 #include #include #include #include #include "../../crmcommon_private.h" #define MONTHS_TO_SECONDS "months=\"2\" weeks=\"3\" days=\"-1\" " \ "hours=\"1\" minutes=\"1\" seconds=\"1\" />" #define ALL_VALID " #include #include #include #include #include /* * 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' />" \ "" 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' />" \ "" 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 "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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' />" \ "" 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 #include #include #include #include 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: * * * * CDATA * CDATA * ... * * */ 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 #include #include 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 #include #include #include const char *str1 = "\n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" ""; 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 #include #include 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 = "\n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" ""; 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 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 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 = "\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" ""; static void multiple_levels_test(void **state) { xmlNode *xml = pcmk__xml_parse(str2); /* The handler should be called once for every 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 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 = "\n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" " \n" " \n" " content\n" " \n" ""; 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 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 #include #include #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 #include #include #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 = " #include #include #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 = " #include #include #include // 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 #include #include #include #include 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 #include #include #include #include #include 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 , 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 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 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 #include #include #include #include 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 , 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 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 #include #include #include #include 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 */ 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 */ 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 */ 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 #include #include #include #include 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 , 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 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 #include #include #include #include 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 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 , 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 #include #include #include #include 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 #include #include #include #include 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 #include #include #include #include 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 , 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 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 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))