diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:53:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:53:20 +0000 |
commit | e5a812082ae033afb1eed82c0f2df3d0f6bdc93f (patch) | |
tree | a6716c9275b4b413f6c9194798b34b91affb3cc7 /lib/common/tests | |
parent | Initial commit. (diff) | |
download | pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.tar.xz pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.zip |
Adding upstream version 2.1.6.upstream/2.1.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/common/tests')
109 files changed, 7116 insertions, 0 deletions
diff --git a/lib/common/tests/Makefile.am b/lib/common/tests/Makefile.am new file mode 100644 index 0000000..b147309 --- /dev/null +++ b/lib/common/tests/Makefile.am @@ -0,0 +1,32 @@ +# +# Copyright 2020-2022 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. +# + +SUBDIRS = \ + acl \ + agents \ + cmdline \ + flags \ + health \ + io \ + iso8601 \ + lists \ + nvpair \ + operations \ + options \ + output \ + results \ + scores \ + strings \ + utils \ + xml \ + xpath + +if SUPPORT_PROCFS +SUBDIRS += procfs +endif diff --git a/lib/common/tests/acl/Makefile.am b/lib/common/tests/acl/Makefile.am new file mode 100644 index 0000000..50408f9 --- /dev/null +++ b/lib/common/tests/acl/Makefile.am @@ -0,0 +1,21 @@ +# +# Copyright 2021-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. + +check_PROGRAMS = \ + pcmk__is_user_in_group_test \ + pcmk_acl_required_test \ + xml_acl_denied_test \ + xml_acl_enabled_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/acl/pcmk__is_user_in_group_test.c b/lib/common/tests/acl/pcmk__is_user_in_group_test.c new file mode 100644 index 0000000..917d92e --- /dev/null +++ b/lib/common/tests/acl/pcmk__is_user_in_group_test.c @@ -0,0 +1,38 @@ +/* + * Copyright 2020-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/acl.h> + +#include "../../crmcommon_private.h" +#include "mock_private.h" + +static void +is_pcmk__is_user_in_group(void **state) +{ + pcmk__mock_grent = true; + + // null user + assert_false(pcmk__is_user_in_group(NULL, "grp0")); + // null group + assert_false(pcmk__is_user_in_group("user0", NULL)); + // nonexistent group + assert_false(pcmk__is_user_in_group("user0", "nonexistent_group")); + // user is in group + assert_true(pcmk__is_user_in_group("user0", "grp0")); + // user is not in group + assert_false(pcmk__is_user_in_group("user2", "grp0")); + + pcmk__mock_grent = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(is_pcmk__is_user_in_group)) diff --git a/lib/common/tests/acl/pcmk_acl_required_test.c b/lib/common/tests/acl/pcmk_acl_required_test.c new file mode 100644 index 0000000..bd5b922 --- /dev/null +++ b/lib/common/tests/acl/pcmk_acl_required_test.c @@ -0,0 +1,26 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/acl.h> + +static void +is_pcmk_acl_required(void **state) +{ + assert_false(pcmk_acl_required(NULL)); + assert_false(pcmk_acl_required("")); + assert_true(pcmk_acl_required("123")); + assert_false(pcmk_acl_required(CRM_DAEMON_USER)); + assert_false(pcmk_acl_required("root")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(is_pcmk_acl_required)) diff --git a/lib/common/tests/acl/xml_acl_denied_test.c b/lib/common/tests/acl/xml_acl_denied_test.c new file mode 100644 index 0000000..faf2a39 --- /dev/null +++ b/lib/common/tests/acl/xml_acl_denied_test.c @@ -0,0 +1,61 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/acl.h> + +#include "../../crmcommon_private.h" + +static void +is_xml_acl_denied_without_node(void **state) +{ + xmlNode *test_xml = create_xml_node(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 = create_xml_node(NULL, "test_xml"); + + // allocate memory for _private, which is NULL by default + test_xml->doc->_private = calloc(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(NULL, NULL, + 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 new file mode 100644 index 0000000..28665f4 --- /dev/null +++ b/lib/common/tests/acl/xml_acl_enabled_test.c @@ -0,0 +1,61 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/acl.h> + +#include "../../crmcommon_private.h" + +static void +is_xml_acl_enabled_without_node(void **state) +{ + xmlNode *test_xml = create_xml_node(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 = create_xml_node(NULL, "test_xml"); + + // allocate memory for _private, which is NULL by default + test_xml->doc->_private = calloc(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(NULL, NULL, + cmocka_unit_test(is_xml_acl_enabled_without_node), + cmocka_unit_test(is_xml_acl_enabled_with_node)) diff --git a/lib/common/tests/agents/Makefile.am b/lib/common/tests/agents/Makefile.am new file mode 100644 index 0000000..7a54b7d --- /dev/null +++ b/lib/common/tests/agents/Makefile.am @@ -0,0 +1,20 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = crm_generate_ra_key_test \ + crm_parse_agent_spec_test \ + pcmk__effective_rc_test \ + pcmk_get_ra_caps_test \ + pcmk_stonith_param_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/agents/crm_generate_ra_key_test.c b/lib/common/tests/agents/crm_generate_ra_key_test.c new file mode 100644 index 0000000..f71c1c2 --- /dev/null +++ b/lib/common/tests/agents/crm_generate_ra_key_test.c @@ -0,0 +1,48 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/agents.h> + +static void +all_params_null(void **state) { + assert_null(crm_generate_ra_key(NULL, NULL, NULL)); +} + +static void +some_params_null(void **state) { + char *retval; + + assert_null(crm_generate_ra_key("std", "prov", NULL)); + + retval = crm_generate_ra_key("std", NULL, "ty"); + assert_string_equal(retval, "std:ty"); + free(retval); + + assert_null(crm_generate_ra_key(NULL, "prov", "ty")); + assert_null(crm_generate_ra_key("std", NULL, NULL)); + assert_null(crm_generate_ra_key(NULL, "prov", NULL)); + assert_null(crm_generate_ra_key(NULL, NULL, "ty")); +} + +static void +no_params_null(void **state) { + char *retval; + + retval = crm_generate_ra_key("std", "prov", "ty"); + assert_string_equal(retval, "std:prov:ty"); + free(retval); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(all_params_null), + cmocka_unit_test(some_params_null), + cmocka_unit_test(no_params_null)) diff --git a/lib/common/tests/agents/crm_parse_agent_spec_test.c b/lib/common/tests/agents/crm_parse_agent_spec_test.c new file mode 100644 index 0000000..cfd75f0 --- /dev/null +++ b/lib/common/tests/agents/crm_parse_agent_spec_test.c @@ -0,0 +1,87 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/agents.h> + +static void +all_params_null(void **state) { + assert_int_equal(crm_parse_agent_spec(NULL, NULL, NULL, NULL), -EINVAL); + assert_int_equal(crm_parse_agent_spec("", NULL, NULL, NULL), -EINVAL); + assert_int_equal(crm_parse_agent_spec(":", NULL, NULL, NULL), -EINVAL); + assert_int_equal(crm_parse_agent_spec("::", NULL, NULL, NULL), -EINVAL); +} + +static void +no_prov_or_type(void **state) { + assert_int_equal(crm_parse_agent_spec("ocf", NULL, NULL, NULL), -EINVAL); + assert_int_equal(crm_parse_agent_spec("ocf:", NULL, NULL, NULL), -EINVAL); + assert_int_equal(crm_parse_agent_spec("ocf::", NULL, NULL, NULL), -EINVAL); +} + +static void +no_type(void **state) { + assert_int_equal(crm_parse_agent_spec("ocf:pacemaker:", NULL, NULL, NULL), -EINVAL); +} + +static void +get_std_and_ty(void **state) { + char *std = NULL; + char *prov = NULL; + char *ty = NULL; + + assert_int_equal(crm_parse_agent_spec("stonith:fence_xvm", &std, &prov, &ty), pcmk_ok); + assert_string_equal(std, "stonith"); + assert_null(prov); + assert_string_equal(ty, "fence_xvm"); + + free(std); + free(ty); +} + +static void +get_all_values(void **state) { + char *std = NULL; + char *prov = NULL; + char *ty = NULL; + + assert_int_equal(crm_parse_agent_spec("ocf:pacemaker:ping", &std, &prov, &ty), pcmk_ok); + assert_string_equal(std, "ocf"); + assert_string_equal(prov, "pacemaker"); + assert_string_equal(ty, "ping"); + + free(std); + free(prov); + free(ty); +} + +static void +get_systemd_values(void **state) { + char *std = NULL; + char *prov = NULL; + char *ty = NULL; + + assert_int_equal(crm_parse_agent_spec("systemd:UNIT@A:B", &std, &prov, &ty), pcmk_ok); + assert_string_equal(std, "systemd"); + assert_null(prov); + assert_string_equal(ty, "UNIT@A:B"); + + free(std); + free(ty); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(all_params_null), + cmocka_unit_test(no_prov_or_type), + cmocka_unit_test(no_type), + cmocka_unit_test(get_std_and_ty), + cmocka_unit_test(get_all_values), + cmocka_unit_test(get_systemd_values)) diff --git a/lib/common/tests/agents/pcmk__effective_rc_test.c b/lib/common/tests/agents/pcmk__effective_rc_test.c new file mode 100644 index 0000000..c9bad97 --- /dev/null +++ b/lib/common/tests/agents/pcmk__effective_rc_test.c @@ -0,0 +1,36 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/agents.h> + +static void +pcmk__effective_rc_test(void **state) { + /* All other PCMK_OCF_* values after UNKNOWN are deprecated and no longer used, + * so probably not worth testing them. + */ + assert_int_equal(PCMK_OCF_OK, pcmk__effective_rc(PCMK_OCF_OK)); + assert_int_equal(PCMK_OCF_OK, pcmk__effective_rc(PCMK_OCF_DEGRADED)); + assert_int_equal(PCMK_OCF_RUNNING_PROMOTED, pcmk__effective_rc(PCMK_OCF_DEGRADED_PROMOTED)); + assert_int_equal(PCMK_OCF_UNKNOWN, pcmk__effective_rc(PCMK_OCF_UNKNOWN)); + + /* There's nothing that says pcmk__effective_rc is restricted to PCMK_OCF_* + * values. That's just how it's used. Let's check some values outside + * that range just to be sure. + */ + assert_int_equal(-1, pcmk__effective_rc(-1)); + assert_int_equal(255, pcmk__effective_rc(255)); + assert_int_equal(INT_MAX, pcmk__effective_rc(INT_MAX)); + assert_int_equal(INT_MIN, pcmk__effective_rc(INT_MIN)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(pcmk__effective_rc_test)) diff --git a/lib/common/tests/agents/pcmk_get_ra_caps_test.c b/lib/common/tests/agents/pcmk_get_ra_caps_test.c new file mode 100644 index 0000000..178dce5 --- /dev/null +++ b/lib/common/tests/agents/pcmk_get_ra_caps_test.c @@ -0,0 +1,63 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/agents.h> + +static void +ocf_standard(void **state) { + uint32_t expected = pcmk_ra_cap_provider | pcmk_ra_cap_params | + pcmk_ra_cap_unique | pcmk_ra_cap_promotable; + + assert_int_equal(pcmk_get_ra_caps("ocf"), expected); + assert_int_equal(pcmk_get_ra_caps("OCF"), expected); +} + +static void +stonith_standard(void **state) { + uint32_t expected = pcmk_ra_cap_params | pcmk_ra_cap_unique | + pcmk_ra_cap_stdin | pcmk_ra_cap_fence_params; + + assert_int_equal(pcmk_get_ra_caps("stonith"), expected); + assert_int_equal(pcmk_get_ra_caps("StOnItH"), expected); +} + +static void +service_standard(void **state) { + assert_int_equal(pcmk_get_ra_caps("systemd"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("SYSTEMD"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("service"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("SeRvIcE"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("lsb"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("LSB"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("upstart"), pcmk_ra_cap_status); + assert_int_equal(pcmk_get_ra_caps("uPsTaRt"), pcmk_ra_cap_status); +} + +static void +nagios_standard(void **state) { + assert_int_equal(pcmk_get_ra_caps("nagios"), pcmk_ra_cap_params); + assert_int_equal(pcmk_get_ra_caps("NAGios"), pcmk_ra_cap_params); +} + +static void +unknown_standard(void **state) { + assert_int_equal(pcmk_get_ra_caps("blahblah"), pcmk_ra_cap_none); + assert_int_equal(pcmk_get_ra_caps(""), pcmk_ra_cap_none); + assert_int_equal(pcmk_get_ra_caps(NULL), pcmk_ra_cap_none); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(ocf_standard), + cmocka_unit_test(stonith_standard), + cmocka_unit_test(service_standard), + cmocka_unit_test(nagios_standard), + cmocka_unit_test(unknown_standard)) diff --git a/lib/common/tests/agents/pcmk_stonith_param_test.c b/lib/common/tests/agents/pcmk_stonith_param_test.c new file mode 100644 index 0000000..fad431e --- /dev/null +++ b/lib/common/tests/agents/pcmk_stonith_param_test.c @@ -0,0 +1,50 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/agents.h> + +static void +is_stonith_param(void **state) +{ + assert_false(pcmk_stonith_param(NULL)); + assert_false(pcmk_stonith_param("")); + assert_false(pcmk_stonith_param("unrecognized")); + assert_false(pcmk_stonith_param("pcmk_unrecognized")); + assert_false(pcmk_stonith_param("x" PCMK_STONITH_ACTION_LIMIT)); + assert_false(pcmk_stonith_param(PCMK_STONITH_ACTION_LIMIT "x")); + + assert_true(pcmk_stonith_param(PCMK_STONITH_ACTION_LIMIT)); + assert_true(pcmk_stonith_param(PCMK_STONITH_DELAY_BASE)); + assert_true(pcmk_stonith_param(PCMK_STONITH_DELAY_MAX)); + assert_true(pcmk_stonith_param(PCMK_STONITH_HOST_ARGUMENT)); + assert_true(pcmk_stonith_param(PCMK_STONITH_HOST_CHECK)); + assert_true(pcmk_stonith_param(PCMK_STONITH_HOST_LIST)); + assert_true(pcmk_stonith_param(PCMK_STONITH_HOST_MAP)); + assert_true(pcmk_stonith_param(PCMK_STONITH_PROVIDES)); + assert_true(pcmk_stonith_param(PCMK_STONITH_STONITH_TIMEOUT)); +} + +static void +is_stonith_action_param(void **state) +{ + /* Currently, the function accepts any string not containing underbars as + * the action name, so we do not need to verify particular action names. + */ + assert_false(pcmk_stonith_param("pcmk_on_unrecognized")); + assert_true(pcmk_stonith_param("pcmk_on_action")); + assert_true(pcmk_stonith_param("pcmk_on_timeout")); + assert_true(pcmk_stonith_param("pcmk_on_retries")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(is_stonith_param), + cmocka_unit_test(is_stonith_action_param)) diff --git a/lib/common/tests/cmdline/Makefile.am b/lib/common/tests/cmdline/Makefile.am new file mode 100644 index 0000000..d781ed5 --- /dev/null +++ b/lib/common/tests/cmdline/Makefile.am @@ -0,0 +1,17 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__cmdline_preproc_test \ + pcmk__quote_cmdline_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c b/lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c new file mode 100644 index 0000000..863fbb9 --- /dev/null +++ b/lib/common/tests/cmdline/pcmk__cmdline_preproc_test.c @@ -0,0 +1,156 @@ +/* + * Copyright 2020-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/cmdline_internal.h> + +#include <glib.h> +#include <stdint.h> + +#define LISTS_EQ(a, b) { \ + assert_int_equal(g_strv_length((gchar **) (a)), g_strv_length((gchar **) (b))); \ + for (int i = 0; i < g_strv_length((a)); i++) { \ + assert_string_equal((a)[i], (b)[i]); \ + } \ +} + +static void +empty_input(void **state) { + assert_null(pcmk__cmdline_preproc(NULL, "")); +} + +static void +no_specials(void **state) { + const char *argv[] = { "crm_mon", "-a", "-b", "-c", "-d", "-1", NULL }; + const gchar *expected[] = { "crm_mon", "-a", "-b", "-c", "-d", "-1", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); + + processed = pcmk__cmdline_preproc((char **) argv, ""); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +single_dash(void **state) { + const char *argv[] = { "crm_mon", "-", NULL }; + const gchar *expected[] = { "crm_mon", "-", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +double_dash(void **state) { + const char *argv[] = { "crm_mon", "-a", "--", "-bc", NULL }; + const gchar *expected[] = { "crm_mon", "-a", "--", "-bc", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +special_args(void **state) { + const char *argv[] = { "crm_mon", "-aX", "-Fval", NULL }; + const gchar *expected[] = { "crm_mon", "-a", "X", "-F", "val", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "aF"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +special_arg_at_end(void **state) { + const char *argv[] = { "crm_mon", "-a", NULL }; + const gchar *expected[] = { "crm_mon", "-a", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "a"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +long_arg(void **state) { + const char *argv[] = { "crm_mon", "--blah=foo", NULL }; + const gchar *expected[] = { "crm_mon", "--blah=foo", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +negative_score(void **state) { + const char *argv[] = { "crm_mon", "-v", "-1000", NULL }; + const gchar *expected[] = { "crm_mon", "-v", "-1000", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "v"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +negative_score_2(void **state) { + const char *argv[] = { "crm_mon", "-1i3", NULL }; + const gchar *expected[] = { "crm_mon", "-1", "-i", "-3", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, NULL); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +string_arg_with_dash(void **state) { + const char *argv[] = { "crm_mon", "-n", "crm_mon_options", "-v", "--opt1 --opt2", NULL }; + const gchar *expected[] = { "crm_mon", "-n", "crm_mon_options", "-v", "--opt1 --opt2", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "v"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +string_arg_with_dash_2(void **state) { + const char *argv[] = { "crm_mon", "-n", "crm_mon_options", "-v", "-1i3", NULL }; + const gchar *expected[] = { "crm_mon", "-n", "crm_mon_options", "-v", "-1i3", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "v"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +static void +string_arg_with_dash_3(void **state) { + const char *argv[] = { "crm_mon", "-abc", "-1i3", NULL }; + const gchar *expected[] = { "crm_mon", "-a", "-b", "-c", "-1i3", NULL }; + + gchar **processed = pcmk__cmdline_preproc((char **) argv, "c"); + LISTS_EQ(processed, expected); + g_strfreev(processed); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input), + cmocka_unit_test(no_specials), + cmocka_unit_test(single_dash), + cmocka_unit_test(double_dash), + cmocka_unit_test(special_args), + cmocka_unit_test(special_arg_at_end), + cmocka_unit_test(long_arg), + cmocka_unit_test(negative_score), + cmocka_unit_test(negative_score_2), + cmocka_unit_test(string_arg_with_dash), + cmocka_unit_test(string_arg_with_dash_2), + cmocka_unit_test(string_arg_with_dash_3)) diff --git a/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c b/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c new file mode 100644 index 0000000..42bd8ca --- /dev/null +++ b/lib/common/tests/cmdline/pcmk__quote_cmdline_test.c @@ -0,0 +1,56 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/cmdline_internal.h> + +#include <glib.h> + +static void +empty_input(void **state) { + assert_null(pcmk__quote_cmdline(NULL)); +} + +static void +no_spaces(void **state) { + const char *argv[] = { "crm_resource", "-r", "rsc1", "--meta", "-p", "comment", "-v", "hello", "--output-as=xml", NULL }; + const gchar *expected = "crm_resource -r rsc1 --meta -p comment -v hello --output-as=xml"; + + gchar *processed = pcmk__quote_cmdline((gchar **) argv); + assert_string_equal(processed, expected); + g_free(processed); +} + +static void +spaces_no_quote(void **state) { + const char *argv[] = { "crm_resource", "-r", "rsc1", "--meta", "-p", "comment", "-v", "hello world", "--output-as=xml", NULL }; + const gchar *expected = "crm_resource -r rsc1 --meta -p comment -v 'hello world' --output-as=xml"; + + gchar *processed = pcmk__quote_cmdline((gchar **) argv); + assert_string_equal(processed, expected); + g_free(processed); +} + +static void +spaces_with_quote(void **state) { + const char *argv[] = { "crm_resource", "-r", "rsc1", "--meta", "-p", "comment", "-v", "here's johnny", "--output-as=xml", NULL }; + const gchar *expected = "crm_resource -r rsc1 --meta -p comment -v 'here\\\'s johnny' --output-as=xml"; + + gchar *processed = pcmk__quote_cmdline((gchar **) argv); + assert_string_equal(processed, expected); + g_free(processed); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input), + cmocka_unit_test(no_spaces), + cmocka_unit_test(spaces_no_quote), + cmocka_unit_test(spaces_with_quote)) diff --git a/lib/common/tests/flags/Makefile.am b/lib/common/tests/flags/Makefile.am new file mode 100644 index 0000000..16d8ffb --- /dev/null +++ b/lib/common/tests/flags/Makefile.am @@ -0,0 +1,20 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + pcmk__clear_flags_as_test \ + pcmk__set_flags_as_test \ + pcmk_all_flags_set_test \ + pcmk_any_flags_set_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/flags/pcmk__clear_flags_as_test.c b/lib/common/tests/flags/pcmk__clear_flags_as_test.c new file mode 100644 index 0000000..07dbe28 --- /dev/null +++ b/lib/common/tests/flags/pcmk__clear_flags_as_test.c @@ -0,0 +1,41 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +clear_none(void **state) { + assert_int_equal(pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0x00f, NULL), 0x0f0); + assert_int_equal(pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0xf0f, NULL), 0x0f0); +} + +static void +clear_some(void **state) { + assert_int_equal(pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0x020, NULL), 0x0d0); + assert_int_equal(pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0x030, NULL), 0x0c0); +} + +static void +clear_all(void **state) { + assert_int_equal(pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0x0f0, NULL), 0x000); + assert_int_equal(pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0xfff, NULL), 0x000); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(clear_none), + cmocka_unit_test(clear_some), + cmocka_unit_test(clear_all)) diff --git a/lib/common/tests/flags/pcmk__set_flags_as_test.c b/lib/common/tests/flags/pcmk__set_flags_as_test.c new file mode 100644 index 0000000..cd14c85 --- /dev/null +++ b/lib/common/tests/flags/pcmk__set_flags_as_test.c @@ -0,0 +1,25 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +set_flags(void **state) { + assert_int_equal(pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0x00f, NULL), 0x0ff); + assert_int_equal(pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0xf0f, NULL), 0xfff); + assert_int_equal(pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, "Test", + "test", 0x0f0, 0xfff, NULL), 0xfff); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(set_flags)) diff --git a/lib/common/tests/flags/pcmk_all_flags_set_test.c b/lib/common/tests/flags/pcmk_all_flags_set_test.c new file mode 100644 index 0000000..512ccce --- /dev/null +++ b/lib/common/tests/flags/pcmk_all_flags_set_test.c @@ -0,0 +1,33 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +all_set(void **state) { + assert_false(pcmk_all_flags_set(0x000, 0x003)); + assert_true(pcmk_all_flags_set(0x00f, 0x003)); + assert_false(pcmk_all_flags_set(0x00f, 0x010)); + assert_false(pcmk_all_flags_set(0x00f, 0x011)); + assert_true(pcmk_all_flags_set(0x000, 0x000)); + assert_true(pcmk_all_flags_set(0x00f, 0x000)); +} + +static void +one_is_set(void **state) { + // pcmk_is_set() is a simple macro alias for pcmk_all_flags_set() + assert_true(pcmk_is_set(0x00f, 0x001)); + assert_false(pcmk_is_set(0x00f, 0x010)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(all_set), + cmocka_unit_test(one_is_set)) diff --git a/lib/common/tests/flags/pcmk_any_flags_set_test.c b/lib/common/tests/flags/pcmk_any_flags_set_test.c new file mode 100644 index 0000000..dc3aabc --- /dev/null +++ b/lib/common/tests/flags/pcmk_any_flags_set_test.c @@ -0,0 +1,26 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +any_set(void **state) { + assert_false(pcmk_any_flags_set(0x000, 0x000)); + assert_false(pcmk_any_flags_set(0x000, 0x001)); + assert_true(pcmk_any_flags_set(0x00f, 0x001)); + assert_false(pcmk_any_flags_set(0x00f, 0x010)); + assert_true(pcmk_any_flags_set(0x00f, 0x011)); + assert_false(pcmk_any_flags_set(0x000, 0x000)); + assert_false(pcmk_any_flags_set(0x00f, 0x000)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(any_set)) diff --git a/lib/common/tests/health/Makefile.am b/lib/common/tests/health/Makefile.am new file mode 100644 index 0000000..ad2a2da --- /dev/null +++ b/lib/common/tests/health/Makefile.am @@ -0,0 +1,17 @@ +# +# Copyright 2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__parse_health_strategy_test \ + pcmk__validate_health_strategy_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/health/pcmk__parse_health_strategy_test.c b/lib/common/tests/health/pcmk__parse_health_strategy_test.c new file mode 100644 index 0000000..28cc702 --- /dev/null +++ b/lib/common/tests/health/pcmk__parse_health_strategy_test.c @@ -0,0 +1,56 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +valid(void **state) { + assert_int_equal(pcmk__parse_health_strategy(NULL), + pcmk__health_strategy_none); + + assert_int_equal(pcmk__parse_health_strategy("none"), + pcmk__health_strategy_none); + + assert_int_equal(pcmk__parse_health_strategy("NONE"), + pcmk__health_strategy_none); + + assert_int_equal(pcmk__parse_health_strategy("None"), + pcmk__health_strategy_none); + + assert_int_equal(pcmk__parse_health_strategy("nOnE"), + pcmk__health_strategy_none); + + assert_int_equal(pcmk__parse_health_strategy("migrate-on-red"), + pcmk__health_strategy_no_red); + + assert_int_equal(pcmk__parse_health_strategy("only-green"), + pcmk__health_strategy_only_green); + + assert_int_equal(pcmk__parse_health_strategy("progressive"), + pcmk__health_strategy_progressive); + + assert_int_equal(pcmk__parse_health_strategy("custom"), + pcmk__health_strategy_custom); +} + +static void +invalid(void **state) { + assert_int_equal(pcmk__parse_health_strategy("foo"), + pcmk__health_strategy_none); + assert_int_equal(pcmk__parse_health_strategy("custom1"), + pcmk__health_strategy_none); + assert_int_equal(pcmk__parse_health_strategy("not-only-green-here"), + pcmk__health_strategy_none); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(valid), + cmocka_unit_test(invalid)) diff --git a/lib/common/tests/health/pcmk__validate_health_strategy_test.c b/lib/common/tests/health/pcmk__validate_health_strategy_test.c new file mode 100644 index 0000000..c7c60aa --- /dev/null +++ b/lib/common/tests/health/pcmk__validate_health_strategy_test.c @@ -0,0 +1,38 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +// Test functions + +static void +valid_strategy(void **state) { + assert_true(pcmk__validate_health_strategy("none")); + assert_true(pcmk__validate_health_strategy("None")); + assert_true(pcmk__validate_health_strategy("NONE")); + assert_true(pcmk__validate_health_strategy("NoNe")); + assert_true(pcmk__validate_health_strategy("migrate-on-red")); + assert_true(pcmk__validate_health_strategy("only-green")); + assert_true(pcmk__validate_health_strategy("progressive")); + assert_true(pcmk__validate_health_strategy("custom")); +} + +static void +invalid_strategy(void **state) { + assert_false(pcmk__validate_health_strategy(NULL)); + assert_false(pcmk__validate_health_strategy("")); + assert_false(pcmk__validate_health_strategy("none to speak of")); + assert_false(pcmk__validate_health_strategy("customized")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(valid_strategy), + cmocka_unit_test(invalid_strategy)) diff --git a/lib/common/tests/io/Makefile.am b/lib/common/tests/io/Makefile.am new file mode 100644 index 0000000..c26482c --- /dev/null +++ b/lib/common/tests/io/Makefile.am @@ -0,0 +1,18 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + pcmk__full_path_test \ + pcmk__get_tmpdir_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/io/pcmk__full_path_test.c b/lib/common/tests/io/pcmk__full_path_test.c new file mode 100644 index 0000000..dbbd71b --- /dev/null +++ b/lib/common/tests/io/pcmk__full_path_test.c @@ -0,0 +1,52 @@ +/* + * Copyright 2020-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +static void +function_asserts(void **state) +{ + pcmk__assert_asserts(pcmk__full_path(NULL, "/dir")); + pcmk__assert_asserts(pcmk__full_path("file", NULL)); + + pcmk__assert_asserts( + { + pcmk__mock_strdup = true; // strdup() will return NULL + expect_string(__wrap_strdup, s, "/full/path"); + pcmk__full_path("/full/path", "/dir"); + pcmk__mock_strdup = false; // Use real strdup() + } + ); +} + +static void +full_path(void **state) +{ + char *path = NULL; + + path = pcmk__full_path("file", "/dir"); + assert_int_equal(strcmp(path, "/dir/file"), 0); + free(path); + + path = pcmk__full_path("/full/path", "/dir"); + assert_int_equal(strcmp(path, "/full/path"), 0); + free(path); + + path = pcmk__full_path("../relative/path", "/dir"); + assert_int_equal(strcmp(path, "/dir/../relative/path"), 0); + free(path); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(function_asserts), + cmocka_unit_test(full_path)) diff --git a/lib/common/tests/io/pcmk__get_tmpdir_test.c b/lib/common/tests/io/pcmk__get_tmpdir_test.c new file mode 100644 index 0000000..bc17513 --- /dev/null +++ b/lib/common/tests/io/pcmk__get_tmpdir_test.c @@ -0,0 +1,68 @@ +/* + * Copyright 2021-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +static void +getenv_returns_invalid(void **state) +{ + const char *result; + + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "TMPDIR"); + will_return(__wrap_getenv, NULL); // getenv("TMPDIR") return value + result = pcmk__get_tmpdir(); + assert_string_equal(result, "/tmp"); + + expect_string(__wrap_getenv, name, "TMPDIR"); + will_return(__wrap_getenv, ""); // getenv("TMPDIR") return value + result = pcmk__get_tmpdir(); + assert_string_equal(result, "/tmp"); + + expect_string(__wrap_getenv, name, "TMPDIR"); + will_return(__wrap_getenv, "subpath"); // getenv("TMPDIR") return value + result = pcmk__get_tmpdir(); + assert_string_equal(result, "/tmp"); + + pcmk__mock_getenv = false; +} + +static void +getenv_returns_valid(void **state) +{ + const char *result; + + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "TMPDIR"); + will_return(__wrap_getenv, "/var/tmp"); // getenv("TMPDIR") return value + result = pcmk__get_tmpdir(); + assert_string_equal(result, "/var/tmp"); + + expect_string(__wrap_getenv, name, "TMPDIR"); + will_return(__wrap_getenv, "/"); // getenv("TMPDIR") return value + result = pcmk__get_tmpdir(); + assert_string_equal(result, "/"); + + expect_string(__wrap_getenv, name, "TMPDIR"); + will_return(__wrap_getenv, "/tmp/abcd.1234"); // getenv("TMPDIR") return value + result = pcmk__get_tmpdir(); + assert_string_equal(result, "/tmp/abcd.1234"); + + pcmk__mock_getenv = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(getenv_returns_invalid), + cmocka_unit_test(getenv_returns_valid)) diff --git a/lib/common/tests/iso8601/Makefile.am b/lib/common/tests/iso8601/Makefile.am new file mode 100644 index 0000000..5187aec --- /dev/null +++ b/lib/common/tests/iso8601/Makefile.am @@ -0,0 +1,16 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__readable_interval_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/iso8601/pcmk__readable_interval_test.c b/lib/common/tests/iso8601/pcmk__readable_interval_test.c new file mode 100644 index 0000000..43b5541 --- /dev/null +++ b/lib/common/tests/iso8601/pcmk__readable_interval_test.c @@ -0,0 +1,27 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <limits.h> + +static void +readable_interval(void **state) +{ + assert_string_equal(pcmk__readable_interval(0), "0s"); + assert_string_equal(pcmk__readable_interval(30000), "30s"); + assert_string_equal(pcmk__readable_interval(150000), "2m30s"); + assert_string_equal(pcmk__readable_interval(3333), "3.333s"); + assert_string_equal(pcmk__readable_interval(UINT_MAX), "49d17h2m47.295s"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(readable_interval)) diff --git a/lib/common/tests/lists/Makefile.am b/lib/common/tests/lists/Makefile.am new file mode 100644 index 0000000..ae0c0b6 --- /dev/null +++ b/lib/common/tests/lists/Makefile.am @@ -0,0 +1,20 @@ +# +# Copyright 2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. + +check_PROGRAMS = \ + pcmk__list_of_1_test \ + pcmk__list_of_multiple_test \ + pcmk__subtract_lists_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/lists/pcmk__list_of_1_test.c b/lib/common/tests/lists/pcmk__list_of_1_test.c new file mode 100644 index 0000000..a3e0bbc --- /dev/null +++ b/lib/common/tests/lists/pcmk__list_of_1_test.c @@ -0,0 +1,45 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +empty_list(void **state) { + assert_false(pcmk__list_of_1(NULL)); +} + +static void +singleton_list(void **state) { + GList *lst = NULL; + + lst = g_list_append(lst, strdup("abc")); + assert_true(pcmk__list_of_1(lst)); + + g_list_free_full(lst, free); +} + +static void +longer_list(void **state) { + GList *lst = NULL; + + lst = g_list_append(lst, strdup("abc")); + lst = g_list_append(lst, strdup("xyz")); + assert_false(pcmk__list_of_1(lst)); + + g_list_free_full(lst, free); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_list), + cmocka_unit_test(singleton_list), + cmocka_unit_test(longer_list)) diff --git a/lib/common/tests/lists/pcmk__list_of_multiple_test.c b/lib/common/tests/lists/pcmk__list_of_multiple_test.c new file mode 100644 index 0000000..0966037 --- /dev/null +++ b/lib/common/tests/lists/pcmk__list_of_multiple_test.c @@ -0,0 +1,45 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +empty_list(void **state) { + assert_false(pcmk__list_of_multiple(NULL)); +} + +static void +singleton_list(void **state) { + GList *lst = NULL; + + lst = g_list_append(lst, strdup("abc")); + assert_false(pcmk__list_of_multiple(lst)); + + g_list_free_full(lst, free); +} + +static void +longer_list(void **state) { + GList *lst = NULL; + + lst = g_list_append(lst, strdup("abc")); + lst = g_list_append(lst, strdup("xyz")); + assert_true(pcmk__list_of_multiple(lst)); + + g_list_free_full(lst, free); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_list), + cmocka_unit_test(singleton_list), + cmocka_unit_test(longer_list)) diff --git a/lib/common/tests/lists/pcmk__subtract_lists_test.c b/lib/common/tests/lists/pcmk__subtract_lists_test.c new file mode 100644 index 0000000..1198e2b --- /dev/null +++ b/lib/common/tests/lists/pcmk__subtract_lists_test.c @@ -0,0 +1,144 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/lists_internal.h> + +#include <glib.h> + +static void +different_lists(void **state) +{ + GList *from = NULL; + GList *items = NULL; + GList *result = NULL; + + from = g_list_append(from, strdup("abc")); + from = g_list_append(from, strdup("def")); + from = g_list_append(from, strdup("ghi")); + + items = g_list_append(items, strdup("123")); + items = g_list_append(items, strdup("456")); + + result = pcmk__subtract_lists(from, items, (GCompareFunc) strcmp); + + assert_int_equal(g_list_length(result), 3); + assert_string_equal(g_list_nth_data(result, 0), "abc"); + assert_string_equal(g_list_nth_data(result, 1), "def"); + assert_string_equal(g_list_nth_data(result, 2), "ghi"); + + g_list_free(result); + g_list_free_full(from, free); + g_list_free_full(items, free); +} + +static void +remove_first_item(void **state) +{ + GList *from = NULL; + GList *items = NULL; + GList *result = NULL; + + from = g_list_append(from, strdup("abc")); + from = g_list_append(from, strdup("def")); + from = g_list_append(from, strdup("ghi")); + + items = g_list_append(items, strdup("abc")); + + result = pcmk__subtract_lists(from, items, (GCompareFunc) strcmp); + + assert_int_equal(g_list_length(result), 2); + assert_string_equal(g_list_nth_data(result, 0), "def"); + assert_string_equal(g_list_nth_data(result, 1), "ghi"); + + g_list_free(result); + g_list_free_full(from, free); + g_list_free_full(items, free); +} + +static void +remove_middle_item(void **state) +{ + GList *from = NULL; + GList *items = NULL; + GList *result = NULL; + + from = g_list_append(from, strdup("abc")); + from = g_list_append(from, strdup("def")); + from = g_list_append(from, strdup("ghi")); + + items = g_list_append(items, strdup("def")); + + result = pcmk__subtract_lists(from, items, (GCompareFunc) strcmp); + + assert_int_equal(g_list_length(result), 2); + assert_string_equal(g_list_nth_data(result, 0), "abc"); + assert_string_equal(g_list_nth_data(result, 1), "ghi"); + + g_list_free(result); + g_list_free_full(from, free); + g_list_free_full(items, free); +} + +static void +remove_last_item(void **state) +{ + GList *from = NULL; + GList *items = NULL; + GList *result = NULL; + + from = g_list_append(from, strdup("abc")); + from = g_list_append(from, strdup("def")); + from = g_list_append(from, strdup("ghi")); + + items = g_list_append(items, strdup("ghi")); + + result = pcmk__subtract_lists(from, items, (GCompareFunc) strcmp); + + assert_int_equal(g_list_length(result), 2); + assert_string_equal(g_list_nth_data(result, 0), "abc"); + assert_string_equal(g_list_nth_data(result, 1), "def"); + + g_list_free(result); + g_list_free_full(from, free); + g_list_free_full(items, free); +} + +static void +remove_all_items(void **state) +{ + GList *from = NULL; + GList *items = NULL; + GList *result = NULL; + + from = g_list_append(from, strdup("abc")); + from = g_list_append(from, strdup("def")); + from = g_list_append(from, strdup("ghi")); + + items = g_list_append(items, strdup("abc")); + items = g_list_append(items, strdup("def")); + items = g_list_append(items, strdup("ghi")); + + result = pcmk__subtract_lists(from, items, (GCompareFunc) strcmp); + + assert_int_equal(g_list_length(result), 0); + + g_list_free(result); + g_list_free_full(from, free); + g_list_free_full(items, free); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(different_lists), + cmocka_unit_test(remove_first_item), + cmocka_unit_test(remove_middle_item), + cmocka_unit_test(remove_last_item), + cmocka_unit_test(remove_all_items)) diff --git a/lib/common/tests/nvpair/Makefile.am b/lib/common/tests/nvpair/Makefile.am new file mode 100644 index 0000000..7acaba3 --- /dev/null +++ b/lib/common/tests/nvpair/Makefile.am @@ -0,0 +1,18 @@ +# +# Copyright 2021-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__xe_attr_is_true_test \ + pcmk__xe_get_bool_attr_test \ + pcmk__xe_set_bool_attr_test + +TESTS = $(check_PROGRAMS) 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 new file mode 100644 index 0000000..3723707 --- /dev/null +++ b/lib/common/tests/nvpair/pcmk__xe_attr_is_true_test.c @@ -0,0 +1,50 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/xml_internal.h> + +static void +empty_input(void **state) +{ + xmlNode *node = string2xml("<node/>"); + + assert_false(pcmk__xe_attr_is_true(NULL, NULL)); + assert_false(pcmk__xe_attr_is_true(NULL, "whatever")); + assert_false(pcmk__xe_attr_is_true(node, NULL)); + + free_xml(node); +} + +static void +attr_missing(void **state) +{ + xmlNode *node = string2xml("<node a=\"true\" b=\"false\"/>"); + + assert_false(pcmk__xe_attr_is_true(node, "c")); + free_xml(node); +} + +static void +attr_present(void **state) +{ + xmlNode *node = string2xml("<node a=\"true\" b=\"false\"/>"); + + assert_true(pcmk__xe_attr_is_true(node, "a")); + assert_false(pcmk__xe_attr_is_true(node, "b")); + + free_xml(node); +} + +PCMK__UNIT_TEST(NULL, NULL, + 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 new file mode 100644 index 0000000..500d8a6 --- /dev/null +++ b/lib/common/tests/nvpair/pcmk__xe_get_bool_attr_test.c @@ -0,0 +1,59 @@ +/* + * Copyright 2021-2023 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/xml_internal.h> + +static void +empty_input(void **state) +{ + xmlNode *node = string2xml("<node/>"); + bool value; + + assert_int_equal(pcmk__xe_get_bool_attr(NULL, NULL, &value), ENODATA); + assert_int_equal(pcmk__xe_get_bool_attr(NULL, "whatever", &value), ENODATA); + assert_int_equal(pcmk__xe_get_bool_attr(node, NULL, &value), EINVAL); + assert_int_equal(pcmk__xe_get_bool_attr(node, "whatever", NULL), EINVAL); + + free_xml(node); +} + +static void +attr_missing(void **state) +{ + xmlNode *node = string2xml("<node a=\"true\" b=\"false\"/>"); + bool value; + + assert_int_equal(pcmk__xe_get_bool_attr(node, "c", &value), ENODATA); + free_xml(node); +} + +static void +attr_present(void **state) +{ + xmlNode *node = string2xml("<node a=\"true\" b=\"false\" c=\"blah\"/>"); + bool value; + + value = false; + assert_int_equal(pcmk__xe_get_bool_attr(node, "a", &value), pcmk_rc_ok); + assert_true(value); + value = true; + assert_int_equal(pcmk__xe_get_bool_attr(node, "b", &value), pcmk_rc_ok); + assert_false(value); + assert_int_equal(pcmk__xe_get_bool_attr(node, "c", &value), pcmk_rc_bad_input); + + free_xml(node); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input), + cmocka_unit_test(attr_missing), + cmocka_unit_test(attr_present)) 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 new file mode 100644 index 0000000..e1fb9c4 --- /dev/null +++ b/lib/common/tests/nvpair/pcmk__xe_set_bool_attr_test.c @@ -0,0 +1,31 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/xml_internal.h> +#include <crm/msg_xml.h> + +static void +set_attr(void **state) +{ + xmlNode *node = string2xml("<node/>"); + + pcmk__xe_set_bool_attr(node, "a", true); + pcmk__xe_set_bool_attr(node, "b", false); + + assert_string_equal(crm_element_value(node, "a"), XML_BOOLEAN_TRUE); + assert_string_equal(crm_element_value(node, "b"), XML_BOOLEAN_FALSE); + + free_xml(node); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(set_attr)) diff --git a/lib/common/tests/operations/Makefile.am b/lib/common/tests/operations/Makefile.am new file mode 100644 index 0000000..4687e1b --- /dev/null +++ b/lib/common/tests/operations/Makefile.am @@ -0,0 +1,22 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = copy_in_properties_test \ + expand_plus_plus_test \ + fix_plus_plus_recursive_test \ + parse_op_key_test \ + pcmk_is_probe_test \ + pcmk_xe_is_probe_test \ + pcmk_xe_mask_probe_failure_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/operations/copy_in_properties_test.c b/lib/common/tests/operations/copy_in_properties_test.c new file mode 100644 index 0000000..7882551 --- /dev/null +++ b/lib/common/tests/operations/copy_in_properties_test.c @@ -0,0 +1,62 @@ + /* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +target_is_NULL(void **state) +{ + xmlNode *test_xml_1 = create_xml_node(NULL, "test_xml_1"); + xmlNode *test_xml_2 = NULL; + + pcmk__xe_set_props(test_xml_1, "test_prop", "test_value", NULL); + + copy_in_properties(test_xml_2, test_xml_1); + + assert_ptr_equal(test_xml_2, NULL); +} + +static void +src_is_NULL(void **state) +{ + xmlNode *test_xml_1 = NULL; + xmlNode *test_xml_2 = create_xml_node(NULL, "test_xml_2"); + + copy_in_properties(test_xml_2, test_xml_1); + + assert_ptr_equal(test_xml_2->properties, NULL); +} + +static void +copying_is_successful(void **state) +{ + const char *xml_1_value; + const char *xml_2_value; + + xmlNode *test_xml_1 = create_xml_node(NULL, "test_xml_1"); + xmlNode *test_xml_2 = create_xml_node(NULL, "test_xml_2"); + + pcmk__xe_set_props(test_xml_1, "test_prop", "test_value", NULL); + + copy_in_properties(test_xml_2, test_xml_1); + + xml_1_value = crm_element_value(test_xml_1, "test_prop"); + xml_2_value = crm_element_value(test_xml_2, "test_prop"); + + assert_string_equal(xml_1_value, xml_2_value); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(target_is_NULL), + cmocka_unit_test(src_is_NULL), + cmocka_unit_test(copying_is_successful)) diff --git a/lib/common/tests/operations/expand_plus_plus_test.c b/lib/common/tests/operations/expand_plus_plus_test.c new file mode 100644 index 0000000..41471f9 --- /dev/null +++ b/lib/common/tests/operations/expand_plus_plus_test.c @@ -0,0 +1,256 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +value_is_name_plus_plus(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "6"); +} + +static void +value_is_name_plus_equals_integer(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X+=2"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "7"); +} + +// NULL input + +static void +target_is_NULL(void **state) +{ + + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(NULL, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "5"); +} + +static void +name_is_NULL(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, NULL, "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "5"); +} + +static void +value_is_NULL(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", NULL); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "5"); +} + +// the value input doesn't start with the name input + +static void +value_is_wrong_name(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "Y++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "Y++"); +} + +static void +value_is_only_an_integer(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "2"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "2"); +} + +// non-integers + +static void +variable_is_initialized_to_be_NULL(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", NULL); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "X++"); +} + +static void +variable_is_initialized_to_be_non_numeric(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "hello"); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "1"); +} + +static void +variable_is_initialized_to_be_non_numeric_2(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "hello"); + expand_plus_plus(test_xml, "X", "X+=2"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "2"); +} + +static void +variable_is_initialized_to_be_numeric_and_decimal_point_containing(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5.01"); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "6"); +} + +static void +variable_is_initialized_to_be_numeric_and_decimal_point_containing_2(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5.50"); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "6"); +} + +static void +variable_is_initialized_to_be_numeric_and_decimal_point_containing_3(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5.99"); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "6"); +} + +static void +value_is_non_numeric(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X+=hello"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "5"); +} + +static void +value_is_numeric_and_decimal_point_containing(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X+=2.01"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "7"); +} + +static void +value_is_numeric_and_decimal_point_containing_2(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X+=1.50"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "6"); +} + +static void +value_is_numeric_and_decimal_point_containing_3(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X+=1.99"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "6"); +} + +// undefined input + +static void +name_is_undefined(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "Y", "5"); + expand_plus_plus(test_xml, "X", "X++"); + new_value = crm_element_value(test_xml, "X"); + assert_string_equal(new_value, "X++"); +} + +// large input + +static void +assignment_result_is_too_large(void **state) +{ + const char *new_value; + xmlNode *test_xml = create_xml_node(NULL, "test_xml"); + crm_xml_add(test_xml, "X", "5"); + expand_plus_plus(test_xml, "X", "X+=100000000000"); + new_value = crm_element_value(test_xml, "X"); + printf("assignment result is too large %s\n", new_value); + assert_string_equal(new_value, "1000000"); +} + +PCMK__UNIT_TEST(NULL, NULL, + 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_NULL), + 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/operations/fix_plus_plus_recursive_test.c b/lib/common/tests/operations/fix_plus_plus_recursive_test.c new file mode 100644 index 0000000..b3c7cc2 --- /dev/null +++ b/lib/common/tests/operations/fix_plus_plus_recursive_test.c @@ -0,0 +1,47 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +element_nodes(void **state) +{ + const char *new_value_root; + const char *new_value_child; + const char *new_value_grandchild; + + xmlNode *test_xml_root = create_xml_node(NULL, "test_xml_root"); + xmlNode *test_xml_child = create_xml_node(test_xml_root, "test_xml_child"); + xmlNode *test_xml_grandchild = create_xml_node(test_xml_child, "test_xml_grandchild"); + xmlNode *test_xml_text = pcmk_create_xml_text_node(test_xml_root, "text_xml_text", "content"); + xmlNode *test_xml_comment = string2xml("<!-- a comment -->"); + + crm_xml_add(test_xml_root, "X", "5"); + crm_xml_add(test_xml_child, "X", "X++"); + crm_xml_add(test_xml_grandchild, "X", "X+=2"); + crm_xml_add(test_xml_text, "X", "X++"); + + fix_plus_plus_recursive(test_xml_root); + fix_plus_plus_recursive(test_xml_comment); + + new_value_root = crm_element_value(test_xml_root, "X"); + new_value_child = crm_element_value(test_xml_child, "X"); + new_value_grandchild = crm_element_value(test_xml_grandchild, "X"); + + assert_string_equal(new_value_root, "5"); + assert_string_equal(new_value_child, "1"); + assert_string_equal(new_value_grandchild, "2"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(element_nodes)) diff --git a/lib/common/tests/operations/parse_op_key_test.c b/lib/common/tests/operations/parse_op_key_test.c new file mode 100644 index 0000000..1b1bfff --- /dev/null +++ b/lib/common/tests/operations/parse_op_key_test.c @@ -0,0 +1,275 @@ +/* + * Copyright 2020-2023 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +basic(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("Fencing_monitor_60000", &rsc, &ty, &ms)); + assert_string_equal(rsc, "Fencing"); + assert_string_equal(ty, "monitor"); + assert_int_equal(ms, 60000); + free(rsc); + free(ty); + + // Single-character resource name + assert_true(parse_op_key("R_monitor_100000", &rsc, &ty, &ms)); + assert_string_equal(rsc, "R"); + assert_string_equal(ty, "monitor"); + assert_int_equal(ms, 100000); + free(rsc); + free(ty); + + // Single-character action name + assert_true(parse_op_key("R_A_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "R"); + assert_string_equal(ty, "A"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); +} + +static void +rsc_just_underbars(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("__monitor_1000", &rsc, &ty, &ms)); + assert_string_equal(rsc, "_"); + assert_string_equal(ty, "monitor"); + assert_int_equal(ms, 1000); + free(rsc); + free(ty); + + assert_true(parse_op_key("___migrate_from_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "__"); + assert_string_equal(ty, "migrate_from"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("____pre_notify_stop_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "___"); + assert_string_equal(ty, "pre_notify_stop"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); +} + +static void +colon_in_rsc(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("ClusterIP:0_start_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "ClusterIP:0"); + assert_string_equal(ty, "start"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("imagestoreclone:1_post_notify_stop_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "imagestoreclone:1"); + assert_string_equal(ty, "post_notify_stop"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); +} + +static void +dashes_in_rsc(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("httpd-bundle-0_monitor_30000", &rsc, &ty, &ms)); + assert_string_equal(rsc, "httpd-bundle-0"); + assert_string_equal(ty, "monitor"); + assert_int_equal(ms, 30000); + free(rsc); + free(ty); + + assert_true(parse_op_key("httpd-bundle-ip-192.168.122.132_start_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "httpd-bundle-ip-192.168.122.132"); + assert_string_equal(ty, "start"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); +} + +static void +migrate_to_from(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("vm_migrate_from_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "vm"); + assert_string_equal(ty, "migrate_from"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("vm_migrate_to_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "vm"); + assert_string_equal(ty, "migrate_to"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("vm_idcc_devel_migrate_to_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "vm_idcc_devel"); + assert_string_equal(ty, "migrate_to"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); +} + +static void +pre_post(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("rsc_drbd_7788:1_post_notify_start_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "rsc_drbd_7788:1"); + assert_string_equal(ty, "post_notify_start"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("rabbitmq-bundle-clone_pre_notify_stop_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "rabbitmq-bundle-clone"); + assert_string_equal(ty, "pre_notify_stop"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("post_notify_start_0", &rsc, &ty, &ms)); + assert_string_equal(rsc, "post_notify"); + assert_string_equal(ty, "start"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); + + assert_true(parse_op_key("r_confirmed-post_notify_start_0", + &rsc, &ty, &ms)); + assert_string_equal(rsc, "r"); + assert_string_equal(ty, "confirmed-post_notify_start"); + assert_int_equal(ms, 0); + free(rsc); + free(ty); +} + +static void +skip_rsc(void **state) +{ + char *ty = NULL; + guint ms = 0; + + assert_true(parse_op_key("Fencing_monitor_60000", NULL, &ty, &ms)); + assert_string_equal(ty, "monitor"); + assert_int_equal(ms, 60000); + free(ty); +} + +static void +skip_ty(void **state) +{ + char *rsc = NULL; + guint ms = 0; + + assert_true(parse_op_key("Fencing_monitor_60000", &rsc, NULL, &ms)); + assert_string_equal(rsc, "Fencing"); + assert_int_equal(ms, 60000); + free(rsc); +} + +static void +skip_ms(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + + assert_true(parse_op_key("Fencing_monitor_60000", &rsc, &ty, NULL)); + assert_string_equal(rsc, "Fencing"); + assert_string_equal(ty, "monitor"); + free(rsc); + free(ty); +} + +static void +empty_input(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_false(parse_op_key("", &rsc, &ty, &ms)); + assert_null(rsc); + assert_null(ty); + assert_int_equal(ms, 0); + + assert_false(parse_op_key(NULL, &rsc, &ty, &ms)); + assert_null(rsc); + assert_null(ty); + assert_int_equal(ms, 0); +} + +static void +malformed_input(void **state) +{ + char *rsc = NULL; + char *ty = NULL; + guint ms = 0; + + assert_false(parse_op_key("httpd-bundle-0", &rsc, &ty, &ms)); + assert_null(rsc); + assert_null(ty); + assert_int_equal(ms, 0); + + assert_false(parse_op_key("httpd-bundle-0_monitor", &rsc, &ty, &ms)); + assert_null(rsc); + assert_null(ty); + assert_int_equal(ms, 0); + + assert_false(parse_op_key("httpd-bundle-0_30000", &rsc, &ty, &ms)); + assert_null(rsc); + assert_null(ty); + assert_int_equal(ms, 0); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(basic), + cmocka_unit_test(rsc_just_underbars), + cmocka_unit_test(colon_in_rsc), + cmocka_unit_test(dashes_in_rsc), + cmocka_unit_test(migrate_to_from), + cmocka_unit_test(pre_post), + cmocka_unit_test(skip_rsc), + cmocka_unit_test(skip_ty), + cmocka_unit_test(skip_ms), + cmocka_unit_test(empty_input), + cmocka_unit_test(malformed_input)) diff --git a/lib/common/tests/operations/pcmk_is_probe_test.c b/lib/common/tests/operations/pcmk_is_probe_test.c new file mode 100644 index 0000000..4a65e3f --- /dev/null +++ b/lib/common/tests/operations/pcmk_is_probe_test.c @@ -0,0 +1,25 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +is_probe_test(void **state) +{ + assert_false(pcmk_is_probe(NULL, 0)); + assert_false(pcmk_is_probe("", 0)); + assert_false(pcmk_is_probe("blahblah", 0)); + assert_false(pcmk_is_probe("monitor", 1)); + assert_true(pcmk_is_probe("monitor", 0)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(is_probe_test)) diff --git a/lib/common/tests/operations/pcmk_xe_is_probe_test.c b/lib/common/tests/operations/pcmk_xe_is_probe_test.c new file mode 100644 index 0000000..62b21d9 --- /dev/null +++ b/lib/common/tests/operations/pcmk_xe_is_probe_test.c @@ -0,0 +1,43 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +op_is_probe_test(void **state) +{ + xmlNode *node = NULL; + + assert_false(pcmk_xe_is_probe(NULL)); + + node = string2xml("<lrm_rsc_op/>"); + assert_false(pcmk_xe_is_probe(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation_key=\"blah\" interval=\"30s\"/>"); + assert_false(pcmk_xe_is_probe(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"30s\"/>"); + assert_false(pcmk_xe_is_probe(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"start\" interval=\"0\"/>"); + assert_false(pcmk_xe_is_probe(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\"/>"); + assert_true(pcmk_xe_is_probe(node)); + free_xml(node); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(op_is_probe_test)) diff --git a/lib/common/tests/operations/pcmk_xe_mask_probe_failure_test.c b/lib/common/tests/operations/pcmk_xe_mask_probe_failure_test.c new file mode 100644 index 0000000..9e38019 --- /dev/null +++ b/lib/common/tests/operations/pcmk_xe_mask_probe_failure_test.c @@ -0,0 +1,150 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +op_is_not_probe_test(void **state) { + xmlNode *node = NULL; + + /* Not worth testing this thoroughly since it's just a duplicate of whether + * pcmk_op_is_probe works or not. + */ + + node = string2xml("<lrm_rsc_op operation=\"start\" 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; + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); +} + +static void +check_values_test(void **state) { + xmlNode *node = NULL; + + /* PCMK_EXEC_NOT_SUPPORTED */ + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"3\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"5\" op-status=\"3\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + /* PCMK_EXEC_DONE */ + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"0\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"2\" op-status=\"0\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"5\" op-status=\"0\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"6\" op-status=\"0\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"7\" op-status=\"0\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + /* PCMK_EXEC_NOT_INSTALLED */ + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"7\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"5\" op-status=\"7\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + /* PCMK_EXEC_ERROR */ + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"4\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"2\" op-status=\"4\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"5\" op-status=\"4\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"6\" op-status=\"4\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"7\" op-status=\"4\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + /* PCMK_EXEC_ERROR_HARD */ + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"5\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"2\" op-status=\"5\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"5\" op-status=\"5\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"6\" op-status=\"5\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"7\" op-status=\"5\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + /* PCMK_EXEC_ERROR_FATAL */ + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"0\" op-status=\"6\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"2\" op-status=\"6\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"5\" op-status=\"6\"/>"); + assert_true(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"6\" op-status=\"6\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); + + node = string2xml("<lrm_rsc_op operation=\"monitor\" interval=\"0\" rc-code=\"7\" op-status=\"6\"/>"); + assert_false(pcmk_xe_mask_probe_failure(node)); + free_xml(node); +} + +PCMK__UNIT_TEST(NULL, NULL, + 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/options/Makefile.am b/lib/common/tests/options/Makefile.am new file mode 100644 index 0000000..9a5fa98 --- /dev/null +++ b/lib/common/tests/options/Makefile.am @@ -0,0 +1,19 @@ +# +# Copyright 2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + pcmk__env_option_test \ + pcmk__set_env_option_test \ + pcmk__env_option_enabled_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/options/pcmk__env_option_enabled_test.c b/lib/common/tests/options/pcmk__env_option_enabled_test.c new file mode 100644 index 0000000..b7d5d25 --- /dev/null +++ b/lib/common/tests/options/pcmk__env_option_enabled_test.c @@ -0,0 +1,101 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +static void +disabled_null_value(void **state) +{ + // Return false if option value not found (NULL accomplishes this) + assert_false(pcmk__env_option_enabled(NULL, NULL)); + assert_false(pcmk__env_option_enabled("pacemaker-execd", NULL)); +} + +static void +enabled_true_value(void **state) +{ + // Return true if option value is true, with or without daemon name + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "true"); + assert_true(pcmk__env_option_enabled(NULL, "env_var")); + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "true"); + assert_true(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + pcmk__mock_getenv = false; +} + +static void +disabled_false_value(void **state) +{ + // Return false if option value is false (no daemon list) + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "false"); + assert_false(pcmk__env_option_enabled(NULL, "env_var")); + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "false"); + assert_false(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + pcmk__mock_getenv = false; +} + +static void +enabled_daemon_in_list(void **state) +{ + // Return true if daemon is in the option's value + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "pacemaker-execd"); + assert_true(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "pacemaker-execd,pacemaker-fenced"); + assert_true(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "pacemaker-controld,pacemaker-execd"); + assert_true(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, + "pacemaker-controld,pacemaker-execd,pacemaker-fenced"); + assert_true(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + pcmk__mock_getenv = false; +} + +static void +disabled_daemon_not_in_list(void **state) +{ + // Return false if value is not true and daemon is not in the option's value + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "pacemaker-controld,pacemaker-fenced"); + assert_false(pcmk__env_option_enabled("pacemaker-execd", "env_var")); + + pcmk__mock_getenv = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(disabled_null_value), + cmocka_unit_test(enabled_true_value), + cmocka_unit_test(disabled_false_value), + cmocka_unit_test(enabled_daemon_in_list), + cmocka_unit_test(disabled_daemon_not_in_list)) diff --git a/lib/common/tests/options/pcmk__env_option_test.c b/lib/common/tests/options/pcmk__env_option_test.c new file mode 100644 index 0000000..2b85b68 --- /dev/null +++ b/lib/common/tests/options/pcmk__env_option_test.c @@ -0,0 +1,134 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +static void +empty_input_string(void **state) +{ + pcmk__mock_getenv = true; + + // getenv() not called + assert_null(pcmk__env_option(NULL)); + assert_null(pcmk__env_option("")); + + pcmk__mock_getenv = false; +} + +static void +input_too_long_for_both(void **state) +{ + /* pcmk__env_option() prepends "PCMK_" before lookup. If the option name is + * too long for the buffer or isn't found in the env, then it prepends "HA_" + * and tries again. A string of length (NAME_MAX - 3) will set us just over + * just over the edge for both tries. + */ + char long_opt[NAME_MAX - 2]; + + for (int i = 0; i < NAME_MAX - 3; i++) { + long_opt[i] = 'a'; + } + long_opt[NAME_MAX - 3] = '\0'; + + pcmk__mock_getenv = true; + + // getenv() not called + assert_null(pcmk__env_option(long_opt)); + + pcmk__mock_getenv = false; +} + +static void +input_too_long_for_pcmk(void **state) +{ + /* If an input is too long for "PCMK_<option>", make sure we fall through + * to try "HA_<option>". + * + * pcmk__env_option() prepends "PCMK_" first. A string of length + * (NAME_MAX - 5) will set us just over the edge, still short enough for + * "HA_<option>" to fit. + */ + char long_opt[NAME_MAX - 4]; + char buf[NAME_MAX]; + + for (int i = 0; i < NAME_MAX - 5; i++) { + long_opt[i] = 'a'; + } + long_opt[NAME_MAX - 5] = '\0'; + + pcmk__mock_getenv = true; + + /* NULL/non-NULL retval doesn't really matter here; just testing that we + * call getenv() for "HA_" prefix after too long for "PCMK_". + */ + snprintf(buf, NAME_MAX, "HA_%s", long_opt); + expect_string(__wrap_getenv, name, buf); + will_return(__wrap_getenv, "value"); + assert_string_equal(pcmk__env_option(long_opt), "value"); + + pcmk__mock_getenv = false; +} + +static void +value_not_found(void **state) +{ + // Value not found using PCMK_ or HA_ prefix. Should return NULL. + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, NULL); + + expect_string(__wrap_getenv, name, "HA_env_var"); + will_return(__wrap_getenv, NULL); + + assert_null(pcmk__env_option("env_var")); + + pcmk__mock_getenv = false; +} + +static void +value_found_pcmk(void **state) +{ + // Value found using PCMK_. Should return value and skip HA_ lookup. + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, "value"); + assert_string_equal(pcmk__env_option("env_var"), "value"); + + pcmk__mock_getenv = false; +} + +static void +value_found_ha(void **state) +{ + // Value not found using PCMK_. Move on to HA_ lookup, find, and return. + pcmk__mock_getenv = true; + + expect_string(__wrap_getenv, name, "PCMK_env_var"); + will_return(__wrap_getenv, NULL); + + expect_string(__wrap_getenv, name, "HA_env_var"); + will_return(__wrap_getenv, "value"); + + assert_string_equal(pcmk__env_option("env_var"), "value"); + + pcmk__mock_getenv = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_string), + cmocka_unit_test(input_too_long_for_both), + cmocka_unit_test(input_too_long_for_pcmk), + cmocka_unit_test(value_not_found), + cmocka_unit_test(value_found_pcmk), + cmocka_unit_test(value_found_ha)) diff --git a/lib/common/tests/options/pcmk__set_env_option_test.c b/lib/common/tests/options/pcmk__set_env_option_test.c new file mode 100644 index 0000000..753bf74 --- /dev/null +++ b/lib/common/tests/options/pcmk__set_env_option_test.c @@ -0,0 +1,154 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +static void +bad_input_string(void **state) +{ + // Bad setenv()/unsetenv() input: NULL, empty, or containing '=' + + // Never call setenv() + pcmk__mock_setenv = true; + + pcmk__set_env_option(NULL, "new_value"); + pcmk__set_env_option("", "new_value"); + pcmk__set_env_option("name=val", "new_value"); + + pcmk__mock_setenv = false; + + // Never call unsetenv() + pcmk__mock_unsetenv = true; + + pcmk__set_env_option(NULL, NULL); + pcmk__set_env_option("", NULL); + pcmk__set_env_option("name=val", NULL); + + pcmk__mock_unsetenv = false; +} + +static void +input_too_long_for_both(void **state) +{ + /* pcmk__set_env_option() wants to set "PCMK_<option>" and "HA_<option>". If + * "PCMK_<option>" is too long for the buffer, it simply moves on to + * "HA_<option>". A string of length (NAME_MAX - 3) will set us just over + * the edge for both tries. + */ + char long_opt[NAME_MAX - 2]; + + for (int i = 0; i < NAME_MAX - 3; i++) { + long_opt[i] = 'a'; + } + long_opt[NAME_MAX - 3] = '\0'; + + // Never call setenv() or unsetenv() + pcmk__mock_setenv = true; + pcmk__set_env_option(long_opt, "new_value"); + pcmk__mock_setenv = false; + + pcmk__mock_unsetenv = true; + pcmk__set_env_option(long_opt, NULL); + pcmk__mock_unsetenv = false; +} + +static void +input_too_long_for_pcmk(void **state) +{ + /* If an input is too long to set "PCMK_<option>", make sure we fall through + * to try to set "HA_<option>". + * + * A string of length (NAME_MAX - 5) will set us just over the edge for + * "PCMK_<option>", while still short enough for "HA_<option>" to fit. + */ + char long_opt[NAME_MAX - 4]; + char buf[NAME_MAX]; + + for (int i = 0; i < NAME_MAX - 5; i++) { + long_opt[i] = 'a'; + } + long_opt[NAME_MAX - 5] = '\0'; + + snprintf(buf, NAME_MAX, "HA_%s", long_opt); + + // Call setenv() for "HA_" only + pcmk__mock_setenv = true; + + expect_string(__wrap_setenv, name, buf); + expect_string(__wrap_setenv, value, "new_value"); + expect_value(__wrap_setenv, overwrite, 1); + will_return(__wrap_setenv, 0); + pcmk__set_env_option(long_opt, "new_value"); + + pcmk__mock_setenv = false; + + // Call unsetenv() for "HA_" only + pcmk__mock_unsetenv = true; + + expect_string(__wrap_unsetenv, name, buf); + will_return(__wrap_unsetenv, 0); + pcmk__set_env_option(long_opt, NULL); + + pcmk__mock_unsetenv = false; +} + +static void +valid_inputs_set(void **state) +{ + // Make sure we set "PCMK_<option>" and "HA_<option>" + pcmk__mock_setenv = true; + + expect_string(__wrap_setenv, name, "PCMK_env_var"); + expect_string(__wrap_setenv, value, "new_value"); + expect_value(__wrap_setenv, overwrite, 1); + will_return(__wrap_setenv, 0); + expect_string(__wrap_setenv, name, "HA_env_var"); + expect_string(__wrap_setenv, value, "new_value"); + expect_value(__wrap_setenv, overwrite, 1); + will_return(__wrap_setenv, 0); + pcmk__set_env_option("env_var", "new_value"); + + // Empty string is also a valid value + expect_string(__wrap_setenv, name, "PCMK_env_var"); + expect_string(__wrap_setenv, value, ""); + expect_value(__wrap_setenv, overwrite, 1); + will_return(__wrap_setenv, 0); + expect_string(__wrap_setenv, name, "HA_env_var"); + expect_string(__wrap_setenv, value, ""); + expect_value(__wrap_setenv, overwrite, 1); + will_return(__wrap_setenv, 0); + pcmk__set_env_option("env_var", ""); + + pcmk__mock_setenv = false; +} + +static void +valid_inputs_unset(void **state) +{ + // Make sure we unset "PCMK_<option>" and "HA_<option>" + pcmk__mock_unsetenv = true; + + expect_string(__wrap_unsetenv, name, "PCMK_env_var"); + will_return(__wrap_unsetenv, 0); + expect_string(__wrap_unsetenv, name, "HA_env_var"); + will_return(__wrap_unsetenv, 0); + pcmk__set_env_option("env_var", NULL); + + pcmk__mock_unsetenv = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_input_string), + cmocka_unit_test(input_too_long_for_both), + cmocka_unit_test(input_too_long_for_pcmk), + cmocka_unit_test(valid_inputs_set), + cmocka_unit_test(valid_inputs_unset)) diff --git a/lib/common/tests/output/Makefile.am b/lib/common/tests/output/Makefile.am new file mode 100644 index 0000000..6ac7b5f --- /dev/null +++ b/lib/common/tests/output/Makefile.am @@ -0,0 +1,24 @@ +# +# Copyright 2021-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__call_message_test \ + pcmk__output_and_clear_error_test \ + pcmk__output_free_test \ + pcmk__output_new_test \ + pcmk__register_format_test \ + pcmk__register_formats_test \ + pcmk__register_message_test \ + pcmk__register_messages_test \ + pcmk__unregister_formats_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/output/pcmk__call_message_test.c b/lib/common/tests/output/pcmk__call_message_test.c new file mode 100644 index 0000000..824eac7 --- /dev/null +++ b/lib/common/tests/output/pcmk__call_message_test.c @@ -0,0 +1,156 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +static int +default_message_fn(pcmk__output_t *out, va_list args) { + function_called(); + return pcmk_rc_ok; +} + +static int +failed_message_fn(pcmk__output_t *out, va_list args) { + function_called(); + return pcmk_rc_no_output; +} + +static int +message_fn_1(pcmk__output_t *out, va_list args) { + function_called(); + return pcmk_rc_ok; +} + +static int +message_fn_2(pcmk__output_t *out, va_list args) { + function_called(); + return pcmk_rc_ok; +} + +static bool +fake_text_init(pcmk__output_t *out) { + return true; +} + +static void +fake_text_free_priv(pcmk__output_t *out) { + /* This function intentionally left blank */ +} + +static pcmk__output_t * +mk_fake_text_output(char **argv) { + pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); + + if (retval == NULL) { + return NULL; + } + + retval->fmt_name = "text"; + retval->init = fake_text_init; + retval->free_priv = fake_text_free_priv; + + retval->register_message = pcmk__register_message; + retval->message = pcmk__call_message; + + return retval; +} + +static int +setup(void **state) { + pcmk__register_format(NULL, "text", mk_fake_text_output, NULL); + return 0; +} + +static int +teardown(void **state) { + pcmk__unregister_formats(); + return 0; +} + +static void +no_such_message(void **state) { + pcmk__output_t *out = NULL; + + pcmk__output_new(&out, "text", NULL, NULL); + + assert_int_equal(out->message(out, "fake"), EINVAL); + pcmk__assert_asserts(out->message(out, "")); + pcmk__assert_asserts(out->message(out, NULL)); + + pcmk__output_free(out); +} + +static void +message_return_value(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "text", message_fn_1 }, + { "msg2", "text", message_fn_2 }, + { "fail", "text", failed_message_fn }, + { NULL }, + }; + + pcmk__output_new(&out, "text", NULL, NULL); + pcmk__register_messages(out, entries); + + expect_function_call(message_fn_1); + assert_int_equal(out->message(out, "msg1"), pcmk_rc_ok); + expect_function_call(message_fn_2); + assert_int_equal(out->message(out, "msg2"), pcmk_rc_ok); + expect_function_call(failed_message_fn); + assert_int_equal(out->message(out, "fail"), pcmk_rc_no_output); + + pcmk__output_free(out); +} + +static void +wrong_format(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "xml", message_fn_1 }, + { NULL }, + }; + + pcmk__output_new(&out, "text", NULL, NULL); + pcmk__register_messages(out, entries); + + assert_int_equal(out->message(out, "msg1"), EINVAL); + + pcmk__output_free(out); +} + +static void +default_called(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "default", default_message_fn }, + { "msg1", "xml", message_fn_1 }, + { NULL }, + }; + + pcmk__output_new(&out, "text", NULL, NULL); + pcmk__register_messages(out, entries); + + expect_function_call(default_message_fn); + assert_int_equal(out->message(out, "msg1"), pcmk_rc_ok); + + pcmk__output_free(out); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test_setup_teardown(no_such_message, setup, teardown), + cmocka_unit_test_setup_teardown(message_return_value, setup, teardown), + cmocka_unit_test_setup_teardown(wrong_format, setup, teardown), + cmocka_unit_test_setup_teardown(default_called, setup, teardown)) diff --git a/lib/common/tests/output/pcmk__output_and_clear_error_test.c b/lib/common/tests/output/pcmk__output_and_clear_error_test.c new file mode 100644 index 0000000..f54ed8a --- /dev/null +++ b/lib/common/tests/output/pcmk__output_and_clear_error_test.c @@ -0,0 +1,82 @@ +/* + * Copyright 2022-2023 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +#include <glib.h> + +static bool +fake_text_init(pcmk__output_t *out) { + return true; +} + +static void +fake_text_free_priv(pcmk__output_t *out) { + /* This function intentionally left blank */ +} + +G_GNUC_PRINTF(2, 3) +static void +fake_text_err(pcmk__output_t *out, const char *format, ...) { + function_called(); +} + +static pcmk__output_t * +mk_fake_text_output(char **argv) { + pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); + + if (retval == NULL) { + return NULL; + } + + retval->fmt_name = "text"; + retval->init = fake_text_init; + retval->free_priv = fake_text_free_priv; + + retval->register_message = pcmk__register_message; + retval->message = pcmk__call_message; + + retval->err = fake_text_err; + + return retval; +} + +static int +setup(void **state) { + pcmk__register_format(NULL, "text", mk_fake_text_output, NULL); + return 0; +} + +static int +teardown(void **state) { + pcmk__unregister_formats(); + return 0; +} + +static void +standard_usage(void **state) { + GError *error = NULL; + pcmk__output_t *out = NULL; + + pcmk__output_new(&out, "text", NULL, NULL); + g_set_error(&error, PCMK__RC_ERROR, pcmk_rc_bad_nvpair, + "some error message"); + + expect_function_call(fake_text_err); + pcmk__output_and_clear_error(&error, out); + + pcmk__output_free(out); + assert_null(error); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test_setup_teardown(standard_usage, setup, teardown)) diff --git a/lib/common/tests/output/pcmk__output_free_test.c b/lib/common/tests/output/pcmk__output_free_test.c new file mode 100644 index 0000000..ef074d1 --- /dev/null +++ b/lib/common/tests/output/pcmk__output_free_test.c @@ -0,0 +1,84 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +static int +null_message_fn(pcmk__output_t *out, va_list args) { + return pcmk_rc_ok; +} + +static bool +fake_text_init(pcmk__output_t *out) { + return true; +} + +static void +fake_text_free_priv(pcmk__output_t *out) { + function_called(); + /* This function intentionally left blank */ +} + +static pcmk__output_t * +mk_fake_text_output(char **argv) { + pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); + + if (retval == NULL) { + return NULL; + } + + retval->fmt_name = "text"; + retval->init = fake_text_init; + retval->free_priv = fake_text_free_priv; + + retval->register_message = pcmk__register_message; + retval->message = pcmk__call_message; + + return retval; +} + +static int +setup(void **state) { + pcmk__register_format(NULL, "text", mk_fake_text_output, NULL); + return 0; +} + +static int +teardown(void **state) { + pcmk__unregister_formats(); + return 0; +} + +static void +no_messages(void **state) { + pcmk__output_t *out = NULL; + + pcmk__output_new(&out, "text", NULL, NULL); + + expect_function_call(fake_text_free_priv); + pcmk__output_free(out); +} + +static void +messages(void **state) { + pcmk__output_t *out = NULL; + + pcmk__output_new(&out, "text", NULL, NULL); + pcmk__register_message(out, "fake", null_message_fn); + + expect_function_call(fake_text_free_priv); + pcmk__output_free(out); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test_setup_teardown(no_messages, setup, teardown), + cmocka_unit_test_setup_teardown(messages, setup, teardown)) diff --git a/lib/common/tests/output/pcmk__output_new_test.c b/lib/common/tests/output/pcmk__output_new_test.c new file mode 100644 index 0000000..de4268c --- /dev/null +++ b/lib/common/tests/output/pcmk__output_new_test.c @@ -0,0 +1,148 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +#include "mock_private.h" + +static bool init_succeeds = true; + +static bool +fake_text_init(pcmk__output_t *out) { + return init_succeeds; +} + +static void +fake_text_free_priv(pcmk__output_t *out) { + /* This function intentionally left blank */ +} + +/* "text" is the default for pcmk__output_new. */ +static pcmk__output_t * +mk_fake_text_output(char **argv) { + pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); + + if (retval == NULL) { + return NULL; + } + + retval->fmt_name = "text"; + retval->init = fake_text_init; + retval->free_priv = fake_text_free_priv; + + retval->register_message = pcmk__register_message; + retval->message = pcmk__call_message; + + return retval; +} + +static int +setup(void **state) { + pcmk__register_format(NULL, "text", mk_fake_text_output, NULL); + return 0; +} + +static int +teardown(void **state) { + pcmk__unregister_formats(); + return 0; +} + +static void +empty_formatters(void **state) { + pcmk__output_t *out = NULL; + + pcmk__assert_asserts(pcmk__output_new(&out, "fake", NULL, NULL)); +} + +static void +invalid_params(void **state) { + /* This must be called with the setup/teardown functions so formatters is not NULL. */ + pcmk__assert_asserts(pcmk__output_new(NULL, "fake", NULL, NULL)); +} + +static void +no_such_format(void **state) { + pcmk__output_t *out = NULL; + + assert_int_equal(pcmk__output_new(&out, "fake", NULL, NULL), pcmk_rc_unknown_format); +} + +static void +create_fails(void **state) { + pcmk__output_t *out = NULL; + + pcmk__mock_calloc = true; // calloc() will return NULL + + expect_value(__wrap_calloc, nmemb, 1); + expect_value(__wrap_calloc, size, sizeof(pcmk__output_t)); + assert_int_equal(pcmk__output_new(&out, "text", NULL, NULL), ENOMEM); + + pcmk__mock_calloc = false; // Use real calloc() +} + +static void +fopen_fails(void **state) { + pcmk__output_t *out = NULL; + + pcmk__mock_fopen = true; + expect_string(__wrap_fopen, pathname, "destfile"); + expect_string(__wrap_fopen, mode, "w"); + will_return(__wrap_fopen, EPERM); + + assert_int_equal(pcmk__output_new(&out, "text", "destfile", NULL), EPERM); + + pcmk__mock_fopen = false; +} + +static void +init_fails(void **state) { + pcmk__output_t *out = NULL; + + init_succeeds = false; + assert_int_equal(pcmk__output_new(&out, "text", NULL, NULL), ENOMEM); + init_succeeds = true; +} + +static void +everything_succeeds(void **state) { + pcmk__output_t *out = NULL; + + assert_int_equal(pcmk__output_new(&out, "text", NULL, NULL), pcmk_rc_ok); + assert_string_equal(out->fmt_name, "text"); + assert_ptr_equal(out->dest, stdout); + assert_false(out->quiet); + assert_non_null(out->messages); + assert_string_equal(getenv("OCF_OUTPUT_FORMAT"), "text"); + + pcmk__output_free(out); +} + +static void +no_fmt_name_given(void **state) { + pcmk__output_t *out = NULL; + + assert_int_equal(pcmk__output_new(&out, NULL, NULL, NULL), pcmk_rc_ok); + assert_string_equal(out->fmt_name, "text"); + + pcmk__output_free(out); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_formatters), + cmocka_unit_test_setup_teardown(invalid_params, setup, teardown), + cmocka_unit_test_setup_teardown(no_such_format, setup, teardown), + cmocka_unit_test_setup_teardown(create_fails, setup, teardown), + cmocka_unit_test_setup_teardown(init_fails, setup, teardown), + cmocka_unit_test_setup_teardown(fopen_fails, setup, teardown), + cmocka_unit_test_setup_teardown(everything_succeeds, setup, teardown), + cmocka_unit_test_setup_teardown(no_fmt_name_given, setup, teardown)) diff --git a/lib/common/tests/output/pcmk__register_format_test.c b/lib/common/tests/output/pcmk__register_format_test.c new file mode 100644 index 0000000..bcbde48 --- /dev/null +++ b/lib/common/tests/output/pcmk__register_format_test.c @@ -0,0 +1,63 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +static pcmk__output_t * +null_create_fn(char **argv) { + return NULL; +} + +static pcmk__output_t * +null_create_fn_2(char **argv) { + return NULL; +} + +static void +invalid_params(void **state) { + pcmk__assert_asserts(pcmk__register_format(NULL, "fake", NULL, NULL)); + pcmk__assert_asserts(pcmk__register_format(NULL, "", null_create_fn, NULL)); + pcmk__assert_asserts(pcmk__register_format(NULL, NULL, null_create_fn, NULL)); +} + +static void +add_format(void **state) { + GHashTable *formatters = NULL; + gpointer value; + + /* For starters, there should be no formatters defined. */ + assert_null(pcmk__output_formatters()); + + /* Add a fake formatter and check that it's the only item in the hash table. */ + assert_int_equal(pcmk__register_format(NULL, "fake", null_create_fn, NULL), pcmk_rc_ok); + formatters = pcmk__output_formatters(); + assert_int_equal(g_hash_table_size(formatters), 1); + + value = g_hash_table_lookup(formatters, "fake"); + assert_ptr_equal(value, null_create_fn); + + /* Add a second fake formatter which should overwrite the first one, leaving + * only one item in the hash table but pointing at the new function. + */ + assert_int_equal(pcmk__register_format(NULL, "fake", null_create_fn_2, NULL), pcmk_rc_ok); + formatters = pcmk__output_formatters(); + assert_int_equal(g_hash_table_size(formatters), 1); + + value = g_hash_table_lookup(formatters, "fake"); + assert_ptr_equal(value, null_create_fn_2); + + pcmk__unregister_formats(); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(invalid_params), + cmocka_unit_test(add_format)) diff --git a/lib/common/tests/output/pcmk__register_formats_test.c b/lib/common/tests/output/pcmk__register_formats_test.c new file mode 100644 index 0000000..4be2d78 --- /dev/null +++ b/lib/common/tests/output/pcmk__register_formats_test.c @@ -0,0 +1,108 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +static pcmk__output_t * +null_create_fn(char **argv) { + return NULL; +} + +static pcmk__output_t * +null_create_fn_2(char **argv) { + return NULL; +} + +static void +no_formats(void **state) { + pcmk__register_formats(NULL, NULL); + assert_null(pcmk__output_formatters()); +} + +static void +invalid_entries(void **state) { + /* Here, we can only test that an empty name won't be added. A NULL name is + * the marker for the end of the format table. + */ + pcmk__supported_format_t formats[] = { + { "", null_create_fn, NULL }, + { NULL }, + }; + + pcmk__assert_asserts(pcmk__register_formats(NULL, formats)); +} + +static void +valid_entries(void **state) { + GHashTable *formatters = NULL; + + pcmk__supported_format_t formats[] = { + { "fmt1", null_create_fn, NULL }, + { "fmt2", null_create_fn_2, NULL }, + { NULL }, + }; + + pcmk__register_formats(NULL, formats); + + formatters = pcmk__output_formatters(); + assert_int_equal(g_hash_table_size(formatters), 2); + assert_ptr_equal(g_hash_table_lookup(formatters, "fmt1"), null_create_fn); + assert_ptr_equal(g_hash_table_lookup(formatters, "fmt2"), null_create_fn_2); + + pcmk__unregister_formats(); +} + +static void +duplicate_keys(void **state) { + GHashTable *formatters = NULL; + + pcmk__supported_format_t formats[] = { + { "fmt1", null_create_fn, NULL }, + { "fmt1", null_create_fn_2, NULL }, + { NULL }, + }; + + pcmk__register_formats(NULL, formats); + + formatters = pcmk__output_formatters(); + assert_int_equal(g_hash_table_size(formatters), 1); + assert_ptr_equal(g_hash_table_lookup(formatters, "fmt1"), null_create_fn_2); + + pcmk__unregister_formats(); +} + +static void +duplicate_values(void **state) { + GHashTable *formatters = NULL; + + pcmk__supported_format_t formats[] = { + { "fmt1", null_create_fn, NULL }, + { "fmt2", null_create_fn, NULL }, + { NULL }, + }; + + pcmk__register_formats(NULL, formats); + + formatters = pcmk__output_formatters(); + assert_int_equal(g_hash_table_size(formatters), 2); + assert_ptr_equal(g_hash_table_lookup(formatters, "fmt1"), null_create_fn); + assert_ptr_equal(g_hash_table_lookup(formatters, "fmt2"), null_create_fn); + + pcmk__unregister_formats(); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(no_formats), + cmocka_unit_test(invalid_entries), + cmocka_unit_test(valid_entries), + cmocka_unit_test(duplicate_keys), + cmocka_unit_test(duplicate_values)) diff --git a/lib/common/tests/output/pcmk__register_message_test.c b/lib/common/tests/output/pcmk__register_message_test.c new file mode 100644 index 0000000..4b4a282 --- /dev/null +++ b/lib/common/tests/output/pcmk__register_message_test.c @@ -0,0 +1,107 @@ +/* + * Copyright 2022-2023 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +#include "../../crmcommon_private.h" + +static int +null_message_fn(pcmk__output_t *out, va_list args) { + return pcmk_rc_ok; +} + +static int +null_message_fn_2(pcmk__output_t *out, va_list args) { + return pcmk_rc_ok; +} + +static bool +fake_text_init(pcmk__output_t *out) { + return true; +} + +static void +fake_text_free_priv(pcmk__output_t *out) { + /* This function intentionally left blank */ +} + +static pcmk__output_t * +mk_fake_text_output(char **argv) { + pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); + + if (retval == NULL) { + return NULL; + } + + retval->fmt_name = "text"; + retval->init = fake_text_init; + retval->free_priv = fake_text_free_priv; + + retval->register_message = pcmk__register_message; + retval->message = pcmk__call_message; + + return retval; +} + +static int +setup(void **state) { + pcmk__register_format(NULL, "text", mk_fake_text_output, NULL); + return 0; +} + +static int +teardown(void **state) { + pcmk__unregister_formats(); + return 0; +} + +static void +null_params(void **state) { + pcmk__output_t *out = NULL; + + pcmk__output_new(&out, "text", NULL, NULL); + + pcmk__assert_asserts(pcmk__register_message(NULL, "fake", null_message_fn)); + pcmk__assert_asserts(pcmk__register_message(out, NULL, null_message_fn)); + pcmk__assert_asserts(pcmk__register_message(out, "", null_message_fn)); + pcmk__assert_asserts(pcmk__register_message(out, "fake", NULL)); + + pcmk__output_free(out); +} + +static void +add_message(void **state) { + pcmk__output_t *out = NULL; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + /* For starters, there should be no messages defined. */ + assert_int_equal(g_hash_table_size(out->messages), 0); + + /* Add a fake function and check that it's the only item in the hash table. */ + pcmk__register_message(out, "fake", null_message_fn); + assert_int_equal(g_hash_table_size(out->messages), 1); + assert_ptr_equal(g_hash_table_lookup(out->messages, "fake"), null_message_fn); + + /* Add a second fake function which should overwrite the first one, leaving + * only one item in the hash table but pointing at the new function. + */ + pcmk__register_message(out, "fake", null_message_fn_2); + assert_int_equal(g_hash_table_size(out->messages), 1); + assert_ptr_equal(g_hash_table_lookup(out->messages, "fake"), null_message_fn_2); + + pcmk__output_free(out); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test_setup_teardown(null_params, setup, teardown), + cmocka_unit_test_setup_teardown(add_message, setup, teardown)) diff --git a/lib/common/tests/output/pcmk__register_messages_test.c b/lib/common/tests/output/pcmk__register_messages_test.c new file mode 100644 index 0000000..3fdd759 --- /dev/null +++ b/lib/common/tests/output/pcmk__register_messages_test.c @@ -0,0 +1,191 @@ +/* + * Copyright 2022-2023 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +#include "../../crmcommon_private.h" + +static int +null_message_fn(pcmk__output_t *out, va_list args) { + return pcmk_rc_ok; +} + +static int +null_message_fn_2(pcmk__output_t *out, va_list args) { + return pcmk_rc_ok; +} + +static bool +fake_text_init(pcmk__output_t *out) { + return true; +} + +static void +fake_text_free_priv(pcmk__output_t *out) { + /* This function intentionally left blank */ +} + +static pcmk__output_t * +mk_fake_text_output(char **argv) { + pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t)); + + if (retval == NULL) { + return NULL; + } + + retval->fmt_name = "text"; + retval->init = fake_text_init; + retval->free_priv = fake_text_free_priv; + + retval->register_message = pcmk__register_message; + retval->message = pcmk__call_message; + + return retval; +} + +static int +setup(void **state) { + pcmk__register_format(NULL, "text", mk_fake_text_output, NULL); + return 0; +} + +static int +teardown(void **state) { + pcmk__unregister_formats(); + return 0; +} + +static void +invalid_entries(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + /* We can't test a NULL message_id here because that's the marker for + * the end of the table. + */ + { "", "", null_message_fn }, + { "", NULL, null_message_fn }, + { "", "text", NULL }, + { NULL }, + }; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + pcmk__assert_asserts(pcmk__register_messages(out, entries)); + assert_int_equal(g_hash_table_size(out->messages), 0); + + pcmk__output_free(out); +} + +static void +valid_entries(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "text", null_message_fn }, + { "msg2", "text", null_message_fn_2 }, + { NULL }, + }; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + pcmk__register_messages(out, entries); + assert_int_equal(g_hash_table_size(out->messages), 2); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg1"), null_message_fn); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg2"), null_message_fn_2); + + pcmk__output_free(out); +} + +static void +duplicate_message_ids(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "text", null_message_fn }, + { "msg1", "text", null_message_fn_2 }, + { NULL }, + }; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + pcmk__register_messages(out, entries); + assert_int_equal(g_hash_table_size(out->messages), 1); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg1"), null_message_fn_2); + + pcmk__output_free(out); +} + +static void +duplicate_functions(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "text", null_message_fn }, + { "msg2", "text", null_message_fn }, + { NULL }, + }; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + pcmk__register_messages(out, entries); + assert_int_equal(g_hash_table_size(out->messages), 2); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg1"), null_message_fn); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg2"), null_message_fn); + + pcmk__output_free(out); +} + +static void +default_handler(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "default", null_message_fn }, + { NULL }, + }; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + pcmk__register_messages(out, entries); + assert_int_equal(g_hash_table_size(out->messages), 1); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg1"), null_message_fn); + + pcmk__output_free(out); +} + +static void +override_default_handler(void **state) { + pcmk__output_t *out = NULL; + + pcmk__message_entry_t entries[] = { + { "msg1", "default", null_message_fn }, + { "msg1", "text", null_message_fn_2 }, + { NULL }, + }; + + pcmk__bare_output_new(&out, "text", NULL, NULL); + + pcmk__register_messages(out, entries); + assert_int_equal(g_hash_table_size(out->messages), 1); + assert_ptr_equal(g_hash_table_lookup(out->messages, "msg1"), null_message_fn_2); + + pcmk__output_free(out); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test_setup_teardown(invalid_entries, setup, teardown), + cmocka_unit_test_setup_teardown(valid_entries, setup, teardown), + cmocka_unit_test_setup_teardown(duplicate_message_ids, setup, teardown), + cmocka_unit_test_setup_teardown(duplicate_functions, setup, teardown), + cmocka_unit_test_setup_teardown(default_handler, setup, teardown), + cmocka_unit_test_setup_teardown(override_default_handler, setup, teardown)) diff --git a/lib/common/tests/output/pcmk__unregister_formats_test.c b/lib/common/tests/output/pcmk__unregister_formats_test.c new file mode 100644 index 0000000..0631c95 --- /dev/null +++ b/lib/common/tests/output/pcmk__unregister_formats_test.c @@ -0,0 +1,39 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/output_internal.h> + +static pcmk__output_t * +null_create_fn(char **argv) { + return NULL; +} + +static void +invalid_params(void **state) { + /* This is basically just here to make sure that calling pcmk__unregister_formats + * with formatters=NULL doesn't segfault. + */ + pcmk__unregister_formats(); + assert_null(pcmk__output_formatters()); +} + +static void +non_null_formatters(void **state) { + pcmk__register_format(NULL, "fake", null_create_fn, NULL); + + pcmk__unregister_formats(); + assert_null(pcmk__output_formatters()); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(invalid_params), + cmocka_unit_test(non_null_formatters)) diff --git a/lib/common/tests/procfs/Makefile.am b/lib/common/tests/procfs/Makefile.am new file mode 100644 index 0000000..75511f5 --- /dev/null +++ b/lib/common/tests/procfs/Makefile.am @@ -0,0 +1,18 @@ +# +# Copyright 2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__procfs_has_pids_false_test \ + pcmk__procfs_has_pids_true_test \ + pcmk__procfs_pid2path_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/procfs/pcmk__procfs_has_pids_false_test.c b/lib/common/tests/procfs/pcmk__procfs_has_pids_false_test.c new file mode 100644 index 0000000..4601aac --- /dev/null +++ b/lib/common/tests/procfs/pcmk__procfs_has_pids_false_test.c @@ -0,0 +1,42 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +#include <unistd.h> +#include <string.h> +#include <errno.h> + + +static void +no_pids(void **state) +{ + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "/proc/%u/exe", getpid()); + + // Set readlink() errno and link contents (for /proc/PID/exe) + pcmk__mock_readlink = true; + + expect_string(__wrap_readlink, path, path); + expect_any(__wrap_readlink, buf); + expect_value(__wrap_readlink, bufsize, PATH_MAX - 1); + will_return(__wrap_readlink, ENOENT); + will_return(__wrap_readlink, NULL); + + assert_false(pcmk__procfs_has_pids()); + + pcmk__mock_readlink = false; +} + +PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(no_pids)) diff --git a/lib/common/tests/procfs/pcmk__procfs_has_pids_true_test.c b/lib/common/tests/procfs/pcmk__procfs_has_pids_true_test.c new file mode 100644 index 0000000..758e3b9 --- /dev/null +++ b/lib/common/tests/procfs/pcmk__procfs_has_pids_true_test.c @@ -0,0 +1,41 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static void +has_pids(void **state) +{ + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "/proc/%u/exe", getpid()); + + // Set readlink() errno and link contents (for /proc/PID/exe) + pcmk__mock_readlink = true; + + expect_string(__wrap_readlink, path, path); + expect_any(__wrap_readlink, buf); + expect_value(__wrap_readlink, bufsize, PATH_MAX - 1); + will_return(__wrap_readlink, 0); + will_return(__wrap_readlink, "/ok"); + + assert_true(pcmk__procfs_has_pids()); + + pcmk__mock_readlink = false; +} + +PCMK__UNIT_TEST(NULL, NULL, cmocka_unit_test(has_pids)) diff --git a/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c b/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c new file mode 100644 index 0000000..2bae541 --- /dev/null +++ b/lib/common/tests/procfs/pcmk__procfs_pid2path_test.c @@ -0,0 +1,92 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +#include <unistd.h> +#include <string.h> +#include <errno.h> + +static void +no_exe_file(void **state) +{ + size_t len = PATH_MAX; + char *path = calloc(len, sizeof(char)); + + // Set readlink() errno and link contents + pcmk__mock_readlink = true; + + expect_string(__wrap_readlink, path, "/proc/1000/exe"); + expect_value(__wrap_readlink, buf, path); + expect_value(__wrap_readlink, bufsize, len - 1); + will_return(__wrap_readlink, ENOENT); + will_return(__wrap_readlink, NULL); + + assert_int_equal(pcmk__procfs_pid2path(1000, path, len), ENOENT); + + pcmk__mock_readlink = false; + + free(path); +} + +static void +contents_too_long(void **state) +{ + size_t len = 10; + char *path = calloc(len, sizeof(char)); + + // Set readlink() errno and link contents + pcmk__mock_readlink = true; + + expect_string(__wrap_readlink, path, "/proc/1000/exe"); + expect_value(__wrap_readlink, buf, path); + expect_value(__wrap_readlink, bufsize, len - 1); + will_return(__wrap_readlink, 0); + will_return(__wrap_readlink, "/more/than/10/characters"); + + assert_int_equal(pcmk__procfs_pid2path(1000, path, len), + ENAMETOOLONG); + + pcmk__mock_readlink = false; + + free(path); +} + +static void +contents_ok(void **state) +{ + size_t len = PATH_MAX; + char *path = calloc(len, sizeof(char)); + + // Set readlink() errno and link contents + pcmk__mock_readlink = true; + + expect_string(__wrap_readlink, path, "/proc/1000/exe"); + expect_value(__wrap_readlink, buf, path); + expect_value(__wrap_readlink, bufsize, len - 1); + will_return(__wrap_readlink, 0); + will_return(__wrap_readlink, "/ok"); + + assert_int_equal(pcmk__procfs_pid2path((pid_t) 1000, path, len), + pcmk_rc_ok); + assert_string_equal(path, "/ok"); + + pcmk__mock_readlink = false; + + free(path); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(no_exe_file), + cmocka_unit_test(contents_too_long), + cmocka_unit_test(contents_ok)) diff --git a/lib/common/tests/results/Makefile.am b/lib/common/tests/results/Makefile.am new file mode 100644 index 0000000..8d51d12 --- /dev/null +++ b/lib/common/tests/results/Makefile.am @@ -0,0 +1,16 @@ +# +# Copyright 2021-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__results_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/results/pcmk__results_test.c b/lib/common/tests/results/pcmk__results_test.c new file mode 100644 index 0000000..53665d1 --- /dev/null +++ b/lib/common/tests/results/pcmk__results_test.c @@ -0,0 +1,61 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> +#include <bzlib.h> + +static void +test_for_pcmk_rc_name(void **state) { + assert_string_equal(pcmk_rc_name(pcmk_rc_error-1), "pcmk_rc_unknown_format"); + assert_string_equal(pcmk_rc_name(pcmk_rc_ok), "pcmk_rc_ok"); + assert_string_equal(pcmk_rc_name(pcmk_rc_ok), "pcmk_rc_ok"); + assert_string_equal(pcmk_rc_name(-7777777), "Unknown"); +} + +static void +test_for_pcmk_rc_str(void **state) { + assert_string_equal(pcmk_rc_str(pcmk_rc_error-1), "Unknown output format"); + assert_string_equal(pcmk_rc_str(pcmk_rc_ok), "OK"); + assert_string_equal(pcmk_rc_str(-1), "Error"); +} + +static void +test_for_crm_exit_name(void **state) { + assert_string_equal(crm_exit_name(CRM_EX_OK), "CRM_EX_OK"); +} + +static void +test_for_crm_exit_str(void **state) { + assert_string_equal(crm_exit_str(CRM_EX_OK), "OK"); + assert_string_equal(crm_exit_str(129), "Interrupted by signal"); + assert_string_equal(crm_exit_str(-7777777), "Unknown exit status"); +} + +static void +test_for_pcmk_rc2exitc(void **state) { + assert_int_equal(pcmk_rc2exitc(pcmk_rc_ok), CRM_EX_OK); + assert_int_equal(pcmk_rc2exitc(-7777777), CRM_EX_ERROR); +} + +static void +test_for_bz2_strerror(void **state) { + assert_string_equal(bz2_strerror(BZ_STREAM_END), "Ok"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(test_for_pcmk_rc_name), + cmocka_unit_test(test_for_pcmk_rc_str), + cmocka_unit_test(test_for_crm_exit_name), + cmocka_unit_test(test_for_crm_exit_str), + cmocka_unit_test(test_for_pcmk_rc2exitc), + cmocka_unit_test(test_for_bz2_strerror)) diff --git a/lib/common/tests/scores/Makefile.am b/lib/common/tests/scores/Makefile.am new file mode 100644 index 0000000..66ca073 --- /dev/null +++ b/lib/common/tests/scores/Makefile.am @@ -0,0 +1,19 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + char2score_test \ + pcmk__add_scores_test \ + pcmk_readable_score_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/scores/char2score_test.c b/lib/common/tests/scores/char2score_test.c new file mode 100644 index 0000000..fbba12a --- /dev/null +++ b/lib/common/tests/scores/char2score_test.c @@ -0,0 +1,75 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +extern int pcmk__score_red; +extern int pcmk__score_green; +extern int pcmk__score_yellow; + +static void +empty_input(void **state) +{ + assert_int_equal(char2score(NULL), 0); +} + +static void +bad_input(void **state) +{ + assert_int_equal(char2score("PQRST"), 0); + assert_int_equal(char2score("3.141592"), 3); + assert_int_equal(char2score("0xf00d"), 0); +} + +static void +special_values(void **state) +{ + assert_int_equal(char2score("-INFINITY"), -CRM_SCORE_INFINITY); + assert_int_equal(char2score("INFINITY"), CRM_SCORE_INFINITY); + assert_int_equal(char2score("+INFINITY"), CRM_SCORE_INFINITY); + + pcmk__score_red = 10; + pcmk__score_green = 20; + pcmk__score_yellow = 30; + + assert_int_equal(char2score("red"), pcmk__score_red); + assert_int_equal(char2score("green"), pcmk__score_green); + assert_int_equal(char2score("yellow"), pcmk__score_yellow); + + assert_int_equal(char2score("ReD"), pcmk__score_red); + assert_int_equal(char2score("GrEeN"), pcmk__score_green); + assert_int_equal(char2score("yElLoW"), pcmk__score_yellow); +} + +/* These ridiculous macros turn an integer constant into a string constant. */ +#define A(x) #x +#define B(x) A(x) + +static void +outside_limits(void **state) +{ + assert_int_equal(char2score(B(CRM_SCORE_INFINITY) "00"), CRM_SCORE_INFINITY); + assert_int_equal(char2score("-" B(CRM_SCORE_INFINITY) "00"), -CRM_SCORE_INFINITY); +} + +static void +inside_limits(void **state) +{ + assert_int_equal(char2score("1234"), 1234); + assert_int_equal(char2score("-1234"), -1234); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input), + cmocka_unit_test(bad_input), + cmocka_unit_test(special_values), + cmocka_unit_test(outside_limits), + cmocka_unit_test(inside_limits)) diff --git a/lib/common/tests/scores/pcmk__add_scores_test.c b/lib/common/tests/scores/pcmk__add_scores_test.c new file mode 100644 index 0000000..85ac232 --- /dev/null +++ b/lib/common/tests/scores/pcmk__add_scores_test.c @@ -0,0 +1,74 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +score1_minus_inf(void **state) +{ + assert_int_equal(pcmk__add_scores(-CRM_SCORE_INFINITY, -CRM_SCORE_INFINITY), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(-CRM_SCORE_INFINITY, -1), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(-CRM_SCORE_INFINITY, 0), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(-CRM_SCORE_INFINITY, 1), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(-CRM_SCORE_INFINITY, CRM_SCORE_INFINITY), -CRM_SCORE_INFINITY); +} + +static void +score2_minus_inf(void **state) +{ + assert_int_equal(pcmk__add_scores(-1, -CRM_SCORE_INFINITY), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(0, -CRM_SCORE_INFINITY), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(1, -CRM_SCORE_INFINITY), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(CRM_SCORE_INFINITY, -CRM_SCORE_INFINITY), -CRM_SCORE_INFINITY); +} + +static void +score1_pos_inf(void **state) +{ + assert_int_equal(pcmk__add_scores(CRM_SCORE_INFINITY, CRM_SCORE_INFINITY), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(CRM_SCORE_INFINITY, -1), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(CRM_SCORE_INFINITY, 0), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(CRM_SCORE_INFINITY, 1), CRM_SCORE_INFINITY); +} + +static void +score2_pos_inf(void **state) +{ + assert_int_equal(pcmk__add_scores(-1, CRM_SCORE_INFINITY), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(0, CRM_SCORE_INFINITY), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(1, CRM_SCORE_INFINITY), CRM_SCORE_INFINITY); +} + +static void +result_infinite(void **state) +{ + assert_int_equal(pcmk__add_scores(INT_MAX, INT_MAX), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(INT_MIN, INT_MIN), -CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(2000000, 50), CRM_SCORE_INFINITY); + assert_int_equal(pcmk__add_scores(-4000000, 50), -CRM_SCORE_INFINITY); +} + +static void +result_finite(void **state) +{ + assert_int_equal(pcmk__add_scores(0, 0), 0); + assert_int_equal(pcmk__add_scores(0, 100), 100); + assert_int_equal(pcmk__add_scores(200, 0), 200); + assert_int_equal(pcmk__add_scores(200, -50), 150); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(score1_minus_inf), + cmocka_unit_test(score2_minus_inf), + cmocka_unit_test(score1_pos_inf), + cmocka_unit_test(score2_pos_inf), + cmocka_unit_test(result_infinite), + cmocka_unit_test(result_finite)) diff --git a/lib/common/tests/scores/pcmk_readable_score_test.c b/lib/common/tests/scores/pcmk_readable_score_test.c new file mode 100644 index 0000000..ae24159 --- /dev/null +++ b/lib/common/tests/scores/pcmk_readable_score_test.c @@ -0,0 +1,33 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +outside_limits(void **state) +{ + assert_string_equal(pcmk_readable_score(CRM_SCORE_INFINITY * 2), + CRM_INFINITY_S); + assert_string_equal(pcmk_readable_score(-CRM_SCORE_INFINITY * 2), + CRM_MINUS_INFINITY_S); +} + +static void +inside_limits(void **state) +{ + assert_string_equal(pcmk_readable_score(0), "0"); + assert_string_equal(pcmk_readable_score(1024), "1024"); + assert_string_equal(pcmk_readable_score(-1024), "-1024"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(outside_limits), + cmocka_unit_test(inside_limits)) diff --git a/lib/common/tests/strings/Makefile.am b/lib/common/tests/strings/Makefile.am new file mode 100644 index 0000000..9abb8e9 --- /dev/null +++ b/lib/common/tests/strings/Makefile.am @@ -0,0 +1,41 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + crm_get_msec_test \ + crm_is_true_test \ + crm_str_to_boolean_test \ + pcmk__add_word_test \ + pcmk__btoa_test \ + pcmk__char_in_any_str_test \ + pcmk__compress_test \ + pcmk__ends_with_test \ + pcmk__g_strcat_test \ + pcmk__guint_from_hash_test \ + pcmk__numeric_strcasecmp_test \ + pcmk__parse_ll_range_test \ + pcmk__s_test \ + pcmk__scan_double_test \ + pcmk__scan_min_int_test \ + pcmk__scan_port_test \ + pcmk__starts_with_test \ + pcmk__str_any_of_test \ + pcmk__str_in_list_test \ + pcmk__str_table_dup_test \ + pcmk__str_update_test \ + pcmk__strcmp_test \ + pcmk__strkey_table_test \ + pcmk__strikey_table_test \ + pcmk__trim_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/strings/crm_get_msec_test.c b/lib/common/tests/strings/crm_get_msec_test.c new file mode 100644 index 0000000..5da548b --- /dev/null +++ b/lib/common/tests/strings/crm_get_msec_test.c @@ -0,0 +1,50 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +bad_input(void **state) { + assert_int_equal(crm_get_msec(NULL), PCMK__PARSE_INT_DEFAULT); + assert_int_equal(crm_get_msec(" "), PCMK__PARSE_INT_DEFAULT); + assert_int_equal(crm_get_msec("abcxyz"), PCMK__PARSE_INT_DEFAULT); + assert_int_equal(crm_get_msec("100xs"), PCMK__PARSE_INT_DEFAULT); + assert_int_equal(crm_get_msec(" 100 xs "), PCMK__PARSE_INT_DEFAULT); + assert_int_equal(crm_get_msec("-100ms"), PCMK__PARSE_INT_DEFAULT); +} + +static void +good_input(void **state) { + assert_int_equal(crm_get_msec("100"), 100000); + assert_int_equal(crm_get_msec(" 100 "), 100000); + assert_int_equal(crm_get_msec("\t100\n"), 100000); + + assert_int_equal(crm_get_msec("100ms"), 100); + assert_int_equal(crm_get_msec("100 MSEC"), 100); + assert_int_equal(crm_get_msec("1000US"), 1); + assert_int_equal(crm_get_msec("1000usec"), 1); + assert_int_equal(crm_get_msec("12s"), 12000); + assert_int_equal(crm_get_msec("12 sec"), 12000); + assert_int_equal(crm_get_msec("1m"), 60000); + assert_int_equal(crm_get_msec("13 min"), 780000); + assert_int_equal(crm_get_msec("2\th"), 7200000); + assert_int_equal(crm_get_msec("1 hr"), 3600000); +} + +static void +overflow(void **state) { + assert_int_equal(crm_get_msec("9223372036854775807s"), LLONG_MAX); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_input), + cmocka_unit_test(good_input), + cmocka_unit_test(overflow)) diff --git a/lib/common/tests/strings/crm_is_true_test.c b/lib/common/tests/strings/crm_is_true_test.c new file mode 100644 index 0000000..2a9e31c --- /dev/null +++ b/lib/common/tests/strings/crm_is_true_test.c @@ -0,0 +1,57 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +bad_input(void **state) { + assert_false(crm_is_true(NULL)); +} + +static void +is_true(void **state) { + assert_true(crm_is_true("true")); + assert_true(crm_is_true("TrUe")); + assert_true(crm_is_true("on")); + assert_true(crm_is_true("ON")); + assert_true(crm_is_true("yes")); + assert_true(crm_is_true("yES")); + assert_true(crm_is_true("y")); + assert_true(crm_is_true("Y")); + assert_true(crm_is_true("1")); +} + +static void +is_false(void **state) { + assert_false(crm_is_true("false")); + assert_false(crm_is_true("fAlSe")); + assert_false(crm_is_true("off")); + assert_false(crm_is_true("OFF")); + assert_false(crm_is_true("no")); + assert_false(crm_is_true("No")); + assert_false(crm_is_true("n")); + assert_false(crm_is_true("N")); + assert_false(crm_is_true("0")); + + assert_false(crm_is_true("")); + assert_false(crm_is_true("blahblah")); + + assert_false(crm_is_true("truedat")); + assert_false(crm_is_true("onnn")); + assert_false(crm_is_true("yep")); + assert_false(crm_is_true("Y!")); + assert_false(crm_is_true("100")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_input), + cmocka_unit_test(is_true), + cmocka_unit_test(is_false)) diff --git a/lib/common/tests/strings/crm_str_to_boolean_test.c b/lib/common/tests/strings/crm_str_to_boolean_test.c new file mode 100644 index 0000000..3bd2e5d --- /dev/null +++ b/lib/common/tests/strings/crm_str_to_boolean_test.c @@ -0,0 +1,92 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +bad_input(void **state) { + assert_int_equal(crm_str_to_boolean(NULL, NULL), -1); + assert_int_equal(crm_str_to_boolean("", NULL), -1); + assert_int_equal(crm_str_to_boolean("blahblah", NULL), -1); +} + +static void +is_true(void **state) { + int ret; + + assert_int_equal(crm_str_to_boolean("true", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("TrUe", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("on", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("ON", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("yes", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("yES", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("y", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("Y", &ret), 1); + assert_true(ret); + assert_int_equal(crm_str_to_boolean("1", &ret), 1); + assert_true(ret); +} + +static void +is_not_true(void **state) { + assert_int_equal(crm_str_to_boolean("truedat", NULL), -1); + assert_int_equal(crm_str_to_boolean("onnn", NULL), -1); + assert_int_equal(crm_str_to_boolean("yep", NULL), -1); + assert_int_equal(crm_str_to_boolean("Y!", NULL), -1); + assert_int_equal(crm_str_to_boolean("100", NULL), -1); +} + +static void +is_false(void **state) { + int ret; + + assert_int_equal(crm_str_to_boolean("false", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("fAlSe", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("off", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("OFF", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("no", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("No", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("n", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("N", &ret), 1); + assert_false(ret); + assert_int_equal(crm_str_to_boolean("0", &ret), 1); + assert_false(ret); +} + +static void +is_not_false(void **state) { + assert_int_equal(crm_str_to_boolean("falseee", NULL), -1); + assert_int_equal(crm_str_to_boolean("of", NULL), -1); + assert_int_equal(crm_str_to_boolean("nope", NULL), -1); + assert_int_equal(crm_str_to_boolean("N!", NULL), -1); + assert_int_equal(crm_str_to_boolean("000", NULL), -1); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_input), + cmocka_unit_test(is_true), + cmocka_unit_test(is_not_true), + cmocka_unit_test(is_false), + cmocka_unit_test(is_not_false)) diff --git a/lib/common/tests/strings/pcmk__add_word_test.c b/lib/common/tests/strings/pcmk__add_word_test.c new file mode 100644 index 0000000..16a749e --- /dev/null +++ b/lib/common/tests/strings/pcmk__add_word_test.c @@ -0,0 +1,93 @@ +/* + * Copyright 2020-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +add_words(void **state) +{ + GString *list = NULL; + + pcmk__add_word(&list, 16, "hello"); + pcmk__add_word(&list, 16, "world"); + assert_int_equal(strcmp((const char *) list->str, "hello world"), 0); + g_string_free(list, TRUE); +} + +static void +add_with_no_len(void **state) +{ + GString *list = NULL; + + pcmk__add_word(&list, 0, "hello"); + pcmk__add_word(&list, 0, "world"); + assert_int_equal(strcmp((const char *) list->str, "hello world"), 0); + g_string_free(list, TRUE); +} + +static void +add_nothing(void **state) +{ + GString *list = NULL; + + pcmk__add_word(&list, 0, "hello"); + pcmk__add_word(&list, 0, NULL); + pcmk__add_word(&list, 0, ""); + assert_int_equal(strcmp((const char *) list->str, "hello"), 0); + g_string_free(list, TRUE); +} + +static void +add_with_null(void **state) +{ + GString *list = NULL; + + pcmk__add_separated_word(&list, 32, "hello", NULL); + pcmk__add_separated_word(&list, 32, "world", NULL); + pcmk__add_separated_word(&list, 32, "I am a unit test", NULL); + assert_int_equal(strcmp((const char *) list->str, + "hello world I am a unit test"), 0); + g_string_free(list, TRUE); +} + +static void +add_with_comma(void **state) +{ + GString *list = NULL; + + pcmk__add_separated_word(&list, 32, "hello", ","); + pcmk__add_separated_word(&list, 32, "world", ","); + pcmk__add_separated_word(&list, 32, "I am a unit test", ","); + assert_int_equal(strcmp((const char *) list->str, + "hello,world,I am a unit test"), 0); + g_string_free(list, TRUE); +} + +static void +add_with_comma_and_space(void **state) +{ + GString *list = NULL; + + pcmk__add_separated_word(&list, 32, "hello", ", "); + pcmk__add_separated_word(&list, 32, "world", ", "); + pcmk__add_separated_word(&list, 32, "I am a unit test", ", "); + assert_int_equal(strcmp((const char *) list->str, + "hello, world, I am a unit test"), 0); + g_string_free(list, TRUE); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(add_words), + cmocka_unit_test(add_with_no_len), + cmocka_unit_test(add_nothing), + cmocka_unit_test(add_with_null), + cmocka_unit_test(add_with_comma), + cmocka_unit_test(add_with_comma_and_space)) diff --git a/lib/common/tests/strings/pcmk__btoa_test.c b/lib/common/tests/strings/pcmk__btoa_test.c new file mode 100644 index 0000000..f7dee9e --- /dev/null +++ b/lib/common/tests/strings/pcmk__btoa_test.c @@ -0,0 +1,22 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +btoa(void **state) { + assert_string_equal(pcmk__btoa(false), "false"); + assert_string_equal(pcmk__btoa(true), "true"); + assert_string_equal(pcmk__btoa(1 == 0), "false"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(btoa)) diff --git a/lib/common/tests/strings/pcmk__char_in_any_str_test.c b/lib/common/tests/strings/pcmk__char_in_any_str_test.c new file mode 100644 index 0000000..e70dfb4 --- /dev/null +++ b/lib/common/tests/strings/pcmk__char_in_any_str_test.c @@ -0,0 +1,46 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +empty_list(void **state) +{ + assert_false(pcmk__char_in_any_str('x', NULL)); + assert_false(pcmk__char_in_any_str('\0', NULL)); +} + +static void +null_char(void **state) +{ + assert_true(pcmk__char_in_any_str('\0', "xxx", "yyy", NULL)); + assert_true(pcmk__char_in_any_str('\0', "", NULL)); +} + +static void +in_list(void **state) +{ + assert_true(pcmk__char_in_any_str('x', "aaa", "bbb", "xxx", NULL)); +} + +static void +not_in_list(void **state) +{ + assert_false(pcmk__char_in_any_str('x', "aaa", "bbb", NULL)); + assert_false(pcmk__char_in_any_str('A', "aaa", "bbb", NULL)); + assert_false(pcmk__char_in_any_str('x', "", NULL)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_list), + cmocka_unit_test(null_char), + cmocka_unit_test(in_list), + cmocka_unit_test(not_in_list)) diff --git a/lib/common/tests/strings/pcmk__compress_test.c b/lib/common/tests/strings/pcmk__compress_test.c new file mode 100644 index 0000000..7480937 --- /dev/null +++ b/lib/common/tests/strings/pcmk__compress_test.c @@ -0,0 +1,58 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +#define SIMPLE_DATA "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + +const char *SIMPLE_COMPRESSED = "BZh41AY&SYO\x1ai"; + +static void +simple_compress(void **state) +{ + char *result = calloc(1024, sizeof(char)); + unsigned int len; + + assert_int_equal(pcmk__compress(SIMPLE_DATA, 40, 0, &result, &len), pcmk_rc_ok); + assert_memory_equal(result, SIMPLE_COMPRESSED, 13); +} + +static void +max_too_small(void **state) +{ + char *result = calloc(1024, sizeof(char)); + unsigned int len; + + assert_int_equal(pcmk__compress(SIMPLE_DATA, 40, 10, &result, &len), pcmk_rc_error); +} + +static void +calloc_fails(void **state) { + char *result = calloc(1024, sizeof(char)); + unsigned int len; + + pcmk__assert_asserts( + { + pcmk__mock_calloc = true; // calloc() will return NULL + expect_value(__wrap_calloc, nmemb, (size_t) ((40 * 1.01) + 601)); + expect_value(__wrap_calloc, size, sizeof(char)); + pcmk__compress(SIMPLE_DATA, 40, 0, &result, &len); + pcmk__mock_calloc = false; // Use the real calloc() + } + ); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(simple_compress), + cmocka_unit_test(max_too_small), + cmocka_unit_test(calloc_fails)) diff --git a/lib/common/tests/strings/pcmk__ends_with_test.c b/lib/common/tests/strings/pcmk__ends_with_test.c new file mode 100644 index 0000000..7503571 --- /dev/null +++ b/lib/common/tests/strings/pcmk__ends_with_test.c @@ -0,0 +1,57 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +bad_input(void **state) { + assert_false(pcmk__ends_with(NULL, "xyz")); + + assert_true(pcmk__ends_with(NULL, NULL)); + assert_true(pcmk__ends_with(NULL, "")); + assert_true(pcmk__ends_with("", NULL)); + assert_true(pcmk__ends_with("", "")); + assert_true(pcmk__ends_with("abc", NULL)); + assert_true(pcmk__ends_with("abc", "")); +} + +static void +ends_with(void **state) { + assert_true(pcmk__ends_with("abc", "abc")); + assert_true(pcmk__ends_with("abc", "bc")); + assert_true(pcmk__ends_with("abc", "c")); + assert_true(pcmk__ends_with("abcbc", "bc")); + + assert_false(pcmk__ends_with("abc", "def")); + assert_false(pcmk__ends_with("abc", "defg")); + assert_false(pcmk__ends_with("abc", "bcd")); + assert_false(pcmk__ends_with("abc", "ab")); + + assert_false(pcmk__ends_with("abc", "BC")); +} + +static void +ends_with_ext(void **state) { + assert_true(pcmk__ends_with_ext("ab.c", ".c")); + assert_true(pcmk__ends_with_ext("ab.cb.c", ".c")); + + assert_false(pcmk__ends_with_ext("ab.c", ".def")); + assert_false(pcmk__ends_with_ext("ab.c", ".defg")); + assert_false(pcmk__ends_with_ext("ab.c", ".cd")); + assert_false(pcmk__ends_with_ext("ab.c", "ab")); + + assert_false(pcmk__ends_with_ext("ab.c", ".C")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_input), + cmocka_unit_test(ends_with), + cmocka_unit_test(ends_with_ext)) diff --git a/lib/common/tests/strings/pcmk__g_strcat_test.c b/lib/common/tests/strings/pcmk__g_strcat_test.c new file mode 100644 index 0000000..2116f0e --- /dev/null +++ b/lib/common/tests/strings/pcmk__g_strcat_test.c @@ -0,0 +1,73 @@ +/* + * Copyright 2020-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +add_to_null(void **state) +{ + pcmk__assert_asserts(pcmk__g_strcat(NULL, NULL)); + pcmk__assert_asserts(pcmk__g_strcat(NULL, "hello", NULL)); +} + +static void +add_nothing(void **state) +{ + GString *buf = g_string_new(NULL); + + // Start with empty string + pcmk__g_strcat(buf, NULL); + assert_string_equal((const char *) buf->str, ""); + + pcmk__g_strcat(buf, "", NULL); + assert_string_equal((const char *) buf->str, ""); + + // Start with populated string + g_string_append(buf, "hello"); + pcmk__g_strcat(buf, NULL); + assert_string_equal((const char *) buf->str, "hello"); + + pcmk__g_strcat(buf, "", NULL); + assert_string_equal((const char *) buf->str, "hello"); + g_string_free(buf, TRUE); +} + +static void +add_words(void **state) +{ + GString *buf = g_string_new(NULL); + + // Verify a call with multiple words + pcmk__g_strcat(buf, "hello", " ", NULL); + assert_string_equal((const char *) buf->str, "hello "); + + // Verify that a second call doesn't overwrite the first one + pcmk__g_strcat(buf, "world", NULL); + assert_string_equal((const char *) buf->str, "hello world"); + g_string_free(buf, TRUE); +} + +static void +stop_early(void **state) +{ + GString *buf = g_string_new(NULL); + + // NULL anywhere after buf in the arg list should cause a return + pcmk__g_strcat(buf, "hello", NULL, " world", NULL); + assert_string_equal((const char *) buf->str, "hello"); + g_string_free(buf, TRUE); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(add_to_null), + cmocka_unit_test(add_nothing), + cmocka_unit_test(add_words), + cmocka_unit_test(stop_early)) diff --git a/lib/common/tests/strings/pcmk__guint_from_hash_test.c b/lib/common/tests/strings/pcmk__guint_from_hash_test.c new file mode 100644 index 0000000..e2b4762 --- /dev/null +++ b/lib/common/tests/strings/pcmk__guint_from_hash_test.c @@ -0,0 +1,76 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +null_args(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + guint result; + + assert_int_equal(pcmk__guint_from_hash(NULL, "abc", 123, &result), EINVAL); + assert_int_equal(pcmk__guint_from_hash(tbl, NULL, 123, &result), EINVAL); + + g_hash_table_destroy(tbl); +} + +static void +missing_key(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + guint result; + + assert_int_equal(pcmk__guint_from_hash(tbl, "abc", 123, &result), pcmk_rc_ok); + assert_int_equal(result, 123); + + g_hash_table_destroy(tbl); +} + +static void +standard_usage(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + guint result; + + g_hash_table_insert(tbl, strdup("abc"), strdup("123")); + + assert_int_equal(pcmk__guint_from_hash(tbl, "abc", 456, &result), pcmk_rc_ok); + assert_int_equal(result, 123); + + g_hash_table_destroy(tbl); +} + +static void +conversion_errors(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + guint result; + + g_hash_table_insert(tbl, strdup("negative"), strdup("-3")); + g_hash_table_insert(tbl, strdup("toobig"), strdup("20000000000000000")); + + assert_int_equal(pcmk__guint_from_hash(tbl, "negative", 456, &result), ERANGE); + assert_int_equal(result, 456); + + assert_int_equal(pcmk__guint_from_hash(tbl, "toobig", 456, &result), ERANGE); + assert_int_equal(result, 456); + + g_hash_table_destroy(tbl); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(null_args), + cmocka_unit_test(missing_key), + cmocka_unit_test(standard_usage), + cmocka_unit_test(conversion_errors)) diff --git a/lib/common/tests/strings/pcmk__numeric_strcasecmp_test.c b/lib/common/tests/strings/pcmk__numeric_strcasecmp_test.c new file mode 100644 index 0000000..df7b11c --- /dev/null +++ b/lib/common/tests/strings/pcmk__numeric_strcasecmp_test.c @@ -0,0 +1,79 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +null_ptr(void **state) +{ + pcmk__assert_asserts(pcmk__numeric_strcasecmp(NULL, NULL)); + pcmk__assert_asserts(pcmk__numeric_strcasecmp("a", NULL)); + pcmk__assert_asserts(pcmk__numeric_strcasecmp(NULL, "a")); +} + +static void +no_numbers(void **state) +{ + /* All comparisons are done case-insensitively. */ + assert_int_equal(pcmk__numeric_strcasecmp("abcd", "efgh"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("abcd", "abcd"), 0); + assert_int_equal(pcmk__numeric_strcasecmp("efgh", "abcd"), 1); + + assert_int_equal(pcmk__numeric_strcasecmp("AbCd", "eFgH"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("ABCD", "abcd"), 0); + assert_int_equal(pcmk__numeric_strcasecmp("EFgh", "ABcd"), 1); +} + +static void +trailing_numbers(void **state) +{ + assert_int_equal(pcmk__numeric_strcasecmp("node1", "node2"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("node1", "node1"), 0); + assert_int_equal(pcmk__numeric_strcasecmp("node2", "node1"), 1); + + assert_int_equal(pcmk__numeric_strcasecmp("node1", "node10"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("node10", "node10"), 0); + assert_int_equal(pcmk__numeric_strcasecmp("node10", "node1"), 1); + + assert_int_equal(pcmk__numeric_strcasecmp("node10", "remotenode9"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("remotenode9", "node10"), 1); + + /* Longer numbers sort higher than shorter numbers. */ + assert_int_equal(pcmk__numeric_strcasecmp("node001", "node1"), 1); + assert_int_equal(pcmk__numeric_strcasecmp("node1", "node001"), -1); +} + +static void +middle_numbers(void **state) +{ + assert_int_equal(pcmk__numeric_strcasecmp("node1abc", "node1def"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("node1def", "node1abc"), 1); + + assert_int_equal(pcmk__numeric_strcasecmp("node1abc", "node2abc"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("node2abc", "node1abc"), 1); +} + +static void +unequal_lengths(void **state) +{ + assert_int_equal(pcmk__numeric_strcasecmp("node-ab", "node-abc"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("node-abc", "node-ab"), 1); + + assert_int_equal(pcmk__numeric_strcasecmp("node1ab", "node1abc"), -1); + assert_int_equal(pcmk__numeric_strcasecmp("node1abc", "node1ab"), 1); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(null_ptr), + cmocka_unit_test(no_numbers), + cmocka_unit_test(trailing_numbers), + cmocka_unit_test(middle_numbers), + cmocka_unit_test(unequal_lengths)) diff --git a/lib/common/tests/strings/pcmk__parse_ll_range_test.c b/lib/common/tests/strings/pcmk__parse_ll_range_test.c new file mode 100644 index 0000000..7656ad7 --- /dev/null +++ b/lib/common/tests/strings/pcmk__parse_ll_range_test.c @@ -0,0 +1,117 @@ +/* + * Copyright 2020-2023 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include "crm/common/results.h" +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +empty_input_string(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range(NULL, &start, &end), ENODATA); + assert_int_equal(pcmk__parse_ll_range("", &start, &end), ENODATA); +} + +static void +null_input_variables(void **state) +{ + long long start, end; + + pcmk__assert_asserts(pcmk__parse_ll_range("1234", NULL, &end)); + pcmk__assert_asserts(pcmk__parse_ll_range("1234", &start, NULL)); +} + +static void +missing_separator(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("1234", &start, &end), pcmk_rc_ok); + assert_int_equal(start, 1234); + assert_int_equal(end, 1234); +} + +static void +only_separator(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("-", &start, &end), pcmk_rc_bad_input); + assert_int_equal(start, PCMK__PARSE_INT_DEFAULT); + assert_int_equal(end, PCMK__PARSE_INT_DEFAULT); +} + +static void +no_range_end(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("2000-", &start, &end), pcmk_rc_ok); + assert_int_equal(start, 2000); + assert_int_equal(end, PCMK__PARSE_INT_DEFAULT); +} + +static void +no_range_start(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("-2020", &start, &end), pcmk_rc_ok); + assert_int_equal(start, PCMK__PARSE_INT_DEFAULT); + assert_int_equal(end, 2020); +} + +static void +range_start_and_end(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("2000-2020", &start, &end), pcmk_rc_ok); + assert_int_equal(start, 2000); + assert_int_equal(end, 2020); + + assert_int_equal(pcmk__parse_ll_range("2000-2020-2030", &start, &end), pcmk_rc_bad_input); +} + +static void +garbage(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("2000x-", &start, &end), pcmk_rc_bad_input); + assert_int_equal(start, PCMK__PARSE_INT_DEFAULT); + assert_int_equal(end, PCMK__PARSE_INT_DEFAULT); + + assert_int_equal(pcmk__parse_ll_range("-x2000", &start, &end), pcmk_rc_bad_input); + assert_int_equal(start, PCMK__PARSE_INT_DEFAULT); + assert_int_equal(end, PCMK__PARSE_INT_DEFAULT); +} + +static void +strtoll_errors(void **state) +{ + long long start, end; + + assert_int_equal(pcmk__parse_ll_range("20000000000000000000-", &start, &end), EOVERFLOW); + assert_int_equal(pcmk__parse_ll_range("100-20000000000000000000", &start, &end), EOVERFLOW); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_string), + cmocka_unit_test(null_input_variables), + cmocka_unit_test(missing_separator), + cmocka_unit_test(only_separator), + cmocka_unit_test(no_range_end), + cmocka_unit_test(no_range_start), + cmocka_unit_test(range_start_and_end), + cmocka_unit_test(strtoll_errors), + cmocka_unit_test(garbage)) diff --git a/lib/common/tests/strings/pcmk__s_test.c b/lib/common/tests/strings/pcmk__s_test.c new file mode 100644 index 0000000..cdc2551 --- /dev/null +++ b/lib/common/tests/strings/pcmk__s_test.c @@ -0,0 +1,29 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +s_is_null(void **state) { + assert_null(pcmk__s(NULL, NULL)); + assert_string_equal(pcmk__s(NULL, ""), ""); + assert_string_equal(pcmk__s(NULL, "something"), "something"); +} + +static void +s_is_not_null(void **state) { + assert_string_equal(pcmk__s("something", NULL), "something"); + assert_string_equal(pcmk__s("something", "default"), "something"); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(s_is_null), + cmocka_unit_test(s_is_not_null)) diff --git a/lib/common/tests/strings/pcmk__scan_double_test.c b/lib/common/tests/strings/pcmk__scan_double_test.c new file mode 100644 index 0000000..a1a180a --- /dev/null +++ b/lib/common/tests/strings/pcmk__scan_double_test.c @@ -0,0 +1,158 @@ +/* + * Copyright 2004-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <float.h> // DBL_MAX, etc. +#include <math.h> // fabs() + +// Ensure plenty of characters for %f display +#define LOCAL_BUF_SIZE 2 * DBL_MAX_10_EXP + +/* + * assert_float_equal doesn't exist for older versions of cmocka installed on some + * of our builders, so define it in terms of regular assert() here in that case. + */ +#if HAVE_DECL_ASSERT_FLOAT_EQUAL == 0 +#define assert_float_equal(a, b, epsilon) assert_true(fabs((a) - (b)) < (epsilon)) +#endif + +static void +empty_input_string(void **state) +{ + double result; + + // Without default_text + assert_int_equal(pcmk__scan_double(NULL, &result, NULL, NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); + + assert_int_equal(pcmk__scan_double("", &result, NULL, NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); + + // With default_text + assert_int_equal(pcmk__scan_double(NULL, &result, "2.0", NULL), pcmk_rc_ok); + assert_float_equal(result, 2.0, DBL_EPSILON); + + assert_int_equal(pcmk__scan_double("", &result, "2.0", NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); +} + +static void +bad_input_string(void **state) +{ + double result; + + // Without default text + assert_int_equal(pcmk__scan_double("asdf", &result, NULL, NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); + + assert_int_equal(pcmk__scan_double("as2.0", &result, NULL, NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); + + // With default text (not used) + assert_int_equal(pcmk__scan_double("asdf", &result, "2.0", NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); + + assert_int_equal(pcmk__scan_double("as2.0", &result, "2.0", NULL), EINVAL); + assert_float_equal(result, PCMK__PARSE_DBL_DEFAULT, DBL_EPSILON); +} + +static void +trailing_chars(void **state) +{ + double result; + char *end_text; + + assert_int_equal(pcmk__scan_double("2.0asdf", &result, NULL, &end_text), pcmk_rc_ok); + assert_float_equal(result, 2.0, DBL_EPSILON); + assert_string_equal(end_text, "asdf"); +} + +static void +no_result_variable(void **state) +{ + pcmk__assert_asserts(pcmk__scan_double("asdf", NULL, NULL, NULL)); +} + +static void +typical_case(void **state) +{ + char str[LOCAL_BUF_SIZE]; + double result; + + assert_int_equal(pcmk__scan_double("0.0", &result, NULL, NULL), pcmk_rc_ok); + assert_float_equal(result, 0.0, DBL_EPSILON); + + assert_int_equal(pcmk__scan_double("1.0", &result, NULL, NULL), pcmk_rc_ok); + assert_float_equal(result, 1.0, DBL_EPSILON); + + assert_int_equal(pcmk__scan_double("-1.0", &result, NULL, NULL), pcmk_rc_ok); + assert_float_equal(result, -1.0, DBL_EPSILON); + + snprintf(str, LOCAL_BUF_SIZE, "%f", DBL_MAX); + assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok); + assert_float_equal(result, DBL_MAX, DBL_EPSILON); + + snprintf(str, LOCAL_BUF_SIZE, "%f", -DBL_MAX); + assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_ok); + assert_float_equal(result, -DBL_MAX, DBL_EPSILON); +} + +static void +double_overflow(void **state) +{ + char str[LOCAL_BUF_SIZE]; + double result; + + /* + * 1e(DBL_MAX_10_EXP + 1) produces an inf value + * Can't use assert_float_equal() because (inf - inf) == NaN + */ + snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MAX_10_EXP + 1); + assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW); + assert_true(result > DBL_MAX); + + snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MAX_10_EXP + 1); + assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), EOVERFLOW); + assert_true(result < -DBL_MAX); +} + +static void +double_underflow(void **state) +{ + char str[LOCAL_BUF_SIZE]; + double result; + + /* + * 1e(DBL_MIN_10_EXP - 1) produces a denormalized value (between 0 + * and DBL_MIN) + * + * C99/C11: result will be **no greater than** DBL_MIN + */ + snprintf(str, LOCAL_BUF_SIZE, "1e%d", DBL_MIN_10_EXP - 1); + assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow); + assert_true(result >= 0.0); + assert_true(result <= DBL_MIN); + + snprintf(str, LOCAL_BUF_SIZE, "-1e%d", DBL_MIN_10_EXP - 1); + assert_int_equal(pcmk__scan_double(str, &result, NULL, NULL), pcmk_rc_underflow); + assert_true(result <= 0.0); + assert_true(result >= -DBL_MIN); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_string), + cmocka_unit_test(bad_input_string), + cmocka_unit_test(trailing_chars), + cmocka_unit_test(no_result_variable), + cmocka_unit_test(typical_case), + cmocka_unit_test(double_overflow), + cmocka_unit_test(double_underflow)) diff --git a/lib/common/tests/strings/pcmk__scan_min_int_test.c b/lib/common/tests/strings/pcmk__scan_min_int_test.c new file mode 100644 index 0000000..90c3e87 --- /dev/null +++ b/lib/common/tests/strings/pcmk__scan_min_int_test.c @@ -0,0 +1,60 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +empty_input_string(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_min_int("", &result, 1), EINVAL); + assert_int_equal(result, 1); + + assert_int_equal(pcmk__scan_min_int(NULL, &result, 1), pcmk_rc_ok); + assert_int_equal(result, 1); +} + +static void +input_below_minimum(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_min_int("100", &result, 1024), pcmk_rc_ok); + assert_int_equal(result, 1024); +} + +static void +input_above_maximum(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_min_int("20000000000000000", &result, 100), EOVERFLOW); + assert_int_equal(result, INT_MAX); +} + +static void +input_just_right(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_min_int("1024", &result, 1024), pcmk_rc_ok); + assert_int_equal(result, 1024); + + assert_int_equal(pcmk__scan_min_int("2048", &result, 1024), pcmk_rc_ok); + assert_int_equal(result, 2048); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_string), + cmocka_unit_test(input_below_minimum), + cmocka_unit_test(input_above_maximum), + cmocka_unit_test(input_just_right)) diff --git a/lib/common/tests/strings/pcmk__scan_port_test.c b/lib/common/tests/strings/pcmk__scan_port_test.c new file mode 100644 index 0000000..cf927e4 --- /dev/null +++ b/lib/common/tests/strings/pcmk__scan_port_test.c @@ -0,0 +1,59 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +empty_input_string(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_port("", &result), EINVAL); + assert_int_equal(result, -1); +} + +static void +bad_input_string(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_port("abc", &result), EINVAL); + assert_int_equal(result, -1); +} + +static void +out_of_range(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_port("-1", &result), pcmk_rc_before_range); + assert_int_equal(result, -1); + assert_int_equal(pcmk__scan_port("65536", &result), pcmk_rc_after_range); + assert_int_equal(result, -1); +} + +static void +typical_case(void **state) +{ + int result; + + assert_int_equal(pcmk__scan_port("0", &result), pcmk_rc_ok); + assert_int_equal(result, 0); + + assert_int_equal(pcmk__scan_port("80", &result), pcmk_rc_ok); + assert_int_equal(result, 80); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_string), + cmocka_unit_test(bad_input_string), + cmocka_unit_test(out_of_range), + cmocka_unit_test(typical_case)) diff --git a/lib/common/tests/strings/pcmk__starts_with_test.c b/lib/common/tests/strings/pcmk__starts_with_test.c new file mode 100644 index 0000000..5429417 --- /dev/null +++ b/lib/common/tests/strings/pcmk__starts_with_test.c @@ -0,0 +1,35 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +bad_input(void **state) { + assert_false(pcmk__starts_with(NULL, "x")); + assert_false(pcmk__starts_with("abc", NULL)); +} + +static void +starts_with(void **state) { + assert_true(pcmk__starts_with("abc", "a")); + assert_true(pcmk__starts_with("abc", "ab")); + assert_true(pcmk__starts_with("abc", "abc")); + + assert_false(pcmk__starts_with("abc", "A")); + assert_false(pcmk__starts_with("abc", "bc")); + + assert_false(pcmk__starts_with("", "x")); + assert_true(pcmk__starts_with("xyz", "")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(bad_input), + cmocka_unit_test(starts_with)) diff --git a/lib/common/tests/strings/pcmk__str_any_of_test.c b/lib/common/tests/strings/pcmk__str_any_of_test.c new file mode 100644 index 0000000..bd4ae2c --- /dev/null +++ b/lib/common/tests/strings/pcmk__str_any_of_test.c @@ -0,0 +1,48 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +empty_input_list(void **state) { + assert_false(pcmk__strcase_any_of("xxx", NULL)); + assert_false(pcmk__str_any_of("xxx", NULL)); + assert_false(pcmk__strcase_any_of("", NULL)); + assert_false(pcmk__str_any_of("", NULL)); +} + +static void +empty_string(void **state) { + assert_false(pcmk__strcase_any_of("", "xxx", "yyy", NULL)); + assert_false(pcmk__str_any_of("", "xxx", "yyy", NULL)); + assert_false(pcmk__strcase_any_of(NULL, "xxx", "yyy", NULL)); + assert_false(pcmk__str_any_of(NULL, "xxx", "yyy", NULL)); +} + +static void +in_list(void **state) { + assert_true(pcmk__strcase_any_of("xxx", "aaa", "bbb", "xxx", NULL)); + assert_true(pcmk__str_any_of("xxx", "aaa", "bbb", "xxx", NULL)); + assert_true(pcmk__strcase_any_of("XXX", "aaa", "bbb", "xxx", NULL)); +} + +static void +not_in_list(void **state) { + assert_false(pcmk__strcase_any_of("xxx", "aaa", "bbb", NULL)); + assert_false(pcmk__str_any_of("xxx", "aaa", "bbb", NULL)); + assert_false(pcmk__str_any_of("AAA", "aaa", "bbb", NULL)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_list), + cmocka_unit_test(empty_string), + cmocka_unit_test(in_list), + cmocka_unit_test(not_in_list)) diff --git a/lib/common/tests/strings/pcmk__str_in_list_test.c b/lib/common/tests/strings/pcmk__str_in_list_test.c new file mode 100644 index 0000000..cff536a --- /dev/null +++ b/lib/common/tests/strings/pcmk__str_in_list_test.c @@ -0,0 +1,107 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +empty_input_list(void **state) { + assert_false(pcmk__str_in_list(NULL, NULL, pcmk__str_none)); + assert_false(pcmk__str_in_list(NULL, NULL, pcmk__str_null_matches)); + assert_false(pcmk__str_in_list("xxx", NULL, pcmk__str_none)); + assert_false(pcmk__str_in_list("", NULL, pcmk__str_none)); +} + +static void +empty_string(void **state) { + GList *list = NULL; + + list = g_list_prepend(list, (gpointer) "xxx"); + + assert_false(pcmk__str_in_list(NULL, list, pcmk__str_none)); + assert_true(pcmk__str_in_list(NULL, list, pcmk__str_null_matches)); + assert_false(pcmk__str_in_list("", list, pcmk__str_none)); + assert_false(pcmk__str_in_list("", list, pcmk__str_null_matches)); + + g_list_free(list); +} + +static void +star_matches(void **state) { + GList *list = NULL; + + list = g_list_prepend(list, (gpointer) "*"); + list = g_list_append(list, (gpointer) "more"); + + assert_true(pcmk__str_in_list("xxx", list, pcmk__str_star_matches)); + assert_true(pcmk__str_in_list("yyy", list, pcmk__str_star_matches)); + assert_true(pcmk__str_in_list("XXX", list, pcmk__str_star_matches|pcmk__str_casei)); + assert_true(pcmk__str_in_list("", list, pcmk__str_star_matches)); + + g_list_free(list); +} + +static void +star_doesnt_match(void **state) { + GList *list = NULL; + + list = g_list_prepend(list, (gpointer) "*"); + + assert_false(pcmk__str_in_list("xxx", list, pcmk__str_none)); + assert_false(pcmk__str_in_list("yyy", list, pcmk__str_none)); + assert_false(pcmk__str_in_list("XXX", list, pcmk__str_casei)); + assert_false(pcmk__str_in_list("", list, pcmk__str_none)); + assert_false(pcmk__str_in_list(NULL, list, pcmk__str_star_matches)); + + g_list_free(list); +} + +static void +in_list(void **state) { + GList *list = NULL; + + list = g_list_prepend(list, (gpointer) "xxx"); + list = g_list_prepend(list, (gpointer) "yyy"); + list = g_list_prepend(list, (gpointer) "zzz"); + + assert_true(pcmk__str_in_list("xxx", list, pcmk__str_none)); + assert_true(pcmk__str_in_list("XXX", list, pcmk__str_casei)); + assert_true(pcmk__str_in_list("yyy", list, pcmk__str_none)); + assert_true(pcmk__str_in_list("YYY", list, pcmk__str_casei)); + assert_true(pcmk__str_in_list("zzz", list, pcmk__str_none)); + assert_true(pcmk__str_in_list("ZZZ", list, pcmk__str_casei)); + + g_list_free(list); +} + +static void +not_in_list(void **state) { + GList *list = NULL; + + list = g_list_prepend(list, (gpointer) "xxx"); + list = g_list_prepend(list, (gpointer) "yyy"); + + assert_false(pcmk__str_in_list("xx", list, pcmk__str_none)); + assert_false(pcmk__str_in_list("XXX", list, pcmk__str_none)); + assert_false(pcmk__str_in_list("zzz", list, pcmk__str_none)); + assert_false(pcmk__str_in_list("zzz", list, pcmk__str_casei)); + + g_list_free(list); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input_list), + cmocka_unit_test(empty_string), + cmocka_unit_test(star_matches), + cmocka_unit_test(star_doesnt_match), + cmocka_unit_test(in_list), + cmocka_unit_test(not_in_list)) diff --git a/lib/common/tests/strings/pcmk__str_table_dup_test.c b/lib/common/tests/strings/pcmk__str_table_dup_test.c new file mode 100644 index 0000000..754bde6 --- /dev/null +++ b/lib/common/tests/strings/pcmk__str_table_dup_test.c @@ -0,0 +1,59 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +null_input_table(void **state) +{ + assert_null(pcmk__str_table_dup(NULL)); +} + +static void +empty_input_table(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + GHashTable *copy = NULL; + + copy = pcmk__str_table_dup(tbl); + assert_int_equal(g_hash_table_size(copy), 0); + + g_hash_table_destroy(tbl); + g_hash_table_destroy(copy); +} + +static void +regular_input_table(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + GHashTable *copy = NULL; + + g_hash_table_insert(tbl, strdup("abc"), strdup("123")); + g_hash_table_insert(tbl, strdup("def"), strdup("456")); + g_hash_table_insert(tbl, strdup("ghi"), strdup("789")); + + copy = pcmk__str_table_dup(tbl); + assert_int_equal(g_hash_table_size(copy), 3); + + assert_string_equal(g_hash_table_lookup(tbl, "abc"), "123"); + assert_string_equal(g_hash_table_lookup(tbl, "def"), "456"); + assert_string_equal(g_hash_table_lookup(tbl, "ghi"), "789"); + + g_hash_table_destroy(tbl); + g_hash_table_destroy(copy); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(null_input_table), + cmocka_unit_test(empty_input_table), + cmocka_unit_test(regular_input_table)) diff --git a/lib/common/tests/strings/pcmk__str_update_test.c b/lib/common/tests/strings/pcmk__str_update_test.c new file mode 100644 index 0000000..571031d --- /dev/null +++ b/lib/common/tests/strings/pcmk__str_update_test.c @@ -0,0 +1,78 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +static void +update_null(void **state) { + char *str = NULL; + + // These just make sure they don't crash + pcmk__str_update(NULL, NULL); + pcmk__str_update(NULL, "value"); + + // Update an already NULL string to NULL + pcmk__str_update(&str, NULL); + assert_null(str); + + // Update an already allocated string to NULL + str = strdup("hello"); + pcmk__str_update(&str, NULL); + assert_null(str); +} + +static void +update_same(void **state) { + char *str = NULL; + char *saved = NULL; + + str = strdup("hello"); + saved = str; + pcmk__str_update(&str, "hello"); + assert_ptr_equal(saved, str); // No free and reallocation + free(str); +} + +static void +update_different(void **state) { + char *str = NULL; + + str = strdup("hello"); + pcmk__str_update(&str, "world"); + assert_string_equal(str, "world"); + free(str); +} + +static void +strdup_fails(void **state) { + char *str = NULL; + + str = strdup("hello"); + + pcmk__assert_asserts( + { + pcmk__mock_strdup = true; // strdup() will return NULL + expect_string(__wrap_strdup, s, "world"); + pcmk__str_update(&str, "world"); + pcmk__mock_strdup = false; // Use the real strdup() + } + ); + + free(str); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(update_null), + cmocka_unit_test(update_same), + cmocka_unit_test(update_different), + cmocka_unit_test(strdup_fails)) diff --git a/lib/common/tests/strings/pcmk__strcmp_test.c b/lib/common/tests/strings/pcmk__strcmp_test.c new file mode 100644 index 0000000..a709f18 --- /dev/null +++ b/lib/common/tests/strings/pcmk__strcmp_test.c @@ -0,0 +1,80 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +same_pointer(void **state) { + const char *s1 = "abcd"; + const char *s2 = "wxyz"; + + assert_int_equal(pcmk__strcmp(s1, s1, pcmk__str_none), 0); + assert_true(pcmk__str_eq(s1, s1, pcmk__str_none)); + assert_int_not_equal(pcmk__strcmp(s1, s2, pcmk__str_none), 0); + assert_false(pcmk__str_eq(s1, s2, pcmk__str_none)); + assert_int_equal(pcmk__strcmp(NULL, NULL, pcmk__str_none), 0); +} + +static void +one_is_null(void **state) { + const char *s1 = "abcd"; + + assert_int_equal(pcmk__strcmp(s1, NULL, pcmk__str_null_matches), 0); + assert_true(pcmk__str_eq(s1, NULL, pcmk__str_null_matches)); + assert_int_equal(pcmk__strcmp(NULL, s1, pcmk__str_null_matches), 0); + assert_true(pcmk__strcmp(s1, NULL, pcmk__str_none) > 0); + assert_false(pcmk__str_eq(s1, NULL, pcmk__str_none)); + assert_true(pcmk__strcmp(NULL, s1, pcmk__str_none) < 0); +} + +static void +case_matters(void **state) { + const char *s1 = "abcd"; + const char *s2 = "ABCD"; + + assert_true(pcmk__strcmp(s1, s2, pcmk__str_none) > 0); + assert_false(pcmk__str_eq(s1, s2, pcmk__str_none)); + assert_true(pcmk__strcmp(s2, s1, pcmk__str_none) < 0); +} + +static void +case_insensitive(void **state) { + const char *s1 = "abcd"; + const char *s2 = "ABCD"; + + assert_int_equal(pcmk__strcmp(s1, s2, pcmk__str_casei), 0); + assert_true(pcmk__str_eq(s1, s2, pcmk__str_casei)); +} + +static void +regex(void **state) { + const char *s1 = "abcd"; + const char *s2 = "ABCD"; + + assert_true(pcmk__strcmp(NULL, "a..d", pcmk__str_regex) > 0); + assert_true(pcmk__strcmp(s1, NULL, pcmk__str_regex) > 0); + assert_int_equal(pcmk__strcmp(s1, "a..d", pcmk__str_regex), 0); + assert_true(pcmk__str_eq(s1, "a..d", pcmk__str_regex)); + assert_int_not_equal(pcmk__strcmp(s1, "xxyy", pcmk__str_regex), 0); + assert_false(pcmk__str_eq(s1, "xxyy", pcmk__str_regex)); + assert_int_equal(pcmk__strcmp(s2, "a..d", pcmk__str_regex|pcmk__str_casei), 0); + assert_true(pcmk__str_eq(s2, "a..d", pcmk__str_regex|pcmk__str_casei)); + assert_int_not_equal(pcmk__strcmp(s2, "a..d", pcmk__str_regex), 0); + assert_false(pcmk__str_eq(s2, "a..d", pcmk__str_regex)); + assert_true(pcmk__strcmp(s2, "*ab", pcmk__str_regex) > 0); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(same_pointer), + cmocka_unit_test(one_is_null), + cmocka_unit_test(case_matters), + cmocka_unit_test(case_insensitive), + cmocka_unit_test(regex)) diff --git a/lib/common/tests/strings/pcmk__strikey_table_test.c b/lib/common/tests/strings/pcmk__strikey_table_test.c new file mode 100644 index 0000000..d5f8635 --- /dev/null +++ b/lib/common/tests/strings/pcmk__strikey_table_test.c @@ -0,0 +1,40 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +store_strs(void **state) +{ + GHashTable *tbl = NULL; + + tbl = pcmk__strikey_table(free, free); + assert_non_null(tbl); + + assert_true(g_hash_table_insert(tbl, strdup("key-abc"), strdup("val-abc"))); + assert_int_equal(g_hash_table_size(tbl), 1); + assert_string_equal(g_hash_table_lookup(tbl, "key-abc"), "val-abc"); + + assert_false(g_hash_table_insert(tbl, strdup("key-abc"), strdup("val-def"))); + assert_int_equal(g_hash_table_size(tbl), 1); + assert_string_equal(g_hash_table_lookup(tbl, "key-abc"), "val-def"); + + assert_false(g_hash_table_insert(tbl, strdup("key-ABC"), strdup("val-ABC"))); + assert_int_equal(g_hash_table_size(tbl), 1); + assert_string_equal(g_hash_table_lookup(tbl, "key-ABC"), "val-ABC"); + + g_hash_table_destroy(tbl); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(store_strs)) diff --git a/lib/common/tests/strings/pcmk__strkey_table_test.c b/lib/common/tests/strings/pcmk__strkey_table_test.c new file mode 100644 index 0000000..ac6d92e --- /dev/null +++ b/lib/common/tests/strings/pcmk__strkey_table_test.c @@ -0,0 +1,40 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <glib.h> + +static void +store_strs(void **state) +{ + GHashTable *tbl = NULL; + + tbl = pcmk__strkey_table(free, free); + assert_non_null(tbl); + + assert_true(g_hash_table_insert(tbl, strdup("key-abc"), strdup("val-abc"))); + assert_int_equal(g_hash_table_size(tbl), 1); + assert_string_equal(g_hash_table_lookup(tbl, "key-abc"), "val-abc"); + + assert_false(g_hash_table_insert(tbl, strdup("key-abc"), strdup("val-def"))); + assert_int_equal(g_hash_table_size(tbl), 1); + assert_string_equal(g_hash_table_lookup(tbl, "key-abc"), "val-def"); + + assert_true(g_hash_table_insert(tbl, strdup("key-ABC"), strdup("val-abc"))); + assert_int_equal(g_hash_table_size(tbl), 2); + assert_string_equal(g_hash_table_lookup(tbl, "key-ABC"), "val-abc"); + + g_hash_table_destroy(tbl); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(store_strs)) diff --git a/lib/common/tests/strings/pcmk__trim_test.c b/lib/common/tests/strings/pcmk__trim_test.c new file mode 100644 index 0000000..56bdd17 --- /dev/null +++ b/lib/common/tests/strings/pcmk__trim_test.c @@ -0,0 +1,72 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include <string.h> + +static void +empty_input(void **state) +{ + char *s = strdup(""); + + assert_null(pcmk__trim(NULL)); + assert_string_equal(pcmk__trim(s), ""); + + free(s); +} + +static void +leading_newline(void **state) +{ + char *s = strdup("\nabcd"); + + assert_string_equal(pcmk__trim(s), "\nabcd"); + free(s); +} + +static void +middle_newline(void **state) +{ + char *s = strdup("ab\ncd"); + + assert_string_equal(pcmk__trim(s), "ab\ncd"); + free(s); +} + +static void +trailing_newline(void **state) +{ + char *s = strdup("abcd\n\n"); + + assert_string_equal(pcmk__trim(s), "abcd"); + free(s); + + s = strdup("abcd\n "); + assert_string_equal(pcmk__trim(s), "abcd\n "); + free(s); +} + +static void +other_whitespace(void **state) +{ + char *s = strdup(" ab\t\ncd \t"); + + assert_string_equal(pcmk__trim(s), " ab\t\ncd \t"); + free(s); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input), + cmocka_unit_test(leading_newline), + cmocka_unit_test(middle_newline), + cmocka_unit_test(trailing_newline), + cmocka_unit_test(other_whitespace)) diff --git a/lib/common/tests/utils/Makefile.am b/lib/common/tests/utils/Makefile.am new file mode 100644 index 0000000..edccf09 --- /dev/null +++ b/lib/common/tests/utils/Makefile.am @@ -0,0 +1,28 @@ +# +# Copyright 2020-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = \ + compare_version_test \ + crm_meta_name_test \ + crm_meta_value_test \ + crm_user_lookup_test \ + pcmk_daemon_user_test \ + pcmk_str_is_infinity_test \ + pcmk_str_is_minus_infinity_test \ + pcmk__getpid_s_test + +if WRAPPABLE_UNAME +check_PROGRAMS += pcmk_hostname_test +endif + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/utils/compare_version_test.c b/lib/common/tests/utils/compare_version_test.c new file mode 100644 index 0000000..35ebb63 --- /dev/null +++ b/lib/common/tests/utils/compare_version_test.c @@ -0,0 +1,55 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +empty_params(void **state) +{ + assert_int_equal(compare_version(NULL, NULL), 0); + assert_int_equal(compare_version(NULL, "abc"), -1); + assert_int_equal(compare_version(NULL, "1.0.1"), -1); + assert_int_equal(compare_version("abc", NULL), 1); + assert_int_equal(compare_version("1.0.1", NULL), 1); +} + +static void +equal_versions(void **state) +{ + assert_int_equal(compare_version("0.4.7", "0.4.7"), 0); + assert_int_equal(compare_version("1.0", "1.0"), 0); +} + +static void +unequal_versions(void **state) +{ + assert_int_equal(compare_version("0.4.7", "0.4.8"), -1); + assert_int_equal(compare_version("0.4.8", "0.4.7"), 1); + + assert_int_equal(compare_version("0.2.3", "0.3"), -1); + assert_int_equal(compare_version("0.3", "0.2.3"), 1); + + assert_int_equal(compare_version("0.99", "1.0"), -1); + assert_int_equal(compare_version("1.0", "0.99"), 1); +} + +static void +shorter_versions(void **state) +{ + assert_int_equal(compare_version("1.0", "1.0.1"), -1); + assert_int_equal(compare_version("1.0.1", "1.0"), 1); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_params), + cmocka_unit_test(equal_versions), + cmocka_unit_test(unequal_versions), + cmocka_unit_test(shorter_versions)) diff --git a/lib/common/tests/utils/crm_meta_name_test.c b/lib/common/tests/utils/crm_meta_name_test.c new file mode 100644 index 0000000..06fecc5 --- /dev/null +++ b/lib/common/tests/utils/crm_meta_name_test.c @@ -0,0 +1,41 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/msg_xml.h> + +static void +empty_params(void **state) +{ + assert_null(crm_meta_name(NULL)); +} + +static void +standard_usage(void **state) +{ + char *s = NULL; + + s = crm_meta_name(XML_RSC_ATTR_NOTIFY); + assert_string_equal(s, "CRM_meta_notify"); + free(s); + + s = crm_meta_name(XML_RSC_ATTR_STICKINESS); + assert_string_equal(s, "CRM_meta_resource_stickiness"); + free(s); + + s = crm_meta_name("blah"); + assert_string_equal(s, "CRM_meta_blah"); + free(s); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_params), + cmocka_unit_test(standard_usage)) diff --git a/lib/common/tests/utils/crm_meta_value_test.c b/lib/common/tests/utils/crm_meta_value_test.c new file mode 100644 index 0000000..0bde5c6 --- /dev/null +++ b/lib/common/tests/utils/crm_meta_value_test.c @@ -0,0 +1,56 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/msg_xml.h> + +#include <glib.h> + +static void +empty_params(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + + assert_null(crm_meta_value(NULL, NULL)); + assert_null(crm_meta_value(tbl, NULL)); + + g_hash_table_destroy(tbl); +} + +static void +key_not_in_table(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + + assert_null(crm_meta_value(tbl, XML_RSC_ATTR_NOTIFY)); + assert_null(crm_meta_value(tbl, XML_RSC_ATTR_STICKINESS)); + + g_hash_table_destroy(tbl); +} + +static void +key_in_table(void **state) +{ + GHashTable *tbl = pcmk__strkey_table(free, free); + + g_hash_table_insert(tbl, crm_meta_name(XML_RSC_ATTR_NOTIFY), strdup("1")); + g_hash_table_insert(tbl, crm_meta_name(XML_RSC_ATTR_STICKINESS), strdup("2")); + + assert_string_equal(crm_meta_value(tbl, XML_RSC_ATTR_NOTIFY), "1"); + assert_string_equal(crm_meta_value(tbl, XML_RSC_ATTR_STICKINESS), "2"); + + g_hash_table_destroy(tbl); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_params), + cmocka_unit_test(key_not_in_table), + cmocka_unit_test(key_in_table)) diff --git a/lib/common/tests/utils/crm_user_lookup_test.c b/lib/common/tests/utils/crm_user_lookup_test.c new file mode 100644 index 0000000..5842ec5 --- /dev/null +++ b/lib/common/tests/utils/crm_user_lookup_test.c @@ -0,0 +1,127 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "crmcommon_private.h" +#include "mock_private.h" + +#include <pwd.h> +#include <sys/types.h> + +static void +calloc_fails(void **state) +{ + uid_t uid; + gid_t gid; + + pcmk__mock_calloc = true; // calloc() will return NULL + + expect_value(__wrap_calloc, nmemb, 1); + expect_value(__wrap_calloc, size, PCMK__PW_BUFFER_LEN); + assert_int_equal(crm_user_lookup("hauser", &uid, &gid), -ENOMEM); + + pcmk__mock_calloc = false; // Use real calloc() +} + +static void +getpwnam_r_fails(void **state) +{ + uid_t uid; + gid_t gid; + + // Set getpwnam_r() return value and result parameter + pcmk__mock_getpwnam_r = true; + + expect_string(__wrap_getpwnam_r, name, "hauser"); + expect_any(__wrap_getpwnam_r, pwd); + expect_any(__wrap_getpwnam_r, buf); + expect_value(__wrap_getpwnam_r, buflen, PCMK__PW_BUFFER_LEN); + expect_any(__wrap_getpwnam_r, result); + will_return(__wrap_getpwnam_r, EIO); + will_return(__wrap_getpwnam_r, NULL); + + assert_int_equal(crm_user_lookup("hauser", &uid, &gid), -EIO); + + pcmk__mock_getpwnam_r = false; +} + +static void +no_matching_pwent(void **state) +{ + uid_t uid; + gid_t gid; + + // Set getpwnam_r() return value and result parameter + pcmk__mock_getpwnam_r = true; + + expect_string(__wrap_getpwnam_r, name, "hauser"); + expect_any(__wrap_getpwnam_r, pwd); + expect_any(__wrap_getpwnam_r, buf); + expect_value(__wrap_getpwnam_r, buflen, PCMK__PW_BUFFER_LEN); + expect_any(__wrap_getpwnam_r, result); + will_return(__wrap_getpwnam_r, 0); + will_return(__wrap_getpwnam_r, NULL); + + assert_int_equal(crm_user_lookup("hauser", &uid, &gid), -EINVAL); + + pcmk__mock_getpwnam_r = false; +} + +static void +entry_found(void **state) +{ + uid_t uid; + gid_t gid; + + /* We don't care about any of the other fields of the password entry, so just + * leave them blank. + */ + struct passwd returned_ent = { .pw_uid = 1000, .pw_gid = 1000 }; + + /* Test getpwnam_r returning a valid passwd entry, but we don't pass uid or gid. */ + + // Set getpwnam_r() return value and result parameter + pcmk__mock_getpwnam_r = true; + + expect_string(__wrap_getpwnam_r, name, "hauser"); + expect_any(__wrap_getpwnam_r, pwd); + expect_any(__wrap_getpwnam_r, buf); + expect_value(__wrap_getpwnam_r, buflen, PCMK__PW_BUFFER_LEN); + expect_any(__wrap_getpwnam_r, result); + will_return(__wrap_getpwnam_r, 0); + will_return(__wrap_getpwnam_r, &returned_ent); + + assert_int_equal(crm_user_lookup("hauser", NULL, NULL), 0); + + /* Test getpwnam_r returning a valid passwd entry, and we do pass uid and gid. */ + + // Set getpwnam_r() return value and result parameter + expect_string(__wrap_getpwnam_r, name, "hauser"); + expect_any(__wrap_getpwnam_r, pwd); + expect_any(__wrap_getpwnam_r, buf); + expect_value(__wrap_getpwnam_r, buflen, PCMK__PW_BUFFER_LEN); + expect_any(__wrap_getpwnam_r, result); + will_return(__wrap_getpwnam_r, 0); + will_return(__wrap_getpwnam_r, &returned_ent); + + assert_int_equal(crm_user_lookup("hauser", &uid, &gid), 0); + assert_int_equal(uid, 1000); + assert_int_equal(gid, 1000); + + pcmk__mock_getpwnam_r = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(calloc_fails), + cmocka_unit_test(getpwnam_r_fails), + cmocka_unit_test(no_matching_pwent), + cmocka_unit_test(entry_found)) diff --git a/lib/common/tests/utils/pcmk__getpid_s_test.c b/lib/common/tests/utils/pcmk__getpid_s_test.c new file mode 100644 index 0000000..20ba36a --- /dev/null +++ b/lib/common/tests/utils/pcmk__getpid_s_test.c @@ -0,0 +1,38 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +#include <sys/types.h> +#include <unistd.h> + +static void +pcmk__getpid_s_test(void **state) +{ + char *retval; + + // Set getpid() return value + pcmk__mock_getpid = true; + will_return(__wrap_getpid, 1234); + + retval = pcmk__getpid_s(); + assert_non_null(retval); + assert_string_equal("1234", retval); + + free(retval); + + pcmk__mock_getpid = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(pcmk__getpid_s_test)) diff --git a/lib/common/tests/utils/pcmk_daemon_user_test.c b/lib/common/tests/utils/pcmk_daemon_user_test.c new file mode 100644 index 0000000..a63ca73 --- /dev/null +++ b/lib/common/tests/utils/pcmk_daemon_user_test.c @@ -0,0 +1,83 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "crmcommon_private.h" +#include "mock_private.h" + +#include <pwd.h> +#include <sys/types.h> + +static void +no_matching_pwent(void **state) +{ + uid_t uid; + gid_t gid; + + // Set getpwnam_r() return value and result parameter + pcmk__mock_getpwnam_r = true; + + expect_string(__wrap_getpwnam_r, name, "hacluster"); + expect_any(__wrap_getpwnam_r, pwd); + expect_any(__wrap_getpwnam_r, buf); + expect_value(__wrap_getpwnam_r, buflen, PCMK__PW_BUFFER_LEN); + expect_any(__wrap_getpwnam_r, result); + will_return(__wrap_getpwnam_r, ENOENT); + will_return(__wrap_getpwnam_r, NULL); + + assert_int_equal(pcmk_daemon_user(&uid, &gid), -ENOENT); + + pcmk__mock_getpwnam_r = false; +} + +static void +entry_found(void **state) +{ + uid_t uid; + gid_t gid; + + /* We don't care about any of the other fields of the password entry, so just + * leave them blank. + */ + struct passwd returned_ent = { .pw_uid = 1000, .pw_gid = 1000 }; + + /* Test getpwnam_r returning a valid passwd entry, but we don't pass uid or gid. */ + + // Set getpwnam_r() return value and result parameter + pcmk__mock_getpwnam_r = true; + + expect_string(__wrap_getpwnam_r, name, "hacluster"); + expect_any(__wrap_getpwnam_r, pwd); + expect_any(__wrap_getpwnam_r, buf); + expect_value(__wrap_getpwnam_r, buflen, PCMK__PW_BUFFER_LEN); + expect_any(__wrap_getpwnam_r, result); + will_return(__wrap_getpwnam_r, 0); + will_return(__wrap_getpwnam_r, &returned_ent); + + assert_int_equal(pcmk_daemon_user(NULL, NULL), 0); + + /* Test getpwnam_r returning a valid passwd entry, and we do pass uid and gid. */ + + /* We don't need to call will_return() again because pcmk_daemon_user() + * will have cached the uid/gid from the previous call and won't make + * another call to getpwnam_r(). + */ + assert_int_equal(pcmk_daemon_user(&uid, &gid), 0); + assert_int_equal(uid, 1000); + assert_int_equal(gid, 1000); + + pcmk__mock_getpwnam_r = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(no_matching_pwent), + cmocka_unit_test(entry_found)) diff --git a/lib/common/tests/utils/pcmk_hostname_test.c b/lib/common/tests/utils/pcmk_hostname_test.c new file mode 100644 index 0000000..7329486 --- /dev/null +++ b/lib/common/tests/utils/pcmk_hostname_test.c @@ -0,0 +1,56 @@ +/* + * Copyright 2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +#include "mock_private.h" + +#include <sys/utsname.h> + +static void +uname_succeeded_test(void **state) +{ + char *retval; + + // Set uname() return value and buf parameter node name + pcmk__mock_uname = true; + + expect_any(__wrap_uname, buf); + will_return(__wrap_uname, 0); + will_return(__wrap_uname, "somename"); + + retval = pcmk_hostname(); + assert_non_null(retval); + assert_string_equal("somename", retval); + + free(retval); + + pcmk__mock_uname = false; +} + +static void +uname_failed_test(void **state) +{ + // Set uname() return value and buf parameter node name + pcmk__mock_uname = true; + + expect_any(__wrap_uname, buf); + will_return(__wrap_uname, -1); + will_return(__wrap_uname, NULL); + + assert_null(pcmk_hostname()); + + pcmk__mock_uname = false; +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(uname_succeeded_test), + cmocka_unit_test(uname_failed_test)) diff --git a/lib/common/tests/utils/pcmk_str_is_infinity_test.c b/lib/common/tests/utils/pcmk_str_is_infinity_test.c new file mode 100644 index 0000000..fff58ab --- /dev/null +++ b/lib/common/tests/utils/pcmk_str_is_infinity_test.c @@ -0,0 +1,57 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +uppercase_str_passes(void **state) +{ + assert_true(pcmk_str_is_infinity("INFINITY")); + assert_true(pcmk_str_is_infinity("+INFINITY")); +} + +static void +mixed_case_str_fails(void **state) +{ + assert_false(pcmk_str_is_infinity("infinity")); + assert_false(pcmk_str_is_infinity("+infinity")); + assert_false(pcmk_str_is_infinity("Infinity")); + assert_false(pcmk_str_is_infinity("+Infinity")); +} + +static void +added_whitespace_fails(void **state) +{ + assert_false(pcmk_str_is_infinity(" INFINITY")); + assert_false(pcmk_str_is_infinity("INFINITY ")); + assert_false(pcmk_str_is_infinity(" INFINITY ")); + assert_false(pcmk_str_is_infinity("+ INFINITY")); +} + +static void +empty_str_fails(void **state) +{ + assert_false(pcmk_str_is_infinity(NULL)); + assert_false(pcmk_str_is_infinity("")); +} + +static void +minus_infinity_fails(void **state) +{ + assert_false(pcmk_str_is_infinity("-INFINITY")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(uppercase_str_passes), + cmocka_unit_test(mixed_case_str_fails), + cmocka_unit_test(added_whitespace_fails), + cmocka_unit_test(empty_str_fails), + cmocka_unit_test(minus_infinity_fails)) diff --git a/lib/common/tests/utils/pcmk_str_is_minus_infinity_test.c b/lib/common/tests/utils/pcmk_str_is_minus_infinity_test.c new file mode 100644 index 0000000..477b055 --- /dev/null +++ b/lib/common/tests/utils/pcmk_str_is_minus_infinity_test.c @@ -0,0 +1,54 @@ +/* + * Copyright 2020-2021 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> + +static void +uppercase_str_passes(void **state) +{ + assert_true(pcmk_str_is_minus_infinity("-INFINITY")); +} + +static void +mixed_case_str_fails(void **state) +{ + assert_false(pcmk_str_is_minus_infinity("-infinity")); + assert_false(pcmk_str_is_minus_infinity("-Infinity")); +} + +static void +added_whitespace_fails(void **state) +{ + assert_false(pcmk_str_is_minus_infinity(" -INFINITY")); + assert_false(pcmk_str_is_minus_infinity("-INFINITY ")); + assert_false(pcmk_str_is_minus_infinity(" -INFINITY ")); + assert_false(pcmk_str_is_minus_infinity("- INFINITY")); +} + +static void +empty_str_fails(void **state) +{ + assert_false(pcmk_str_is_minus_infinity(NULL)); + assert_false(pcmk_str_is_minus_infinity("")); +} + +static void +infinity_fails(void **state) +{ + assert_false(pcmk_str_is_minus_infinity("INFINITY")); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(uppercase_str_passes), + cmocka_unit_test(mixed_case_str_fails), + cmocka_unit_test(added_whitespace_fails), + cmocka_unit_test(empty_str_fails), + cmocka_unit_test(infinity_fails)) diff --git a/lib/common/tests/xml/Makefile.am b/lib/common/tests/xml/Makefile.am new file mode 100644 index 0000000..0ccdcc3 --- /dev/null +++ b/lib/common/tests/xml/Makefile.am @@ -0,0 +1,17 @@ +# +# Copyright 2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__xe_foreach_child_test \ + pcmk__xe_match_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/xml/pcmk__xe_foreach_child_test.c b/lib/common/tests/xml/pcmk__xe_foreach_child_test.c new file mode 100644 index 0000000..9bcba87 --- /dev/null +++ b/lib/common/tests/xml/pcmk__xe_foreach_child_test.c @@ -0,0 +1,215 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/common/unittest_internal.h> +#include <crm/common/xml_internal.h> + +static int compare_name_handler(xmlNode *xml, void *userdata) { + function_called(); + assert_string_equal((char *) userdata, crm_element_name(xml)); + return pcmk_rc_ok; +} + +const char *str1 = + "<xml>\n" + " <!-- This is a level 1 node -->\n" + " <level1>\n" + " content\n" + " </level1>\n" + " <!-- This is a level 1 node -->\n" + " <level1>\n" + " content\n" + " </level1>\n" + " <!-- This is a level 1 node -->\n" + " <level1>\n" + " content\n" + " </level1>\n" + "</xml>"; + +static void +bad_input(void **state) { + xmlNode *xml = string2xml(str1); + + pcmk__assert_asserts(pcmk__xe_foreach_child(xml, NULL, NULL, NULL)); + + free_xml(xml); +} + +static void +name_given_test(void **state) { + xmlNode *xml = string2xml(str1); + + /* The handler should be called once for every <level1> node. */ + expect_function_call(compare_name_handler); + expect_function_call(compare_name_handler); + expect_function_call(compare_name_handler); + + pcmk__xe_foreach_child(xml, "level1", compare_name_handler, (void *) "level1"); + free_xml(xml); +} + +static void +no_name_given_test(void **state) { + xmlNode *xml = string2xml(str1); + + /* The handler should be called once for every <level1> node. */ + expect_function_call(compare_name_handler); + expect_function_call(compare_name_handler); + expect_function_call(compare_name_handler); + + pcmk__xe_foreach_child(xml, NULL, compare_name_handler, (void *) "level1"); + free_xml(xml); +} + +static void +name_doesnt_exist_test(void **state) { + xmlNode *xml = string2xml(str1); + pcmk__xe_foreach_child(xml, "xxx", compare_name_handler, NULL); + free_xml(xml); +} + +const char *str2 = + "<xml>\n" + " <level1>\n" + " <!-- Inside a level 1 node -->\n" + " <level2>\n" + " <!-- Inside a level 2 node -->\n" + " </level2>\n" + " </level1>\n" + " <level1>\n" + " <!-- Inside a level 1 node -->\n" + " <level2>\n" + " <!-- Inside a level 2 node -->\n" + " <level3>\n" + " <!-- Inside a level 3 node -->\n" + " </level3>\n" + " </level2>\n" + " <level2>\n" + " <!-- Inside a level 2 node -->\n" + " </level2>\n" + " </level1>\n" + "</xml>"; + +static void +multiple_levels_test(void **state) { + xmlNode *xml = string2xml(str2); + + /* The handler should be called once for every <level1> node. */ + expect_function_call(compare_name_handler); + expect_function_call(compare_name_handler); + + pcmk__xe_foreach_child(xml, "level1", compare_name_handler, (void *) "level1"); + free_xml(xml); +} + +static void +multiple_levels_no_name_test(void **state) { + xmlNode *xml = string2xml(str2); + + /* The handler should be called once for every <level1> node. */ + expect_function_call(compare_name_handler); + expect_function_call(compare_name_handler); + + pcmk__xe_foreach_child(xml, NULL, compare_name_handler, (void *) "level1"); + free_xml(xml); +} + +const char *str3 = + "<xml>\n" + " <!-- This is node #1 -->\n" + " <node1>\n" + " content\n" + " </node1>\n" + " <!-- This is node #2 -->\n" + " <node2>\n" + " content\n" + " </node2>\n" + " <!-- This is node #3 -->\n" + " <node3>\n" + " content\n" + " </node3>\n" + "</xml>"; + +static int any_of_handler(xmlNode *xml, void *userdata) { + function_called(); + assert_true(pcmk__str_any_of(crm_element_name(xml), "node1", "node2", "node3", NULL)); + return pcmk_rc_ok; +} + +static void +any_of_test(void **state) { + xmlNode *xml = string2xml(str3); + + /* The handler should be called once for every <nodeX> node. */ + expect_function_call(any_of_handler); + expect_function_call(any_of_handler); + expect_function_call(any_of_handler); + + pcmk__xe_foreach_child(xml, NULL, any_of_handler, NULL); + free_xml(xml); +} + +static int stops_on_first_handler(xmlNode *xml, void *userdata) { + function_called(); + + if (pcmk__str_eq(crm_element_name(xml), "node1", pcmk__str_none)) { + return pcmk_rc_error; + } else { + return pcmk_rc_ok; + } +} + +static int stops_on_second_handler(xmlNode *xml, void *userdata) { + function_called(); + + if (pcmk__str_eq(crm_element_name(xml), "node2", pcmk__str_none)) { + return pcmk_rc_error; + } else { + return pcmk_rc_ok; + } +} + +static int stops_on_third_handler(xmlNode *xml, void *userdata) { + function_called(); + + if (pcmk__str_eq(crm_element_name(xml), "node3", pcmk__str_none)) { + return pcmk_rc_error; + } else { + return pcmk_rc_ok; + } +} + +static void +one_of_test(void **state) { + xmlNode *xml = string2xml(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(NULL, NULL, + 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_match_test.c b/lib/common/tests/xml/pcmk__xe_match_test.c new file mode 100644 index 0000000..be2c949 --- /dev/null +++ b/lib/common/tests/xml/pcmk__xe_match_test.c @@ -0,0 +1,106 @@ +/* + * Copyright 2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/msg_xml.h> +#include <crm/common/unittest_internal.h> +#include <crm/common/xml_internal.h> + +const char *str1 = + "<xml>\n" + " <!-- This is an A node -->\n" + " <nodeA attrA=\"123\" " XML_ATTR_ID "=\"1\">\n" + " content\n" + " </nodeA>\n" + " <!-- This is an A node -->\n" + " <nodeA attrA=\"456\" " XML_ATTR_ID "=\"2\">\n" + " content\n" + " </nodeA>\n" + " <!-- This is an A node -->\n" + " <nodeA attrB=\"XYZ\" " XML_ATTR_ID "=\"3\">\n" + " content\n" + " </nodeA>\n" + " <!-- This is a B node -->\n" + " <nodeB attrA=\"123\" " XML_ATTR_ID "=\"4\">\n" + " content\n" + " </nodeA>\n" + " <!-- This is a B node -->\n" + " <nodeB attrB=\"ABC\" " XML_ATTR_ID "=\"5\">\n" + " content\n" + " </nodeA>\n" + "</xml>"; + +static void +bad_input(void **state) { + xmlNode *xml = string2xml(str1); + + assert_null(pcmk__xe_match(NULL, NULL, NULL, NULL)); + assert_null(pcmk__xe_match(NULL, NULL, NULL, "attrX")); + + free_xml(xml); +} + +static void +not_found(void **state) { + xmlNode *xml = string2xml(str1); + + /* No node with an attrX attribute */ + assert_null(pcmk__xe_match(xml, NULL, "attrX", NULL)); + /* No nodeX node */ + assert_null(pcmk__xe_match(xml, "nodeX", NULL, NULL)); + /* No nodeA node with attrX */ + assert_null(pcmk__xe_match(xml, "nodeA", "attrX", NULL)); + /* No nodeA node with attrA=XYZ */ + assert_null(pcmk__xe_match(xml, "nodeA", "attrA", "XYZ")); + + free_xml(xml); +} + +static void +find_attrB(void **state) { + xmlNode *xml = string2xml(str1); + xmlNode *result = NULL; + + /* Find the first node with attrB */ + result = pcmk__xe_match(xml, NULL, "attrB", NULL); + assert_non_null(result); + assert_string_equal(crm_element_value(result, "id"), "3"); + + /* Find the first nodeB with attrB */ + result = pcmk__xe_match(xml, "nodeB", "attrB", NULL); + assert_non_null(result); + assert_string_equal(crm_element_value(result, "id"), "5"); + + free_xml(xml); +} + +static void +find_attrA_matching(void **state) { + xmlNode *xml = string2xml(str1); + xmlNode *result = NULL; + + /* Find attrA=456 */ + result = pcmk__xe_match(xml, NULL, "attrA", "456"); + assert_non_null(result); + assert_string_equal(crm_element_value(result, "id"), "2"); + + /* Find a nodeB with attrA=123 */ + result = pcmk__xe_match(xml, "nodeB", "attrA", "123"); + assert_non_null(result); + assert_string_equal(crm_element_value(result, "id"), "4"); + + free_xml(xml); +} + +PCMK__UNIT_TEST(NULL, NULL, + 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/xpath/Makefile.am b/lib/common/tests/xpath/Makefile.am new file mode 100644 index 0000000..94abeee --- /dev/null +++ b/lib/common/tests/xpath/Makefile.am @@ -0,0 +1,16 @@ +# +# Copyright 2021-2022 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 $(top_srcdir)/mk/tap.mk +include $(top_srcdir)/mk/unittest.mk + +# Add "_test" to the end of all test program names to simplify .gitignore. +check_PROGRAMS = pcmk__xpath_node_id_test + +TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/xpath/pcmk__xpath_node_id_test.c b/lib/common/tests/xpath/pcmk__xpath_node_id_test.c new file mode 100644 index 0000000..3922b34 --- /dev/null +++ b/lib/common/tests/xpath/pcmk__xpath_node_id_test.c @@ -0,0 +1,59 @@ +/* + * Copyright 2021-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <crm/msg_xml.h> +#include <crm/common/unittest_internal.h> +#include <crm/common/xml_internal.h> + +static void +empty_input(void **state) { + assert_null(pcmk__xpath_node_id(NULL, "lrm")); + assert_null(pcmk__xpath_node_id("", "lrm")); + assert_null(pcmk__xpath_node_id("/blah/blah", NULL)); + assert_null(pcmk__xpath_node_id("/blah/blah", "")); + assert_null(pcmk__xpath_node_id(NULL, NULL)); +} + +static void +no_quotes(void **state) { + const char *xpath = "/some/xpath/lrm[@" XML_ATTR_ID "=xyz]"; + pcmk__assert_asserts(pcmk__xpath_node_id(xpath, "lrm")); +} + +static void +not_present(void **state) { + const char *xpath = "/some/xpath/string[@" XML_ATTR_ID "='xyz']"; + assert_null(pcmk__xpath_node_id(xpath, "lrm")); + + xpath = "/some/xpath/containing[@" XML_ATTR_ID "='lrm']"; + assert_null(pcmk__xpath_node_id(xpath, "lrm")); +} + +static void +present(void **state) { + char *s = NULL; + const char *xpath = "/some/xpath/containing/lrm[@" XML_ATTR_ID "='xyz']"; + + s = pcmk__xpath_node_id(xpath, "lrm"); + assert_int_equal(strcmp(s, "xyz"), 0); + free(s); + + xpath = "/some/other/lrm[@" XML_ATTR_ID "='xyz']/xpath"; + s = pcmk__xpath_node_id(xpath, "lrm"); + assert_int_equal(strcmp(s, "xyz"), 0); + free(s); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(empty_input), + cmocka_unit_test(no_quotes), + cmocka_unit_test(not_present), + cmocka_unit_test(present)) |