On (08/12/15 14:53), Petr Cech wrote:
On 12/07/2015 03:04 PM, Lukas Slebodnik wrote:
Plase alsoo use appropriate cmocka assertion function also on ther places We shoudl not use "==" in assertions. It's hard to debug
+2 and addressed.
LS
Thank you for carefull review.
Petr
From d6ef4adf46b52c4ef359f91eaf2cf7ea53cee78a Mon Sep 17 00:00:00 2001 From: Petr Cech pcech@redhat.com Date: Fri, 27 Nov 2015 06:39:37 -0500 Subject: [PATCH 2/2] TEST_TOOLS_COLONDB: Add tests for sss_colondb_*
There are three functions at API of colondb wrapper:
- sss_colondb_open()
- sss_colondb_readline()
- sss_colondb_writeline()
This patch adds tests for all of them.
We test those cases:
- open nonexisting file for read
- open nonexisting file for write
- open existing empty file for read
- open existing file with records for read
- open existing empty file for write
- open existing file with records for write
- write to empty file
- write to file with existing records
- sss_colondb_open()
- sss_colondb_readline()
- sss_colondb_write_line()
Resolves: https://fedorahosted.org/sssd/ticket/2764
Makefile.am | 16 ++ src/tests/cmocka/test_tools_colondb.c | 414 ++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+) create mode 100644 src/tests/cmocka/test_tools_colondb.c
diff --git a/Makefile.am b/Makefile.am index d7a6f29520980d933cf0afddf8d041b2d6f3b2ef..6763197a82a38f143436ac0be536dc29f51ad8a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -241,6 +241,7 @@ if HAVE_CMOCKA pam-srv-tests \ test_ipa_subdom_util \ test_ipa_subdom_server \
test_tools_colondb \ test_krb5_wait_queue \ test_cert_utils \ test_ldap_id_cleanup \
@@ -2556,6 +2557,21 @@ test_ipa_subdom_server_LDADD = \ libdlopen_test_providers.la \ $(NULL)
+test_tools_colondb_SOURCES = \
- src/tests/cmocka/test_tools_colondb.c \
- src/tools/common/sss_colondb.c \
- $(NULL)
+test_tools_colondb_CFLAGS = \
- $(AM_CFLAGS) \
- $(NULL)
+test_tools_colondb_LDFLAGS = \
- $(NULL)
+test_tools_colondb_LDADD = \
- $(CMOCKA_LIBS) \
- $(SSSD_INTERNAL_LTLIBS) \
- libsss_test_common.la \
- $(NULL)
test_krb5_wait_queue_SOURCES = \ src/tests/cmocka/common_mock_be.c \ src/tests/cmocka/test_krb5_wait_queue.c \ diff --git a/src/tests/cmocka/test_tools_colondb.c b/src/tests/cmocka/test_tools_colondb.c new file mode 100644 index 0000000000000000000000000000000000000000..c30085aa216d63118227fb8d8459a4a14517237d --- /dev/null +++ b/src/tests/cmocka/test_tools_colondb.c @@ -0,0 +1,414 @@ +/*
- Authors:
Petr Čech <pcech@redhat.com>
- Copyright (C) 2015 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 http://www.gnu.org/licenses/.
+*/
+#include <talloc.h> +#include <errno.h> +#include <popt.h>
+#include "tests/cmocka/common_mock.h" +#include "src/tools/common/sss_colondb.h"
+#define TESTS_PATH "tp_" BASE_FILE_STEM +#define TESTS_FILE "test_colondb.ldb"
+const char *TEST_STRING1 = "white"; +const int TEST_INT1 = 12;
+const char *TEST_STRING2 = "black"; +const int TEST_INT2 = 34;
+struct test_colondb_ctx {
- bool is_file_created;
+};
+static void create_dir(const char *path) +{
- errno_t ret;
- bool is_dir_created = false;
- ret = mkdir(path, 0775);
- is_dir_created = ! (ret != 0 && errno != EEXIST);
I'm sorry it is still combined condition. Even thought you create single variable for this. The main problem is that if it failed we do not know which part is not true and you will do not knoe value of either "ret" or "errno" in case of failure.
I also do not thick that we shoudl continue if directory exist. There can be leftover from previous test which will cause failures.
- if (!is_dir_created) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not create test directory\n");
We will not see a debug messages by default, because by default (SSSDBG_CRIT_FAILURE 0x0020) is not logged to console
So in case of failure in mock you will not see it. You will see just failed following assertions which will not be enough for analysis of failure. I would recommend to get rid of all debug messages from test. and all assertions should be unambiguous. With simple assertion you will immediately will know the root of problem from failed assertion.
- }
- assert_true(is_dir_created);
+}
+static void create_empty_file(const char *path, const char *name) +{
- TALLOC_CTX *tmp_ctx = NULL;
- char *file_name = NULL;
- FILE *fp = NULL;
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
- }
- assert_non_null(tmp_ctx);
- create_dir(path);
- file_name = talloc_asprintf(tmp_ctx, "%s/%s", path, name);
- if (file_name == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not construct colondb path\n");
- }
- assert_non_null(file_name);
- fp = fopen(file_name, "w");
- if (fp == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Could not create file %s\n", file_name);
- }
- assert_non_null(fp);
- fclose(fp);
- talloc_free(tmp_ctx);
+}
+static void create_nonempty_file(const char *path, const char *name) +{
- TALLOC_CTX *tmp_ctx = NULL;
- struct sss_colondb *db = NULL;
- struct sss_colondb_write_field table[] = {
{ SSS_COLONDB_STRING, { .str = TEST_STRING2 } },
{ SSS_COLONDB_UINT32, { .uint32 = TEST_INT2 } },
{ SSS_COLONDB_SENTINEL, { 0 } }
- };
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
- }
- assert_non_null(tmp_ctx);
- create_empty_file(TESTS_PATH, TESTS_FILE);
- db = sss_colondb_open(tmp_ctx, SSS_COLONDB_WRITE,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
- sss_colondb_writeline(db, table);
- talloc_free(tmp_ctx);
+}
+static int setup(void **state, int file_state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- assert_true(leak_check_setup());
- test_ctx = talloc_zero(global_talloc_context, struct test_colondb_ctx);
- assert_non_null(test_ctx);
- switch (file_state) {
- case 0:
test_ctx->is_file_created = false;
break;
- case 1:
create_empty_file(TESTS_PATH, TESTS_FILE);
test_ctx->is_file_created = true;
break;
- case 2:
create_nonempty_file(TESTS_PATH, TESTS_FILE);
test_ctx->is_file_created = true;
break;
- default:
test_ctx->is_file_created = false;
break;
- }
- *state = test_ctx;
- return 0;
+}
+static int without_file_setup(void **state) +{
- return setup(state, 0);
+}
+static int with_empty_file_setup(void **state) +{
- return setup(state, 1);
+}
+static int with_nonempty_file_setup(void **state) +{
- return setup(state, 2);
+}
+static int teardown(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- bool is_config_deleted = false;
- errno_t ret;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- if (test_ctx->is_file_created) {
errno = 0;
ret = unlink(TESTS_PATH "/" TESTS_FILE);
is_config_deleted = ! (ret != 0 && errno != ENOENT);
if (!is_config_deleted) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Could not delete the test config "
"ldb file [%d]: (%s)\n",
ret, sss_strerror(ret));
}
assert_true(is_config_deleted);
- }
- talloc_zfree(*state);
- test_dom_suite_cleanup(TESTS_PATH, NULL, NULL);
- assert_true(leak_check_teardown());
- return 0;
+}
+void test_open_nonexist_for_read(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- check_leaks_push(test_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_READ,
TESTS_PATH "/" TESTS_FILE);
- assert_true(check_leaks_pop(test_ctx));
- assert_null(db);
+}
+void test_open_nonexist_for_write(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- check_leaks_push(test_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_WRITE,
TESTS_PATH "/" TESTS_FILE);
- test_ctx->is_file_created = true;
if you want to clean created file. it might be better to use different teradown function. rather "sending message" in test_ctx.
- assert_true(check_leaks_pop(test_ctx));
- assert_null(db);
+}
+void test_open_exist_for_read(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_READ,
TESTS_PATH "/" TESTS_FILE);
Why this function does not have a check_leaks_push? The test test_open_nonexist_for_read has it. But I would recommend to move check leak push to setup and check_leaks_pop to teardown and you will avoid code duplication in tests.
- assert_non_null(db);
+}
+void test_open_exist_for_write(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_WRITE,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
+}
+void test_open_nonempty_for_read(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_READ,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
+}
+void test_open_nonempty_for_write(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_WRITE,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
+}
+void test_write_to_empty(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- struct sss_colondb_write_field table[] = {
{ SSS_COLONDB_STRING, { .str = TEST_STRING1 } },
{ SSS_COLONDB_UINT32, { .uint32 = TEST_INT1 } },
{ SSS_COLONDB_SENTINEL, { 0 } }
- };
- errno_t ret;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_WRITE,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
- ret = sss_colondb_writeline(db, table);
- assert_int_equal(ret, 0);
+}
+void test_write_to_nonempty(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- struct sss_colondb_write_field table[] = {
{ SSS_COLONDB_STRING, { .str = TEST_STRING1 } },
{ SSS_COLONDB_UINT32, { .uint32 = TEST_INT1 } },
{ SSS_COLONDB_SENTINEL, { 0 } }
- };
- errno_t ret;
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_WRITE,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
- ret = sss_colondb_writeline(db, table);
- assert_int_equal(ret, 0);
+}
+void test_read_from_nonempty(void **state) +{
- struct test_colondb_ctx *test_ctx = NULL;
- struct sss_colondb *db = NULL;
- errno_t ret;
- const char *string;
- uint32_t number;
- struct sss_colondb_read_field table[] = {
{ SSS_COLONDB_STRING, { .str = &string } },
{ SSS_COLONDB_UINT32, { .uint32 = &number } },
{ SSS_COLONDB_SENTINEL, { 0 } }
- };
- test_ctx = talloc_get_type_abort(*state, struct test_colondb_ctx);
- db = sss_colondb_open(test_ctx, SSS_COLONDB_READ,
TESTS_PATH "/" TESTS_FILE);
- assert_non_null(db);
- ret = sss_colondb_readline(test_ctx, db, table);
- assert_int_equal(ret, 0);
- assert_string_equal(string, TEST_STRING2);
- assert_int_equal(number, TEST_INT2);
+}
It would be also good to test SSS_COLONDB_WRITE + sss_colondb_writeline and SSS_COLONDB_READ + sss_colondb_readline in the same test. So we will check wether content didn't change meantime.
LS