From 88b23bf50dd1c12413f3314639de2c3909bd9098 Mon Sep 17 00:00:00 2001 From: Alexey Tikhonov Date: Tue, 28 Jan 2020 19:26:08 +0100 Subject: [PATCH 24/24] TESTS: added sss_ptr_hash unit test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Pavel Březina --- Makefile.am | 1 + src/tests/cmocka/test_sss_ptr_hash.c | 193 +++++++++++++++++++++++++++ src/tests/cmocka/test_utils.c | 9 ++ src/tests/cmocka/test_utils.h | 6 + 4 files changed, 209 insertions(+) create mode 100644 src/tests/cmocka/test_sss_ptr_hash.c diff --git a/Makefile.am b/Makefile.am index 57ba51356..c991f2aa0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3054,6 +3054,7 @@ test_ipa_idmap_LDADD = \ test_utils_SOURCES = \ src/tests/cmocka/test_utils.c \ src/tests/cmocka/test_string_utils.c \ + src/tests/cmocka/test_sss_ptr_hash.c \ src/p11_child/p11_child_common_utils.c \ $(NULL) if BUILD_SSH diff --git a/src/tests/cmocka/test_sss_ptr_hash.c b/src/tests/cmocka/test_sss_ptr_hash.c new file mode 100644 index 000000000..1458238f5 --- /dev/null +++ b/src/tests/cmocka/test_sss_ptr_hash.c @@ -0,0 +1,193 @@ +/* + Copyright (C) 2020 Red Hat + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see . +*/ + +#include "tests/cmocka/common_mock.h" +#include "util/sss_ptr_hash.h" + +static const int MAX_ENTRIES_AMOUNT = 5; + +static void populate_table(hash_table_t *table, int **payloads) +{ + char key[2] = {'z', 0}; + + for (int i = 0; i < MAX_ENTRIES_AMOUNT; ++i) { + payloads[i] = talloc_zero(global_talloc_context, int); + assert_non_null(payloads[i]); + *payloads[i] = i; + key[0] = '0'+(char)i; + assert_int_equal(sss_ptr_hash_add(table, key, payloads[i], int), 0); + } + + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT); +} + +static void free_payload_cb(hash_entry_t *item, hash_destroy_enum type, void *pvt) +{ + int *counter; + + assert_non_null(item); + assert_non_null(item->value.ptr); + talloc_zfree(item->value.ptr); + + assert_non_null(pvt); + counter = (int *)pvt; + (*counter)++; +} + +void test_sss_ptr_hash_with_free_cb(void **state) +{ + hash_table_t *table; + int free_counter = 0; + int *payloads[MAX_ENTRIES_AMOUNT]; + + table = sss_ptr_hash_create(global_talloc_context, + free_payload_cb, + &free_counter); + assert_non_null(table); + + populate_table(table, payloads); + + /* check explicit removal from the hash */ + sss_ptr_hash_delete(table, "1", false); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-1); + assert_int_equal(free_counter, 1); + + /* check implicit removal triggered by payload deletion */ + talloc_free(payloads[3]); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-2); + assert_int_equal(free_counter, 2); + + /* try to remove non existent entry */ + sss_ptr_hash_delete(table, "q", false); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-2); + assert_int_equal(free_counter, 2); + + /* clear all */ + sss_ptr_hash_delete_all(table, false); + assert_int_equal((int)hash_count(table), 0); + assert_int_equal(free_counter, MAX_ENTRIES_AMOUNT); + + /* check that table is still operable */ + populate_table(table, payloads); + sss_ptr_hash_delete(table, "2", false); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-1); + assert_int_equal(free_counter, MAX_ENTRIES_AMOUNT+1); + + talloc_free(table); + assert_int_equal(free_counter, MAX_ENTRIES_AMOUNT*2); +} + +struct table_wrapper +{ + hash_table_t **table; +}; + +static void lookup_cb(hash_entry_t *item, hash_destroy_enum type, void *pvt) +{ + hash_table_t *table; + hash_key_t *keys; + unsigned long count; + int *value = NULL; + int sum = 0; + + assert_non_null(pvt); + table = *((struct table_wrapper *)pvt)->table; + assert_non_null(table); + + if (type == HASH_TABLE_DESTROY) { + /* table is being destroyed */ + return; + } + + assert_int_equal(hash_keys(table, &count, &keys), HASH_SUCCESS); + for (unsigned int i = 0; i < count; ++i) { + assert_int_equal(keys[i].type, HASH_KEY_STRING); + value = sss_ptr_hash_lookup(table, keys[i].c_str, int); + assert_non_null(value); + sum += *value; + } + DEBUG(SSSDBG_TRACE_ALL, "sum of all values = %d\n", sum); + talloc_free(keys); +} + +/* main difference with `test_sss_ptr_hash_with_free_cb()` + * is that table cb here doesn't delete payload so + * this is requested via `free_value(s)` arg + */ +void test_sss_ptr_hash_with_lookup_cb(void **state) +{ + hash_table_t *table; + struct table_wrapper wrapper; + int *payloads[MAX_ENTRIES_AMOUNT]; + + wrapper.table = &table; + table = sss_ptr_hash_create(global_talloc_context, + lookup_cb, + &wrapper); + assert_non_null(table); + + populate_table(table, payloads); + + /* check explicit removal from the hash */ + sss_ptr_hash_delete(table, "2", true); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-1); + + /* check implicit removal triggered by payload deletion */ + talloc_free(payloads[0]); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-2); + + /* clear all */ + sss_ptr_hash_delete_all(table, true); + assert_int_equal((int)hash_count(table), 0); + /* teardown function shall verify there are no leaks + * on global_talloc_context and so that payloads[] were freed + */ + + /* check that table is still operable */ + populate_table(table, payloads); + + talloc_free(table); + /* d-tor triggers hash_destroy() but since cb here doesn free payload + * this should be done manually + */ + for (int i = 0; i < MAX_ENTRIES_AMOUNT; ++i) { + talloc_free(payloads[i]); + } +} + +/* Just smoke test to verify that absence of cb doesn't break anything */ +void test_sss_ptr_hash_without_cb(void **state) +{ + hash_table_t *table; + int *payloads[MAX_ENTRIES_AMOUNT]; + + table = sss_ptr_hash_create(global_talloc_context, NULL, NULL); + assert_non_null(table); + + populate_table(table, payloads); + + sss_ptr_hash_delete(table, "4", true); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-1); + + talloc_free(payloads[1]); + assert_int_equal((int)hash_count(table), MAX_ENTRIES_AMOUNT-2); + + sss_ptr_hash_delete_all(table, true); + assert_int_equal((int)hash_count(table), 0); + + talloc_free(table); +} diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c index 666f32903..c5eda4dd2 100644 --- a/src/tests/cmocka/test_utils.c +++ b/src/tests/cmocka/test_utils.c @@ -2055,6 +2055,15 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_sss_get_domain_mappings_content, setup_dom_list_with_subdomains, teardown_dom_list), + cmocka_unit_test_setup_teardown(test_sss_ptr_hash_with_free_cb, + setup_leak_tests, + teardown_leak_tests), + cmocka_unit_test_setup_teardown(test_sss_ptr_hash_with_lookup_cb, + setup_leak_tests, + teardown_leak_tests), + cmocka_unit_test_setup_teardown(test_sss_ptr_hash_without_cb, + setup_leak_tests, + teardown_leak_tests), }; /* Set debug level to invalid value so we can decide if -d 0 was used. */ diff --git a/src/tests/cmocka/test_utils.h b/src/tests/cmocka/test_utils.h index e93e0da25..44b9479f9 100644 --- a/src/tests/cmocka/test_utils.h +++ b/src/tests/cmocka/test_utils.h @@ -33,4 +33,10 @@ void test_guid_blob_to_string_buf(void **state); void test_get_last_x_chars(void **state); void test_concatenate_string_array(void **state); +/* from src/tests/cmocka/test_sss_ptr_hash.c */ +void test_sss_ptr_hash_with_free_cb(void **state); +void test_sss_ptr_hash_with_lookup_cb(void **state); +void test_sss_ptr_hash_without_cb(void **state); + + #endif /* __TESTS__CMOCKA__TEST_UTILS_H__ */ -- 2.20.1