blob: 59e52dc13203c2bdcc0baffa227ffd947a98e680 [file] [log] [blame]
/*****************************************************************************\
* Copyright (C) SchedMD LLC.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <check.h>
#include "slurm/slurm_errno.h"
#include "src/common/data.h"
#include "src/common/log.h"
#include "src/common/read_config.h"
#include "src/common/slurm_protocol_defs.h"
#include "src/common/xmalloc.h"
#include "src/common/xstring.h"
#define check_with_data_get_bool_converted(str, b) \
do { \
bool bres; \
int rc; \
data_set_string(d, str); \
rc = data_get_bool_converted(d, &bres); \
ck_assert_msg(rc == 0, \
"bool convert string:%s->%s rc:%s [%d]", \
str ? str : "(null)", (b ? "true" : "false"), \
slurm_strerror(rc), rc); \
if (!rc) \
ck_assert_msg(bres == b, \
"bool converted: %s -> %s == %s", \
str ? str : "(null)", (bres ? "true" : "false"), \
(b ? "true" : "false")); \
} while (0)
static data_for_each_cmd_t
_find_dict_bool(const char *key, const data_t *data, void *arg)
{
int *found = arg;
ck_assert_msg(data_get_type(data) == DATA_TYPE_BOOL, "entry bool type");
if (data_get_bool(data))
(*found)++;
ck_assert(key != NULL);
return DATA_FOR_EACH_CONT;
}
static data_for_each_cmd_t
_invert_dict_bool(const char *key, data_t *data, void *arg)
{
ck_assert_msg(data_get_type(data) == DATA_TYPE_BOOL, "entry bool type");
ck_assert(key != NULL);
data_set_bool(data, !data_get_bool(data));
return DATA_FOR_EACH_CONT;
}
static data_for_each_cmd_t
_del_dict_bool_true(const char *key, data_t *data, void *arg)
{
int *max = arg;
ck_assert(key != NULL);
ck_assert_msg(data_get_type(data) == DATA_TYPE_BOOL, "entry bool type");
if (*max <= 0)
return DATA_FOR_EACH_STOP;
if (data_get_bool(data)) {
*max -= 1;
return DATA_FOR_EACH_DELETE;
}
return DATA_FOR_EACH_CONT;
}
static data_for_each_cmd_t _del_list_odd(data_t *data, void *arg)
{
int *max = arg;
ck_assert_msg(data_get_type(data) == DATA_TYPE_INT_64,
"entry int type");
if (*max <= 0)
return DATA_FOR_EACH_STOP;
if (data_get_int(data) % 2 == 1) {
*max -= 1;
return DATA_FOR_EACH_DELETE;
}
return DATA_FOR_EACH_CONT;
}
data_for_each_cmd_t _check_list_order(const data_t *data, void *arg)
{
int *found = arg;
ck_assert_msg(data_get_int(data) == *found,
"check value");
*found += 1;
return DATA_FOR_EACH_CONT;
}
START_TEST(test_list_iteration)
{
int max;
int found = 0;
data_t *d = data_new();
data_set_list(d);
ck_assert_msg(data_get_type(d) == DATA_TYPE_LIST, "check list type");
data_set_int(data_list_append(d), 5);
data_set_int(data_list_prepend(d), 4);
data_set_int(data_list_append(d), 6);
data_set_int(data_list_prepend(d), 3);
data_set_int(data_list_append(d), 7);
data_set_int(data_list_prepend(d), 2);
data_set_int(data_list_append(d), 8);
data_set_int(data_list_prepend(d), 1);
data_set_int(data_list_append(d), 9);
data_set_int(data_list_prepend(d), 0);
ck_assert_msg(data_get_type(d) == DATA_TYPE_LIST, "check list type");
ck_assert_msg(data_get_list_length(d) == 10, "list count");
found = 0;
ck_assert_msg(data_list_for_each_const(d, _check_list_order, &found) ==
10, "order touch count");
ck_assert_msg(found == 10, "check max found");
data_set_int(data_list_append(d), 10);
found = 0;
ck_assert_msg(data_list_for_each_const(d, _check_list_order, &found) ==
11, "order touch count");
ck_assert_msg(found == 11, "check max found");
max = 1;
data_list_for_each(d, _del_list_odd, &max);
ck_assert_msg(data_get_list_length(d) == 10, "list count");
ck_assert_msg(max == 0, "check remove count");
max = 20;
data_list_for_each(d, _del_list_odd, &max);
ck_assert_msg(data_get_list_length(d) == 6, "list count");
ck_assert_msg(max == 16, "check remove count");
FREE_NULL_DATA(d);
}
END_TEST
START_TEST(test_dict_iteration)
{
int max;
int found = 0;
data_t *d = data_new();
data_set_dict(d);
data_set_bool(data_key_set(d, "true1"), true);
data_set_bool(data_key_set(d, "true2"), true);
data_set_bool(data_key_set(d, "true3"), true);
data_set_bool(data_key_set(d, "true4"), true);
data_set_bool(data_key_set(d, "true5"), true);
data_set_bool(data_key_set(d, "false1"), false);
data_set_bool(data_key_set(d, "false2"), false);
data_set_bool(data_key_set(d, "false3"), false);
data_set_bool(data_key_set(d, "false4"), false);
data_set_bool(data_key_set(d, "false5"), false);
ck_assert_msg(data_get_dict_length(d) == 10, "dict cardinality");
ck_assert_msg(data_dict_for_each_const(d, _find_dict_bool, &found) ==
10, "find true");
ck_assert_msg(found == 5, "found true");
ck_assert_msg(data_dict_for_each(d, _invert_dict_bool, NULL) == 10,
"invert true");
ck_assert_msg(data_get_dict_length(d) == 10, "dict cardinality");
found = 0;
ck_assert_msg(data_dict_for_each_const(d, _find_dict_bool, &found) ==
10, "find true");
ck_assert_msg(found == 5, "found true");
max = 1;
data_dict_for_each(d, _del_dict_bool_true, &max);
ck_assert_msg(max == 0, "remove 1 true");
found = 0;
ck_assert_msg(data_dict_for_each_const(d, _find_dict_bool, &found) == 9,
"find true");
ck_assert_msg(found == 4, "found true");
ck_assert_msg(data_get_dict_length(d) == 9, "dict cardinality");
max = 0;
data_dict_for_each(d, _del_dict_bool_true, &max);
ck_assert_msg(max == 0, "no op remove");
ck_assert_msg(data_get_dict_length(d) == 9,
"dict cardinality after no op");
max = 4;
data_dict_for_each(d, _del_dict_bool_true, &max);
ck_assert_msg(max == 0, "remove all true");
ck_assert_msg(data_get_dict_length(d) == 5, "dict cardinality");
FREE_NULL_DATA(d);
}
END_TEST
START_TEST(test_dict_typeset)
{
data_t *d = data_new();
ck_assert_msg(data_get_type(d) == DATA_TYPE_NULL, "default type");
data_set_dict(d);
ck_assert_msg(data_get_type(d) == DATA_TYPE_DICT, "dict type");
ck_assert_msg(data_get_dict_length(d) == 0, "dict cardinality");
data_key_set(d, "test1");
data_key_set(d, "test2");
data_key_set(d, "test3");
data_key_set(d, "test4");
data_key_set(d, "test5");
ck_assert_msg(data_get_dict_length(d) == 5, "dict cardinality");
data_set_list(d);
ck_assert_msg(data_get_type(d) == DATA_TYPE_LIST, "list type");
ck_assert_msg(data_get_list_length(d) == 0, "list cardinality");
data_list_append(d);
data_list_prepend(d);
data_list_prepend(d);
data_list_append(d);
data_list_append(d);
ck_assert_msg(data_get_list_length(d) == 5, "list cardinality");
data_set_int(d, 100);
ck_assert_msg(data_get_type(d) == DATA_TYPE_INT_64, "int type");
ck_assert_msg(data_get_int(d) == 100, "check int value");
char *str = NULL;
ck_assert_msg(data_get_string_converted(d, &str) == 0,
"convert 100 to string");
ck_assert_msg(xstrcmp(str, "100") == 0, "check 100 got converted");
xfree(str);
ck_assert_msg(data_convert_type(d, DATA_TYPE_STRING) ==
DATA_TYPE_STRING, "convert 100 to string");
ck_assert_msg(data_get_type(d) == DATA_TYPE_STRING, "int type");
ck_assert_msg(xstrcmp(data_get_string(d), "100") == 0,
"check 100 got converted");
int64_t b = 0;
ck_assert_msg(data_get_int_converted(d, &b) == 0,
"convert 100 from string");
ck_assert_msg(data_get_type(d) == DATA_TYPE_STRING,
"check still string type");
ck_assert_msg(b == 100, "check string conversion from 100");
ck_assert_msg(data_convert_type(d, DATA_TYPE_INT_64) ==
DATA_TYPE_INT_64, "convert 100 from string");
ck_assert_msg(data_get_type(d) == DATA_TYPE_INT_64, "int type");
ck_assert_msg(data_get_int(d) == 100,
"check string conversion from 100");
data_set_float(d, 3.14);
ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type");
str = NULL;
ck_assert_msg(data_get_string_converted(d, &str) == 0,
"convert 3.14 to string");
ck_assert_msg(xstrcmp(str, "3.140000") == 0,
"check 3.14 got converted");
xfree(str);
ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type");
ck_assert_msg(data_convert_type(d, DATA_TYPE_FLOAT) == DATA_TYPE_FLOAT,
"convert 100 from string");
ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "int type");
ck_assert_msg(data_get_float(d) == 3.14,
"check string conversion from 3.14");
data_set_float(d, -3.14);
ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type");
str = NULL;
ck_assert_msg(data_get_string_converted(d, &str) == 0,
"convert -3.14 to string");
ck_assert_msg(xstrcmp(str, "-3.140000") == 0,
"check -3.14 got converted");
xfree(str);
ck_assert_msg(data_get_type(d) == DATA_TYPE_FLOAT, "float type");
ck_assert_msg(data_get_float(d) == -3.14,
"check string conversion from -3.14");
data_set_null(d);
ck_assert_msg(data_get_type(d) == DATA_TYPE_NULL, "default type");
FREE_NULL_DATA(d);
ck_assert_msg(d == NULL, "free check");
}
END_TEST
static data_for_each_cmd_t _list_is_index(const data_t *data, void *arg)
{
int *i_ptr = arg;
int64_t v;
ck_assert(!data_get_int_converted(data, &v));
ck_assert_int_eq(v, *i_ptr);
(*i_ptr)++;
return DATA_FOR_EACH_CONT;
}
static data_for_each_cmd_t _dict_is_index(const char *key, const data_t *data,
void *arg)
{
int *i_ptr = arg;
int64_t v;
data_t *d = data_set_string(data_new(), key);
ck_assert(data_convert_type(d, DATA_TYPE_INT_64) == DATA_TYPE_INT_64);
ck_assert(data_get_int(d) == *i_ptr);
ck_assert(!data_get_int_converted(data, &v));
ck_assert_int_eq(v, *i_ptr);
(*i_ptr)++;
return DATA_FOR_EACH_CONT;
}
START_TEST(test_convert_list_dict)
{
static const int c = 10;
data_t *d = data_set_dict(data_new());
for (int i = 0; i < c; i++)
data_set_string_fmt(data_key_set_int(d, i), "%d", i);
for (int i = 0; i < c; i++) {
int64_t v;
ck_assert(!data_get_int_converted(data_key_get_int(d, i), &v));
ck_assert_int_eq(v, i);
}
ck_assert(data_convert_type(d, DATA_TYPE_LIST) == DATA_TYPE_LIST);
ck_assert(data_get_type(d) == DATA_TYPE_LIST);
{
int i = 0;
ck_assert(data_list_for_each_const(d, _list_is_index, &i) == c);
ck_assert_int_eq(i, c);
}
ck_assert(data_convert_type(d, DATA_TYPE_DICT) == DATA_TYPE_DICT);
ck_assert(data_get_type(d) == DATA_TYPE_DICT);
{
int i = 0;
ck_assert(data_dict_for_each_const(d, _dict_is_index, &i) == c);
ck_assert_int_eq(i, c);
}
FREE_NULL_DATA(d);
}
END_TEST
START_TEST(test_detection)
{
data_t *d = data_new();
check_with_data_get_bool_converted("1", true);
check_with_data_get_bool_converted("100", true);
check_with_data_get_bool_converted("-100", true);
check_with_data_get_bool_converted("true", true);
check_with_data_get_bool_converted("taco", true);
check_with_data_get_bool_converted("0", false);
check_with_data_get_bool_converted("false", false);
check_with_data_get_bool_converted("-0", false);
check_with_data_get_bool_converted(NULL, false);
FREE_NULL_DATA(d);
}
END_TEST
Suite *suite_data(void)
{
Suite *s = suite_create("Data");
TCase *tc_core = tcase_create("Data");
tcase_add_test(tc_core, test_detection);
tcase_add_test(tc_core, test_dict_typeset);
tcase_add_test(tc_core, test_dict_iteration);
tcase_add_test(tc_core, test_list_iteration);
tcase_add_test(tc_core, test_convert_list_dict);
suite_add_tcase(s, tc_core);
return s;
}
int main(void)
{
int number_failed;
log_options_t log_opts = LOG_OPTS_INITIALIZER;
const char *debug_env = getenv("SLURM_DEBUG");
const char *debug_flags_env = getenv("SLURM_DEBUG_FLAGS");
if (debug_env)
log_opts.stderr_level = log_string2num(debug_env);
if (debug_flags_env)
debug_str2flags(debug_flags_env, &slurm_conf.debug_flags);
log_init("data-test", log_opts, 0, NULL);
SRunner *sr = srunner_create(suite_data());
srunner_run_all(sr, CK_ENV);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
log_fini();
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}