[PATCH] Re: ldb cmocka tests

Andreas Schneider asn at samba.org
Mon Apr 10 10:13:11 UTC 2017


On Monday, 10 April 2017 00:26:06 CEST Andrew Bartlett wrote:
> On Fri, 2017-04-07 at 11:11 +0200, Andreas Schneider wrote:
> > On Friday, 7 April 2017 05:18:02 CEST Andrew Bartlett wrote:
> > > > Can you look at this cmocka test for me?  I've been writing one
> > > > to
> > > > show
> > > > the ldb_tdb locking bug in the other thread.  I like cmocka!
> > > > 
> > > > I'm not sure what the correct interaction with fork() is meant to
> > > > be,
> > > > but I've made this work for now.  
> > 
> > The test looks fine. I think the original idea of the file is to test
> > the API.
> > 
> > This test you wrote is a special case. I would put that in its own
> > binary.
> > 
> > The setup/teardown functions could be shared. 
> 
> Currently we don't have a good framework for multiple tests in ldb.  To
> split it out we need to create that, with a set of test names and a way
> to ensure we run them all.
> 
> I think we both want to get the concept of cmocka in for now, can we
> leave this for the next large test expansion?  
> 
> Otherwise, could you show how you would like it split up by splitting
> the existing test up, so I can just follow the same pattern?

Ok, lets first bring the patchset upstream.


Here is a rebased version on the third_party cmocka code which is upstream 
now. After this is upstream we can look at your additions to the ldb tests. 
Are you OK with that?


Cheers,


	Andreas

-- 
Andreas Schneider                   GPG-ID: CC014E3D
Samba Team                             asn at samba.org
www.samba.org
-------------- next part --------------
>From 9f2892b753aeb41039c852dcf4117ae8feb01f9f Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Mon, 11 May 2015 22:24:01 +0200
Subject: [PATCH 01/14] ldb_tdb: Remove unused function ltdb_add_attr_results

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/ldb_tdb/ldb_search.c | 134 -------------------------------------------
 lib/ldb/ldb_tdb/ldb_tdb.h    |   6 --
 2 files changed, 140 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_search.c b/lib/ldb/ldb_tdb/ldb_search.c
index 373855fd428..53355e04f6b 100644
--- a/lib/ldb/ldb_tdb/ldb_search.c
+++ b/lib/ldb/ldb_tdb/ldb_search.c
@@ -109,102 +109,6 @@ static int msg_add_distinguished_name(struct ldb_message *msg)
 }
 
 /*
-  add all elements from one message into another
- */
-static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *ret,
-				const struct ldb_message *msg)
-{
-	struct ldb_context *ldb;
-	unsigned int i;
-	int check_duplicates = (ret->num_elements != 0);
-
-	ldb = ldb_module_get_ctx(module);
-
-	if (msg_add_distinguished_name(ret) != 0) {
-		return -1;
-	}
-
-	for (i=0;i<msg->num_elements;i++) {
-		const struct ldb_schema_attribute *a;
-		a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
-		if (a->flags & LDB_ATTR_FLAG_HIDDEN) {
-			continue;
-		}
-		if (msg_add_element(ret, &msg->elements[i],
-				    check_duplicates) != 0) {
-			return -1;
-		}
-	}
-
-	return 0;
-}
-
-
-/*
-  pull the specified list of attributes from a message
- */
-static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, 
-					   TALLOC_CTX *mem_ctx, 
-					   const struct ldb_message *msg, 
-					   const char * const *attrs)
-{
-	struct ldb_message *ret;
-	unsigned int i;
-
-	ret = talloc(mem_ctx, struct ldb_message);
-	if (!ret) {
-		return NULL;
-	}
-
-	ret->dn = ldb_dn_copy(ret, msg->dn);
-	if (!ret->dn) {
-		talloc_free(ret);
-		return NULL;
-	}
-
-	ret->num_elements = 0;
-	ret->elements = NULL;
-
-	if (!attrs) {
-		if (msg_add_all_elements(module, ret, msg) != 0) {
-			talloc_free(ret);
-			return NULL;
-		}
-		return ret;
-	}
-
-	for (i=0;attrs[i];i++) {
-		struct ldb_message_element *el;
-
-		if (strcmp(attrs[i], "*") == 0) {
-			if (msg_add_all_elements(module, ret, msg) != 0) {
-				talloc_free(ret);
-				return NULL;
-			}
-			continue;
-		}
-
-		if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
-			if (msg_add_distinguished_name(ret) != 0) {
-				return NULL;
-			}
-			continue;
-		}
-
-		el = ldb_msg_find_element(msg, attrs[i]);
-		if (!el) {
-			continue;
-		}
-		if (msg_add_element(ret, el, 1) != 0) {
-			talloc_free(ret);
-			return NULL;				
-		}
-	}
-
-	return ret;
-}
-
-/*
   search the database for a single simple dn.
   return LDB_ERR_NO_SUCH_OBJECT on record-not-found
   and LDB_SUCCESS on success
@@ -346,44 +250,6 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes
 }
 
 /*
-  add a set of attributes from a record to a set of results
-  return 0 on success, -1 on failure
-*/
-int ltdb_add_attr_results(struct ldb_module *module, 
-			  TALLOC_CTX *mem_ctx, 
-			  struct ldb_message *msg,
-			  const char * const attrs[], 
-			  unsigned int *count, 
-			  struct ldb_message ***res)
-{
-	struct ldb_message *msg2;
-	struct ldb_message **res2;
-
-	/* pull the attributes that the user wants */
-	msg2 = ltdb_pull_attrs(module, mem_ctx, msg, attrs);
-	if (!msg2) {
-		return -1;
-	}
-
-	/* add to the results list */
-	res2 = talloc_realloc(mem_ctx, *res, struct ldb_message *, (*count)+2);
-	if (!res2) {
-		talloc_free(msg2);
-		return -1;
-	}
-
-	(*res) = res2;
-
-	(*res)[*count] = talloc_move(*res, &msg2);
-	(*res)[(*count)+1] = NULL;
-	(*count)++;
-
-	return 0;
-}
-
-
-
-/*
   filter the specified list of attributes from a message
   removing not requested attrs from the new message constructed.
 
diff --git a/lib/ldb/ldb_tdb/ldb_tdb.h b/lib/ldb/ldb_tdb/ldb_tdb.h
index 7caedebe4c7..26ae68e89c8 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.h
+++ b/lib/ldb/ldb_tdb/ldb_tdb.h
@@ -102,12 +102,6 @@ int ltdb_has_wildcard(struct ldb_module *module, const char *attr_name,
 void ltdb_search_dn1_free(struct ldb_module *module, struct ldb_message *msg);
 int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_message *msg,
 		    unsigned int unpack_flags);
-int ltdb_add_attr_results(struct ldb_module *module,
- 			  TALLOC_CTX *mem_ctx, 
-			  struct ldb_message *msg,
-			  const char * const attrs[], 
-			  unsigned int *count, 
-			  struct ldb_message ***res);
 int ltdb_filter_attrs(TALLOC_CTX *mem_ctx,
 		      const struct ldb_message *msg, const char * const *attrs,
 		      struct ldb_message **filtered_msg);
-- 
2.12.2


>From 79ac15fd5e4a85d112aec69be2e9fcfd2a7019db Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Mon, 2 Feb 2015 15:33:24 +0100
Subject: [PATCH 02/14] ldb_tdb: Remove unused function parameter

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/ldb_tdb/ldb_tdb.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index 6b1187e64ad..e1903695bf3 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -571,7 +571,6 @@ static int ltdb_msg_add_element(struct ldb_context *ldb,
   delete all elements having a specified attribute name
 */
 static int msg_delete_attribute(struct ldb_module *module,
-				struct ldb_context *ldb,
 				struct ldb_message *msg, const char *name)
 {
 	unsigned int i;
@@ -638,7 +637,7 @@ static int msg_delete_element(struct ldb_module *module,
 		}
 		if (matched) {
 			if (el->num_values == 1) {
-				return msg_delete_attribute(module, ldb, msg, name);
+				return msg_delete_attribute(module, msg, name);
 			}
 
 			ret = ltdb_index_del_value(module, msg->dn, el, i);
@@ -901,7 +900,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 				}
 
 				/* Delete the attribute if it exists in the DB */
-				if (msg_delete_attribute(module, ldb, msg2,
+				if (msg_delete_attribute(module, msg2,
 							 el->name) != 0) {
 					ret = LDB_ERR_OTHER;
 					goto done;
@@ -930,7 +929,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 
 			if (msg->elements[i].num_values == 0) {
 				/* Delete the whole attribute */
-				ret = msg_delete_attribute(module, ldb, msg2,
+				ret = msg_delete_attribute(module, msg2,
 							   msg->elements[i].name);
 				if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
 				    control_permissive) {
-- 
2.12.2


>From c715fb006b9066f9be494ee399fdb5395244c15a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Mon, 2 Feb 2015 15:48:47 +0100
Subject: [PATCH 03/14] ldb_tdb: Remove unused function parameter

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/ldb_tdb/ldb_tdb.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/lib/ldb/ldb_tdb/ldb_tdb.c b/lib/ldb/ldb_tdb/ldb_tdb.c
index e1903695bf3..c0d7a1a432b 100644
--- a/lib/ldb/ldb_tdb/ldb_tdb.c
+++ b/lib/ldb/ldb_tdb/ldb_tdb.c
@@ -526,8 +526,7 @@ static int find_element(const struct ldb_message *msg, const char *name)
 
   returns 0 on success, -1 on failure (and sets errno)
 */
-static int ltdb_msg_add_element(struct ldb_context *ldb,
-				struct ldb_message *msg,
+static int ltdb_msg_add_element(struct ldb_message *msg,
 				struct ldb_message_element *el)
 {
 	struct ldb_message_element *e2;
@@ -772,7 +771,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 			/* Checks if element already exists */
 			idx = find_element(msg2, el->name);
 			if (idx == -1) {
-				if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
+				if (ltdb_msg_add_element(msg2, el) != 0) {
 					ret = LDB_ERR_OTHER;
 					goto done;
 				}
@@ -908,7 +907,7 @@ int ltdb_modify_internal(struct ldb_module *module,
 			}
 
 			/* Recreate it with the new values */
-			if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
+			if (ltdb_msg_add_element(msg2, el) != 0) {
 				ret = LDB_ERR_OTHER;
 				goto done;
 			}
-- 
2.12.2


>From c1abc5d6da197ab6efaa7327affd396beae3731a Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Fri, 16 Jan 2015 18:52:48 +0100
Subject: [PATCH 04/14] ldb: Clarify LDB_MODULES_PATH is used

Make it (hopefully more) clear where modules are loaded from.

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/include/ldb.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h
index afcf9eb6351..1160a48cc06 100644
--- a/lib/ldb/include/ldb.h
+++ b/lib/ldb/include/ldb.h
@@ -1056,6 +1056,10 @@ int ldb_global_init(void);
   \param mem_ctx pointer to a talloc memory context. Pass NULL if there is
   no suitable context available.
 
+  \note The LDB modules will be loaded from directory specified by the environment
+  variable LDB_MODULES_PATH. If the variable is not specified, the compiled-in default
+  is used.
+
   \return pointer to ldb_context that should be free'd (using talloc_free())
   at the end of the program.
 */
-- 
2.12.2


>From ab00efdc6117056e88b75ee1104468f5a3e28631 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Sat, 17 Jan 2015 18:06:09 +0100
Subject: [PATCH 05/14] ldb:tests: Add a simple cmocka test for ldb_connect()

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 107 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100644 lib/ldb/tests/ldb_mod_op_test.c

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
new file mode 100644
index 00000000000..afd47a9773d
--- /dev/null
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -0,0 +1,107 @@
+/*
+ * from cmocka.c:
+ * These headers or their equivalents should be included prior to
+ * including
+ * this header file.
+ *
+ * #include <stdarg.h>
+ * #include <stddef.h>
+ * #include <setjmp.h>
+ *
+ * This allows test applications to use custom definitions of C standard
+ * library functions and types.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <cmocka.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <ldb.h>
+
+#define DEFAULT_BE  "tdb"
+
+#ifndef TEST_BE
+#define TEST_BE DEFAULT_BE
+#endif /* TEST_BE */
+
+struct ldbtest_ctx {
+	struct tevent_context *ev;
+	struct ldb_context *ldb;
+
+	const char *dbfile;
+	const char *lockfile;
+
+	const char *dbpath;
+	const char *lockpath;   /* lockfile is separate */
+};
+
+static int ldbtest_noconn_setup(void **state)
+{
+	struct ldbtest_ctx *test_ctx;
+
+	test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+	assert_non_null(test_ctx);
+
+	test_ctx->ev = tevent_context_init(test_ctx);
+	assert_non_null(test_ctx->ev);
+
+	test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+	assert_non_null(test_ctx->ldb);
+
+	test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+	assert_non_null(test_ctx->dbfile);
+
+	test_ctx->lockfile = talloc_asprintf(test_ctx,
+					     "%s-lock", test_ctx->dbfile);
+	assert_non_null(test_ctx->lockfile);
+
+	test_ctx->dbpath = talloc_asprintf(test_ctx,
+					  TEST_BE"://%s", test_ctx->dbfile);
+	assert_non_null(test_ctx->dbpath);
+
+	test_ctx->lockpath = talloc_asprintf(test_ctx,
+					     "%s-lock", test_ctx->dbpath);
+	assert_non_null(test_ctx->lockpath);
+
+	*state = test_ctx;
+	return 0;
+}
+
+static int ldbtest_noconn_teardown(void **state)
+{
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+
+	unlink(test_ctx->lockfile);
+
+	unlink(test_ctx->dbfile);
+
+	talloc_free(test_ctx);
+	return 0;
+}
+
+static void test_connect(void **state)
+{
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+	int ret;
+
+	ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+	assert_int_equal(ret, 0);
+}
+
+int main(int argc, const char **argv)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test_setup_teardown(test_connect,
+						ldbtest_noconn_setup,
+						ldbtest_noconn_teardown),
+	};
+
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
-- 
2.12.2


>From 9f196ead7716341db9524af5dcb58052584e03ee Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn at samba.org>
Date: Fri, 2 Oct 2015 11:36:50 +0200
Subject: [PATCH 06/14] ldb:tests: Build a ldb test for the tdb backend

Pair-Programmed-With: Andrew Bartlet <abartlet at samba.org>

Signed-off-by: Andreas Schneider <asn at samba.org>
Signed-off-by: Andrew Bartlet <abartlet at samba.org>
---
 lib/ldb/wscript | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)

diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index c877f3bc7f6..14a13fdce00 100644
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -35,12 +35,18 @@ def configure(conf):
 
     if conf.CHECK_FOR_THIRD_PARTY():
         conf.RECURSE('third_party/popt')
+        conf.RECURSE('third_party/cmocka')
     else:
         if not conf.CHECK_POPT():
             raise Utils.WafError('popt development packages have not been found.\nIf third_party is installed, check that it is in the proper place.')
         else:
             conf.define('USING_SYSTEM_POPT', 1)
 
+        if not conf.CHECK_CMOCKA():
+            raise Utils.WafError('cmocka development package have not been found.\nIf third_party is installed, check that it is in the proper place.')
+        else:
+            conf.define('USING_SYSTEM_CMOCKA', 1)
+
     conf.RECURSE('lib/replace')
     conf.find_program('python', var='PYTHON')
     conf.find_program('xsltproc', var='XSLTPROC')
@@ -107,6 +113,7 @@ def build(bld):
 
     if bld.CHECK_FOR_THIRD_PARTY():
         bld.RECURSE('third_party/popt')
+        bld.RECURSE('third_party/cmocka')
 
     bld.RECURSE('lib/replace')
     bld.RECURSE('lib/tdb')
@@ -307,14 +314,23 @@ def build(bld):
                           deps='ldb dl popt',
                           private_library=True)
 
+    bld.SAMBA_BINARY('ldb_tdb_mod_op_test',
+                     source='tests/ldb_mod_op_test.c',
+                     cflags='-DTEST_BE=\"tdb\"',
+                     deps='cmocka ldb',
+                     install=False)
 
 def test(ctx):
     '''run ldb testsuite'''
     import Utils, samba_utils, shutil
+    env = samba_utils.LOAD_ENVIRONMENT()
+    ctx.env = env
+
     test_prefix = "%s/st" % (Utils.g_module.blddir)
     shutil.rmtree(test_prefix, ignore_errors=True)
     os.makedirs(test_prefix)
     os.environ['TEST_DATA_PREFIX'] = test_prefix
+    os.environ['LD_LIBRARY_PATH'] = Utils.g_module.blddir + '/bin/default/lib/ldb'
     cmd = 'tests/test-tdb.sh %s' % Utils.g_module.blddir
     ret = samba_utils.RUN_COMMAND(cmd)
     print("testsuite returned %d" % ret)
@@ -326,7 +342,13 @@ def test(ctx):
         ['tests/python/api.py'],
         extra_env={'SELFTEST_PREFIX': test_prefix})
     print("Python testsuite returned %d" % pyret)
-    sys.exit(ret or pyret)
+
+    os.environ['LDB_MODULES_PATH'] = Utils.g_module.blddir + '/modules/ldb'
+    os.environ['LD_LIBRARY_PATH'] = Utils.g_module.blddir + '/bin/default/lib/ldb'
+    cmd = Utils.g_module.blddir + '/ldb_tdb_mod_op_test'
+    cmocka_ret = samba_utils.RUN_COMMAND(cmd)
+
+    sys.exit(ret or pyret or cmocka_ret)
 
 def dist():
     '''makes a tarball for distribution'''
-- 
2.12.2


>From bbdb3975ac9cb5aaec4d0736972cce6b7aba23b9 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Tue, 15 Sep 2015 22:39:08 +0200
Subject: [PATCH 07/14] ldb:tests: A rudimentary ldb_add() test

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 51 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index afd47a9773d..fe6a0e8af63 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -95,12 +95,63 @@ static void test_connect(void **state)
 	assert_int_equal(ret, 0);
 }
 
+static int ldbtest_setup(void **state)
+{
+	struct ldbtest_ctx *test_ctx;
+	int ret;
+
+	ldbtest_noconn_setup((void **) &test_ctx);
+
+	ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+	assert_int_equal(ret, 0);
+
+	*state = test_ctx;
+	return 0;
+}
+
+static int ldbtest_teardown(void **state)
+{
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+	ldbtest_noconn_teardown((void **) &test_ctx);
+	return 0;
+}
+
+static void test_ldb_add(void **state)
+{
+	int ret;
+	struct ldb_message *msg;
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+	TALLOC_CTX *tmp_ctx;
+
+	tmp_ctx = talloc_new(test_ctx);
+	assert_non_null(tmp_ctx);
+
+	msg = ldb_msg_new(tmp_ctx);
+	assert_non_null(msg);
+
+	msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test");
+	assert_non_null(msg->dn);
+
+	ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
+	assert_int_equal(ret, 0);
+
+	ret = ldb_add(test_ctx->ldb, msg);
+	assert_int_equal(ret, 0);
+
+	talloc_free(tmp_ctx);
+}
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
 		cmocka_unit_test_setup_teardown(test_connect,
 						ldbtest_noconn_setup,
 						ldbtest_noconn_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_add,
+						ldbtest_setup,
+						ldbtest_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From e50028432a22bcc4e0db48fc8c170fa65e40875b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Sat, 2 May 2015 15:01:13 +0200
Subject: [PATCH 08/14] ldb:tests: Add a basic search test

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 72 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index fe6a0e8af63..1396c16836d 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -143,6 +143,75 @@ static void test_ldb_add(void **state)
 	talloc_free(tmp_ctx);
 }
 
+static void test_ldb_search(void **state)
+{
+	int ret;
+	struct ldb_message *msg;
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+	TALLOC_CTX *tmp_ctx;
+	struct ldb_dn *basedn;
+	struct ldb_dn *basedn2;
+	struct ldb_result *result = NULL;
+
+	tmp_ctx = talloc_new(test_ctx);
+	assert_non_null(tmp_ctx);
+
+	basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test");
+	assert_non_null(basedn);
+
+	ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+			 LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 0);
+
+	msg = ldb_msg_new(tmp_ctx);
+	assert_non_null(msg);
+
+	msg->dn = basedn;
+	assert_non_null(msg->dn);
+
+	ret = ldb_msg_add_string(msg, "cn", "test_cn_val1");
+	assert_int_equal(ret, 0);
+
+	ret = ldb_add(test_ctx->ldb, msg);
+	assert_int_equal(ret, 0);
+
+	basedn2 = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "dc=test2");
+	assert_non_null(basedn2);
+
+	msg = ldb_msg_new(tmp_ctx);
+	assert_non_null(msg);
+
+	msg->dn = basedn2;
+	assert_non_null(msg->dn);
+
+	ret = ldb_msg_add_string(msg, "cn", "test_cn_val2");
+	assert_int_equal(ret, 0);
+
+	ret = ldb_add(test_ctx->ldb, msg);
+	assert_int_equal(ret, 0);
+
+	ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+			 LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 1);
+	assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+			    ldb_dn_get_linearized(basedn));
+
+	ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn2,
+			 LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 1);
+	assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+			    ldb_dn_get_linearized(basedn2));
+
+	talloc_free(tmp_ctx);
+}
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
@@ -152,6 +221,9 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_ldb_add,
 						ldbtest_setup,
 						ldbtest_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_search,
+						ldbtest_setup,
+						ldbtest_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From b398763d7ac6d2658710cd3146e1a709c0397b79 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Tue, 20 Jan 2015 12:11:34 +0100
Subject: [PATCH 09/14] ldb:tests: Add a basic delete test

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 134 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 121 insertions(+), 13 deletions(-)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 1396c16836d..3f4b49fe8ab 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -34,12 +34,28 @@ struct ldbtest_ctx {
 	struct ldb_context *ldb;
 
 	const char *dbfile;
-	const char *lockfile;
+	const char *lockfile;   /* lockfile is separate */
 
 	const char *dbpath;
-	const char *lockpath;   /* lockfile is separate */
 };
 
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+	int ret;
+
+	errno = 0;
+	ret = unlink(test_ctx->lockfile);
+	if (ret == -1 && errno != ENOENT) {
+		fail();
+	}
+
+	errno = 0;
+	ret = unlink(test_ctx->dbfile);
+	if (ret == -1 && errno != ENOENT) {
+		fail();
+	}
+}
+
 static int ldbtest_noconn_setup(void **state)
 {
 	struct ldbtest_ctx *test_ctx;
@@ -56,18 +72,15 @@ static int ldbtest_noconn_setup(void **state)
 	test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
 	assert_non_null(test_ctx->dbfile);
 
-	test_ctx->lockfile = talloc_asprintf(test_ctx,
-					     "%s-lock", test_ctx->dbfile);
+	test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+					     test_ctx->dbfile);
 	assert_non_null(test_ctx->lockfile);
 
 	test_ctx->dbpath = talloc_asprintf(test_ctx,
-					  TEST_BE"://%s", test_ctx->dbfile);
+			TEST_BE"://%s", test_ctx->dbfile);
 	assert_non_null(test_ctx->dbpath);
 
-	test_ctx->lockpath = talloc_asprintf(test_ctx,
-					     "%s-lock", test_ctx->dbpath);
-	assert_non_null(test_ctx->lockpath);
-
+	unlink_old_db(test_ctx);
 	*state = test_ctx;
 	return 0;
 }
@@ -77,10 +90,7 @@ static int ldbtest_noconn_teardown(void **state)
 	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
 							struct ldbtest_ctx);
 
-	unlink(test_ctx->lockfile);
-
-	unlink(test_ctx->dbfile);
-
+	unlink_old_db(test_ctx);
 	talloc_free(test_ctx);
 	return 0;
 }
@@ -212,6 +222,98 @@ static void test_ldb_search(void **state)
 	talloc_free(tmp_ctx);
 }
 
+static int base_search_count(struct ldbtest_ctx *test_ctx, const char *entry_dn)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+	int ret;
+	int count;
+
+	tmp_ctx = talloc_new(test_ctx);
+	assert_non_null(tmp_ctx);
+
+	basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", entry_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+			 LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, LDB_SUCCESS);
+	assert_non_null(result);
+
+	count = result->count;
+	talloc_free(tmp_ctx);
+	return count;
+}
+
+static void assert_dn_exists(struct ldbtest_ctx *test_ctx,
+			     const char *entry_dn)
+{
+	int count;
+
+	count = base_search_count(test_ctx, entry_dn);
+	assert_int_equal(count, 1);
+}
+
+static void assert_dn_doesnt_exist(struct ldbtest_ctx *test_ctx,
+				   const char *entry_dn)
+{
+	int count;
+
+	count = base_search_count(test_ctx, entry_dn);
+	assert_int_equal(count, 0);
+}
+
+static void test_ldb_del(void **state)
+{
+	int ret;
+	struct ldb_message *msg;
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+	TALLOC_CTX *tmp_ctx;
+	const char *basedn = "dc=ldb_del_test";
+
+	tmp_ctx = talloc_new(test_ctx);
+	assert_non_null(tmp_ctx);
+
+	assert_dn_doesnt_exist(test_ctx, basedn);
+
+	msg = ldb_msg_new(tmp_ctx);
+	assert_non_null(msg);
+
+	msg->dn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", basedn);
+	assert_non_null(msg->dn);
+
+	ret = ldb_msg_add_string(msg, "cn", "test_del_cn_val");
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	ret = ldb_add(test_ctx->ldb, msg);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	assert_dn_exists(test_ctx, basedn);
+
+	ret = ldb_delete(test_ctx->ldb, msg->dn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	assert_dn_doesnt_exist(test_ctx, basedn);
+
+	talloc_free(tmp_ctx);
+}
+
+static void test_ldb_del_noexist(void **state)
+{
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							     struct ldbtest_ctx);
+	struct ldb_dn *basedn;
+	int ret;
+
+	basedn = ldb_dn_new(test_ctx, test_ctx->ldb, "dc=nosuchplace");
+	assert_non_null(basedn);
+
+	ret = ldb_delete(test_ctx->ldb, basedn);
+	assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+}
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
@@ -224,6 +326,12 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_ldb_search,
 						ldbtest_setup,
 						ldbtest_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_del,
+						ldbtest_setup,
+						ldbtest_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_del_noexist,
+						ldbtest_setup,
+						ldbtest_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From c79c98410b57a1da56a5b93e082ef58891dd18a0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Fri, 25 Sep 2015 07:02:12 +0200
Subject: [PATCH 10/14] ldb:tests: Add a test for ldb transactions

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 80 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 3f4b49fe8ab..89561fff9ca 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -314,6 +314,83 @@ static void test_ldb_del_noexist(void **state)
 	assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
 }
 
+static void add_keyval(struct ldbtest_ctx *test_ctx,
+		       const char *key,
+		       const char *val)
+{
+	int ret;
+	struct ldb_message *msg;
+
+	msg = ldb_msg_new(test_ctx);
+	assert_non_null(msg);
+
+	msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "%s=%s", key, val);
+	assert_non_null(msg->dn);
+
+	ret = ldb_msg_add_string(msg, key, val);
+	assert_int_equal(ret, 0);
+
+	ret = ldb_add(test_ctx->ldb, msg);
+	assert_int_equal(ret, 0);
+
+	talloc_free(msg);
+}
+
+static struct ldb_result *get_keyval(struct ldbtest_ctx *test_ctx,
+				     const char *key,
+				     const char *val)
+{
+	int ret;
+	struct ldb_result *result;
+	struct ldb_dn *basedn;
+
+	basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "%s=%s", key, val);
+	assert_non_null(basedn);
+
+	ret = ldb_search(test_ctx->ldb, test_ctx, &result, basedn,
+			LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, 0);
+
+	return result;
+}
+
+static void test_transactions(void **state)
+{
+	int ret;
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+			struct ldbtest_ctx);
+	struct ldb_result *res;
+
+	/* start lev-0 transaction */
+	ret = ldb_transaction_start(test_ctx->ldb);
+	assert_int_equal(ret, 0);
+
+	add_keyval(test_ctx, "vegetable", "carrot");
+
+	/* commit lev-0 transaction */
+	ret = ldb_transaction_commit(test_ctx->ldb);
+	assert_int_equal(ret, 0);
+
+	/* start another lev-1 nested transaction */
+	ret = ldb_transaction_start(test_ctx->ldb);
+	assert_int_equal(ret, 0);
+
+	add_keyval(test_ctx, "fruit", "apple");
+
+	/* abort lev-1 nested transaction */
+	ret = ldb_transaction_cancel(test_ctx->ldb);
+	assert_int_equal(ret, 0);
+
+	res = get_keyval(test_ctx, "vegetable", "carrot");
+	assert_non_null(res);
+	assert_int_equal(res->count, 1);
+
+	res = get_keyval(test_ctx, "fruit", "apple");
+	assert_non_null(res);
+	assert_int_equal(res->count, 0);
+}
+
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
@@ -332,6 +409,9 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_ldb_del_noexist,
 						ldbtest_setup,
 						ldbtest_teardown),
+		cmocka_unit_test_setup_teardown(test_transactions,
+						ldbtest_setup,
+						ldbtest_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From 23fbe618a1dec330fbea11c1eab1277c8c85a8c0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Sat, 3 Oct 2015 20:43:45 +0200
Subject: [PATCH 11/14] ldb:tests: Add a modify test

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 423 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 423 insertions(+)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 89561fff9ca..065bd60a55b 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -390,6 +390,402 @@ static void test_transactions(void **state)
 	assert_int_equal(res->count, 0);
 }
 
+struct ldb_mod_test_ctx {
+	struct ldbtest_ctx *ldb_test_ctx;
+	const char *entry_dn;
+};
+
+struct keyval {
+	const char *key;
+	const char *val;
+};
+
+static struct ldb_message *build_mod_msg(TALLOC_CTX *mem_ctx,
+					 struct ldbtest_ctx *test_ctx,
+					 const char *dn,
+					 int modify_flags,
+					 struct keyval *kvs)
+{
+	struct ldb_message *msg;
+	int ret;
+	int i;
+
+	msg = ldb_msg_new(mem_ctx);
+	assert_non_null(msg);
+
+	msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "%s", dn);
+	assert_non_null(msg->dn);
+
+	for (i = 0; kvs[i].key != NULL; i++) {
+		if (modify_flags) {
+			ret = ldb_msg_add_empty(msg, kvs[i].key,
+						modify_flags, NULL);
+			assert_int_equal(ret, 0);
+		}
+
+		if (kvs[i].val) {
+			ret = ldb_msg_add_string(msg, kvs[i].key, kvs[i].val);
+			assert_int_equal(ret, LDB_SUCCESS);
+		}
+	}
+
+	return msg;
+}
+
+static void mod_test_add_data(struct ldb_mod_test_ctx *mod_test_ctx,
+			      struct keyval *kvs)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct ldb_message *msg;
+	struct ldb_result *result = NULL;
+	struct ldbtest_ctx *ldb_test_ctx;
+	int ret;
+
+	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+	tmp_ctx = talloc_new(mod_test_ctx);
+	assert_non_null(tmp_ctx);
+
+	msg = build_mod_msg(tmp_ctx, ldb_test_ctx,
+			    mod_test_ctx->entry_dn, 0, kvs);
+	assert_non_null(msg);
+
+	ret = ldb_add(ldb_test_ctx->ldb, msg);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	ret = ldb_search(ldb_test_ctx->ldb, tmp_ctx, &result, msg->dn,
+			 LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, LDB_SUCCESS);
+	assert_non_null(result);
+	assert_int_equal(result->count, 1);
+	assert_string_equal(ldb_dn_get_linearized(result->msgs[0]->dn),
+			    ldb_dn_get_linearized(msg->dn));
+
+	talloc_free(tmp_ctx);
+}
+
+static void mod_test_remove_data(struct ldb_mod_test_ctx *mod_test_ctx)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+	int ret;
+	struct ldbtest_ctx *ldb_test_ctx;
+
+	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+	tmp_ctx = talloc_new(mod_test_ctx);
+	assert_non_null(tmp_ctx);
+
+	basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
+				"%s", mod_test_ctx->entry_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_delete(ldb_test_ctx->ldb, basedn);
+	assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_NO_SUCH_OBJECT);
+
+	ret = ldb_search(ldb_test_ctx->ldb, tmp_ctx, &result, basedn,
+			LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, LDB_SUCCESS);
+	assert_non_null(result);
+	assert_int_equal(result->count, 0);
+
+	talloc_free(tmp_ctx);
+}
+
+static struct ldb_result *run_mod_test(struct ldb_mod_test_ctx *mod_test_ctx,
+				       int modify_flags,
+				       struct keyval *kvs)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct ldb_result *res;
+	struct ldb_message *mod_msg;
+	struct ldb_dn *basedn;
+	struct ldbtest_ctx *ldb_test_ctx;
+	int ret;
+
+	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+	tmp_ctx = talloc_new(mod_test_ctx);
+	assert_non_null(tmp_ctx);
+
+	mod_msg = build_mod_msg(tmp_ctx, ldb_test_ctx, mod_test_ctx->entry_dn,
+				modify_flags, kvs);
+	assert_non_null(mod_msg);
+
+	ret = ldb_modify(ldb_test_ctx->ldb, mod_msg);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
+			"%s", mod_test_ctx->entry_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(ldb_test_ctx->ldb, mod_test_ctx, &res, basedn,
+			 LDB_SCOPE_BASE, NULL, NULL);
+	assert_int_equal(ret, LDB_SUCCESS);
+	assert_non_null(res);
+	assert_int_equal(res->count, 1);
+	assert_string_equal(ldb_dn_get_linearized(res->msgs[0]->dn),
+			    ldb_dn_get_linearized(mod_msg->dn));
+
+	talloc_free(tmp_ctx);
+	return res;
+}
+
+static int ldb_modify_test_setup(void **state)
+{
+	struct ldbtest_ctx *ldb_test_ctx;
+	struct ldb_mod_test_ctx *mod_test_ctx;
+	struct keyval kvs[] = {
+		{ "cn", "test_mod_cn" },
+		{ NULL, NULL },
+	};
+
+	ldbtest_setup((void **) &ldb_test_ctx);
+
+	mod_test_ctx = talloc(ldb_test_ctx, struct ldb_mod_test_ctx);
+	assert_non_null(mod_test_ctx);
+
+	mod_test_ctx->entry_dn = "dc=mod_test_entry";
+	mod_test_ctx->ldb_test_ctx = ldb_test_ctx;
+
+	mod_test_remove_data(mod_test_ctx);
+	mod_test_add_data(mod_test_ctx, kvs);
+	*state = mod_test_ctx;
+	return 0;
+}
+
+static int ldb_modify_test_teardown(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+				talloc_get_type_abort(*state,
+						      struct ldb_mod_test_ctx);
+	struct ldbtest_ctx *ldb_test_ctx;
+
+	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+	mod_test_remove_data(mod_test_ctx);
+	talloc_free(mod_test_ctx);
+
+	ldbtest_teardown((void **) &ldb_test_ctx);
+	return 0;
+}
+
+static void test_ldb_modify_add_key(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+				talloc_get_type_abort(*state,
+						      struct ldb_mod_test_ctx);
+	struct keyval mod_kvs[] = {
+		{ "name", "test_mod_name" },
+		{ NULL, NULL },
+	};
+	struct ldb_result *res;
+	struct ldb_message_element *el;
+
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_ADD, mod_kvs);
+	assert_non_null(res);
+
+	/* Check cn is intact and name was added */
+	assert_int_equal(res->count, 1);
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_non_null(el);
+	assert_int_equal(el->num_values, 1);
+	assert_string_equal(el->values[0].data, "test_mod_cn");
+
+	el = ldb_msg_find_element(res->msgs[0], "name");
+	assert_non_null(el);
+	assert_int_equal(el->num_values, 1);
+	assert_string_equal(el->values[0].data, "test_mod_name");
+}
+
+static void test_ldb_modify_extend_key(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct keyval mod_kvs[] = {
+		{ "cn", "test_mod_cn2" },
+		{ NULL, NULL },
+	};
+	struct ldb_result *res;
+	struct ldb_message_element *el;
+
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_ADD, mod_kvs);
+	assert_non_null(res);
+
+	/* Check cn was extended with another value */
+	assert_int_equal(res->count, 1);
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_non_null(el);
+	assert_int_equal(el->num_values, 2);
+	assert_string_equal(el->values[0].data, "test_mod_cn");
+	assert_string_equal(el->values[1].data, "test_mod_cn2");
+}
+
+static void test_ldb_modify_add_key_noval(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct ldb_message *mod_msg;
+	struct ldbtest_ctx *ldb_test_ctx;
+	struct ldb_message_element *el;
+	int ret;
+
+	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
+
+	mod_msg = ldb_msg_new(mod_test_ctx);
+	assert_non_null(mod_msg);
+
+	mod_msg->dn = ldb_dn_new_fmt(mod_msg, ldb_test_ctx->ldb,
+			"%s", mod_test_ctx->entry_dn);
+	assert_non_null(mod_msg->dn);
+
+	el = talloc_zero(mod_msg, struct ldb_message_element);
+	el->flags = LDB_FLAG_MOD_ADD;
+	assert_non_null(el);
+	el->name = talloc_strdup(el, "cn");
+	assert_non_null(el->name);
+
+	mod_msg->elements = el;
+	mod_msg->num_elements = 1;
+
+	ret = ldb_modify(ldb_test_ctx->ldb, mod_msg);
+	assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+}
+
+static void test_ldb_modify_replace_key(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	const char *new_cn = "new_cn";
+	struct keyval mod_kvs[] = {
+		{ "cn", new_cn },
+		{ NULL, NULL },
+	};
+	struct ldb_result *res;
+	struct ldb_message_element *el;
+
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, mod_kvs);
+	assert_non_null(res);
+
+	/* Check cn was replaced */
+	assert_int_equal(res->count, 1);
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_non_null(el);
+	assert_int_equal(el->num_values, 1);
+	assert_string_equal(el->values[0].data, new_cn);
+}
+
+static void test_ldb_modify_replace_noexist_key(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct keyval mod_kvs[] = {
+		{ "name", "name_val" },
+		{ NULL, NULL },
+	};
+	struct ldb_result *res;
+	struct ldb_message_element *el;
+
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, mod_kvs);
+	assert_non_null(res);
+
+	/* Check cn is intact and name was added */
+	assert_int_equal(res->count, 1);
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_non_null(el);
+	assert_int_equal(el->num_values, 1);
+	assert_string_equal(el->values[0].data, "test_mod_cn");
+
+	el = ldb_msg_find_element(res->msgs[0], mod_kvs[0].key);
+	assert_non_null(el);
+	assert_int_equal(el->num_values, 1);
+	assert_string_equal(el->values[0].data, mod_kvs[0].val);
+}
+
+static void test_ldb_modify_replace_zero_vals(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct ldb_message_element *el;
+	struct ldb_result *res;
+	struct keyval kvs[] = {
+		{ "cn", NULL },
+		{ NULL, NULL },
+	};
+
+	/* cn must be gone */
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, kvs);
+	assert_non_null(res);
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_null(el);
+}
+
+static void test_ldb_modify_replace_noexist_key_zero_vals(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct ldb_message_element *el;
+	struct ldb_result *res;
+	struct keyval kvs[] = {
+		{ "noexist_key", NULL },
+		{ NULL, NULL },
+	};
+
+	/* cn must be gone */
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_REPLACE, kvs);
+	assert_non_null(res);
+
+	/* cn should be intact */
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_non_null(el);
+}
+
+static void test_ldb_modify_del_key(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct ldb_message_element *el;
+	struct ldb_result *res;
+	struct keyval kvs[] = {
+		{ "cn", NULL },
+		{ NULL, NULL },
+	};
+
+	/* cn must be gone */
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_DELETE, kvs);
+	assert_non_null(res);
+
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_null(el);
+}
+
+static void test_ldb_modify_del_keyval(void **state)
+{
+	struct ldb_mod_test_ctx *mod_test_ctx = \
+			talloc_get_type_abort(*state,
+					      struct ldb_mod_test_ctx);
+	struct ldb_message_element *el;
+	struct ldb_result *res;
+	struct keyval kvs[] = {
+		{ "cn", "test_mod_cn" },
+		{ NULL, NULL },
+	};
+
+	/* cn must be gone */
+	res = run_mod_test(mod_test_ctx, LDB_FLAG_MOD_DELETE, kvs);
+	assert_non_null(res);
+
+	el = ldb_msg_find_element(res->msgs[0], "cn");
+	assert_null(el);
+}
 
 int main(int argc, const char **argv)
 {
@@ -412,6 +808,33 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_transactions,
 						ldbtest_setup,
 						ldbtest_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_add_key,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_extend_key,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_add_key_noval,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_replace_key,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_replace_noexist_key,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_replace_zero_vals,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_replace_noexist_key_zero_vals,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_del_key,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_modify_del_keyval,
+						ldb_modify_test_setup,
+						ldb_modify_test_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From a13b5e9a1bc9cc3d33505d079096ee12fe8cd6a0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Thu, 14 May 2015 22:49:00 +0200
Subject: [PATCH 12/14] ldb:tests: unit test for ldb_search()

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 393 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 380 insertions(+), 13 deletions(-)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 065bd60a55b..2de15838dfd 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -22,6 +22,7 @@
 #include <unistd.h>
 #include <talloc.h>
 #include <ldb.h>
+#include <string.h>
 
 #define DEFAULT_BE  "tdb"
 
@@ -432,22 +433,21 @@ static struct ldb_message *build_mod_msg(TALLOC_CTX *mem_ctx,
 	return msg;
 }
 
-static void mod_test_add_data(struct ldb_mod_test_ctx *mod_test_ctx,
+static void ldb_test_add_data(TALLOC_CTX *mem_ctx,
+			      struct ldbtest_ctx *ldb_test_ctx,
+			      const char *basedn,
 			      struct keyval *kvs)
 {
 	TALLOC_CTX *tmp_ctx;
 	struct ldb_message *msg;
 	struct ldb_result *result = NULL;
-	struct ldbtest_ctx *ldb_test_ctx;
 	int ret;
 
-	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
-
-	tmp_ctx = talloc_new(mod_test_ctx);
+	tmp_ctx = talloc_new(mem_ctx);
 	assert_non_null(tmp_ctx);
 
 	msg = build_mod_msg(tmp_ctx, ldb_test_ctx,
-			    mod_test_ctx->entry_dn, 0, kvs);
+			    basedn, 0, kvs);
 	assert_non_null(msg);
 
 	ret = ldb_add(ldb_test_ctx->ldb, msg);
@@ -464,21 +464,20 @@ static void mod_test_add_data(struct ldb_mod_test_ctx *mod_test_ctx,
 	talloc_free(tmp_ctx);
 }
 
-static void mod_test_remove_data(struct ldb_mod_test_ctx *mod_test_ctx)
+static void ldb_test_remove_data(TALLOC_CTX *mem_ctx,
+				 struct ldbtest_ctx *ldb_test_ctx,
+				 const char *strdn)
 {
 	TALLOC_CTX *tmp_ctx;
-	struct ldb_dn *basedn;
 	struct ldb_result *result = NULL;
+	struct ldb_dn *basedn;
 	int ret;
-	struct ldbtest_ctx *ldb_test_ctx;
-
-	ldb_test_ctx = mod_test_ctx->ldb_test_ctx;
 
-	tmp_ctx = talloc_new(mod_test_ctx);
+	tmp_ctx = talloc_new(mem_ctx);
 	assert_non_null(tmp_ctx);
 
 	basedn = ldb_dn_new_fmt(tmp_ctx, ldb_test_ctx->ldb,
-				"%s", mod_test_ctx->entry_dn);
+				"%s", strdn);
 	assert_non_null(basedn);
 
 	ret = ldb_delete(ldb_test_ctx->ldb, basedn);
@@ -493,6 +492,22 @@ static void mod_test_remove_data(struct ldb_mod_test_ctx *mod_test_ctx)
 	talloc_free(tmp_ctx);
 }
 
+static void mod_test_add_data(struct ldb_mod_test_ctx *mod_test_ctx,
+			      struct keyval *kvs)
+{
+	ldb_test_add_data(mod_test_ctx,
+			  mod_test_ctx->ldb_test_ctx,
+			  mod_test_ctx->entry_dn,
+			  kvs);
+}
+
+static void mod_test_remove_data(struct ldb_mod_test_ctx *mod_test_ctx)
+{
+	ldb_test_remove_data(mod_test_ctx,
+			     mod_test_ctx->ldb_test_ctx,
+			     mod_test_ctx->entry_dn);
+}
+
 static struct ldb_result *run_mod_test(struct ldb_mod_test_ctx *mod_test_ctx,
 				       int modify_flags,
 				       struct keyval *kvs)
@@ -787,6 +802,343 @@ static void test_ldb_modify_del_keyval(void **state)
 	assert_null(el);
 }
 
+struct search_test_ctx {
+	struct ldbtest_ctx *ldb_test_ctx;
+	const char *base_dn;
+};
+
+static char *get_full_dn(TALLOC_CTX *mem_ctx,
+			 struct search_test_ctx *search_test_ctx,
+			 const char *rdn)
+{
+	char *full_dn;
+
+	full_dn = talloc_asprintf(mem_ctx,
+				  "%s,%s", rdn, search_test_ctx->base_dn);
+	assert_non_null(full_dn);
+
+	return full_dn;
+}
+
+static void search_test_add_data(struct search_test_ctx *search_test_ctx,
+				 const char *rdn,
+				 struct keyval *kvs)
+{
+	char *full_dn;
+
+	full_dn = get_full_dn(search_test_ctx, search_test_ctx, rdn);
+
+	ldb_test_add_data(search_test_ctx,
+			  search_test_ctx->ldb_test_ctx,
+			  full_dn,
+			  kvs);
+}
+
+static void search_test_remove_data(struct search_test_ctx *search_test_ctx,
+				    const char *rdn)
+{
+	char *full_dn;
+
+	full_dn = talloc_asprintf(search_test_ctx,
+				  "%s,%s", rdn, search_test_ctx->base_dn);
+	assert_non_null(full_dn);
+
+	ldb_test_remove_data(search_test_ctx,
+			     search_test_ctx->ldb_test_ctx,
+			     full_dn);
+}
+
+static int ldb_search_test_setup(void **state)
+{
+	struct ldbtest_ctx *ldb_test_ctx;
+	struct search_test_ctx *search_test_ctx;
+	struct keyval kvs[] = {
+		{ "cn", "test_search_cn" },
+		{ "cn", "test_search_cn2" },
+		{ "uid", "test_search_uid" },
+		{ "uid", "test_search_uid2" },
+		{ NULL, NULL },
+	};
+	struct keyval kvs2[] = {
+		{ "cn", "test_search_2_cn" },
+		{ "cn", "test_search_2_cn2" },
+		{ "uid", "test_search_2_uid" },
+		{ "uid", "test_search_2_uid2" },
+		{ NULL, NULL },
+	};
+
+	ldbtest_setup((void **) &ldb_test_ctx);
+
+	search_test_ctx = talloc(ldb_test_ctx, struct search_test_ctx);
+	assert_non_null(search_test_ctx);
+
+	search_test_ctx->base_dn = "dc=search_test_entry";
+	search_test_ctx->ldb_test_ctx = ldb_test_ctx;
+
+	search_test_remove_data(search_test_ctx, "cn=test_search_cn");
+	search_test_add_data(search_test_ctx, "cn=test_search_cn", kvs);
+
+	search_test_remove_data(search_test_ctx, "cn=test_search_2_cn");
+	search_test_add_data(search_test_ctx, "cn=test_search_2_cn", kvs2);
+
+	*state = search_test_ctx;
+	return 0;
+}
+
+static int ldb_search_test_teardown(void **state)
+{
+	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+			struct search_test_ctx);
+	struct ldbtest_ctx *ldb_test_ctx;
+
+	ldb_test_ctx = search_test_ctx->ldb_test_ctx;
+
+	search_test_remove_data(search_test_ctx, "cn=test_search_cn");
+	search_test_remove_data(search_test_ctx, "cn=test_search_2_cn");
+	ldbtest_teardown((void **) &ldb_test_ctx);
+	return 0;
+}
+
+static void assert_attr_has_vals(struct ldb_message *msg,
+				 const char *attr,
+				 const char *vals[],
+				 const size_t nvals)
+{
+	struct ldb_message_element *el;
+	size_t i;
+
+	el = ldb_msg_find_element(msg, attr);
+	assert_non_null(el);
+
+	assert_int_equal(el->num_values, nvals);
+	for (i = 0; i < nvals; i++) {
+		assert_string_equal(el->values[i].data,
+				    vals[i]);
+	}
+}
+
+static void assert_has_no_attr(struct ldb_message *msg,
+			       const char *attr)
+{
+	struct ldb_message_element *el;
+
+	el = ldb_msg_find_element(msg, attr);
+	assert_null(el);
+}
+
+static bool has_dn(struct ldb_message *msg, const char *dn)
+{
+	const char *msgdn;
+
+	msgdn = ldb_dn_get_linearized(msg->dn);
+	if (strcmp(dn, msgdn) == 0) {
+		return true;
+	}
+
+	return false;
+}
+
+static void test_search_match_none(void **state)
+{
+	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+			struct search_test_ctx);
+	int ret;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+
+	basedn = ldb_dn_new_fmt(search_test_ctx,
+			        search_test_ctx->ldb_test_ctx->ldb,
+				"%s",
+				search_test_ctx->base_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+			 search_test_ctx,
+			 &result,
+			 basedn,
+			 LDB_SCOPE_SUBTREE, NULL,
+			 "dc=no_such_entry");
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 0);
+}
+
+static void test_search_match_one(void **state)
+{
+	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+			struct search_test_ctx);
+	int ret;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+	const char *cn_vals[] = { "test_search_cn",
+				  "test_search_cn2" };
+	const char *uid_vals[] = { "test_search_uid",
+				   "test_search_uid2" };
+
+	basedn = ldb_dn_new_fmt(search_test_ctx,
+				search_test_ctx->ldb_test_ctx->ldb,
+				"%s",
+				search_test_ctx->base_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+			 search_test_ctx,
+			 &result,
+			 basedn,
+			 LDB_SCOPE_SUBTREE, NULL,
+			 "cn=test_search_cn");
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 1);
+
+	assert_attr_has_vals(result->msgs[0], "cn", cn_vals, 2);
+	assert_attr_has_vals(result->msgs[0], "uid", uid_vals, 2);
+}
+
+static void test_search_match_filter(void **state)
+{
+	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+			struct search_test_ctx);
+	int ret;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+	const char *cn_vals[] = { "test_search_cn",
+				  "test_search_cn2" };
+	const char *attrs[] = { "cn", NULL };
+
+	basedn = ldb_dn_new_fmt(search_test_ctx,
+			        search_test_ctx->ldb_test_ctx->ldb,
+				"%s",
+				search_test_ctx->base_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+			 search_test_ctx,
+			 &result,
+			 basedn,
+			 LDB_SCOPE_SUBTREE,
+			 attrs,
+			 "cn=test_search_cn");
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 1);
+
+	assert_attr_has_vals(result->msgs[0], "cn", cn_vals, 2);
+	assert_has_no_attr(result->msgs[0], "uid");
+}
+
+static void assert_expected(struct search_test_ctx *search_test_ctx,
+			    struct ldb_message *msg)
+{
+	char *full_dn1;
+	char *full_dn2;
+	const char *cn_vals[] = { "test_search_cn",
+				  "test_search_cn2" };
+	const char *uid_vals[] = { "test_search_uid",
+				   "test_search_uid2" };
+	const char *cn2_vals[] = { "test_search_2_cn",
+				   "test_search_2_cn2" };
+	const char *uid2_vals[] = { "test_search_2_uid",
+				    "test_search_2_uid2" };
+
+	full_dn1 = get_full_dn(search_test_ctx,
+			       search_test_ctx,
+			       "cn=test_search_cn");
+
+	full_dn2 = get_full_dn(search_test_ctx,
+			       search_test_ctx,
+			       "cn=test_search_2_cn");
+
+	if (has_dn(msg, full_dn1) == true) {
+		assert_attr_has_vals(msg, "cn", cn_vals, 2);
+		assert_attr_has_vals(msg, "uid", uid_vals, 2);
+	} else if (has_dn(msg, full_dn2) == true) {
+		assert_attr_has_vals(msg, "cn", cn2_vals, 2);
+		assert_attr_has_vals(msg, "uid", uid2_vals, 2);
+	} else {
+		fail();
+	}
+}
+
+static void test_search_match_both(void **state)
+{
+	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+			struct search_test_ctx);
+	int ret;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+
+	basedn = ldb_dn_new_fmt(search_test_ctx,
+			        search_test_ctx->ldb_test_ctx->ldb,
+				"%s",
+				search_test_ctx->base_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+			 search_test_ctx,
+			 &result,
+			 basedn,
+			 LDB_SCOPE_SUBTREE, NULL,
+			 "cn=test_search_*");
+	assert_int_equal(ret, 0);
+	assert_non_null(result);
+	assert_int_equal(result->count, 2);
+
+	assert_expected(search_test_ctx, result->msgs[0]);
+	assert_expected(search_test_ctx, result->msgs[1]);
+}
+
+static void test_search_match_basedn(void **state)
+{
+	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+			struct search_test_ctx);
+	int ret;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+	struct ldb_message *msg;
+
+	basedn = ldb_dn_new_fmt(search_test_ctx,
+			        search_test_ctx->ldb_test_ctx->ldb,
+				"dc=nosuchdn");
+	assert_non_null(basedn);
+
+	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+			 search_test_ctx,
+			 &result,
+			 basedn,
+			 LDB_SCOPE_SUBTREE, NULL,
+			 "cn=*");
+	assert_int_equal(ret, 0);
+
+	/* Add 'checkBaseOnSearch' to @OPTIONS */
+	msg = ldb_msg_new(search_test_ctx);
+	assert_non_null(msg);
+
+	msg->dn = ldb_dn_new_fmt(msg,
+				 search_test_ctx->ldb_test_ctx->ldb,
+				 "@OPTIONS");
+	assert_non_null(msg->dn);
+
+	ret = ldb_msg_add_string(msg, "checkBaseOnSearch", "TRUE");
+	assert_int_equal(ret, 0);
+
+	ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb, msg);
+	assert_int_equal(ret, 0);
+
+	/* Search again */
+	/* The search should return LDB_ERR_NO_SUCH_OBJECT */
+	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+			 search_test_ctx,
+			 &result,
+			 basedn,
+			 LDB_SCOPE_SUBTREE, NULL,
+			 "cn=*");
+	assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+	ret = ldb_delete(search_test_ctx->ldb_test_ctx->ldb, msg->dn);
+	assert_int_equal(ret, 0);
+}
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
@@ -835,6 +1187,21 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_ldb_modify_del_keyval,
 						ldb_modify_test_setup,
 						ldb_modify_test_teardown),
+		cmocka_unit_test_setup_teardown(test_search_match_none,
+						ldb_search_test_setup,
+						ldb_search_test_teardown),
+		cmocka_unit_test_setup_teardown(test_search_match_one,
+						ldb_search_test_setup,
+						ldb_search_test_teardown),
+		cmocka_unit_test_setup_teardown(test_search_match_filter,
+						ldb_search_test_setup,
+						ldb_search_test_teardown),
+		cmocka_unit_test_setup_teardown(test_search_match_both,
+						ldb_search_test_setup,
+						ldb_search_test_teardown),
+		cmocka_unit_test_setup_teardown(test_search_match_basedn,
+						ldb_search_test_setup,
+						ldb_search_test_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From 873b9a3c3066e821fa578c22be89cbfa20c1a79e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Tue, 24 Nov 2015 20:12:43 +0100
Subject: [PATCH 13/14] ldb:tests: Add tests for case insensitive searches

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 114 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 2de15838dfd..1a0ca5299f2 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -247,6 +247,36 @@ static int base_search_count(struct ldbtest_ctx *test_ctx, const char *entry_dn)
 	return count;
 }
 
+static int sub_search_count(struct ldbtest_ctx *test_ctx,
+			    const char *base_dn,
+			    const char *filter)
+{
+	TALLOC_CTX *tmp_ctx;
+	struct ldb_dn *basedn;
+	struct ldb_result *result = NULL;
+	int ret;
+	int count;
+
+	tmp_ctx = talloc_new(test_ctx);
+	assert_non_null(tmp_ctx);
+
+	basedn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", base_dn);
+	assert_non_null(basedn);
+
+	ret = ldb_search(test_ctx->ldb, tmp_ctx, &result, basedn,
+			 LDB_SCOPE_SUBTREE, NULL, "%s", filter);
+	assert_int_equal(ret, LDB_SUCCESS);
+	assert_non_null(result);
+
+	count = result->count;
+	talloc_free(tmp_ctx);
+	return count;
+}
+
+/* In general it would be better if utility test functions didn't assert
+ * but only returned a value, then assert in the test shows correct
+ * line
+ */
 static void assert_dn_exists(struct ldbtest_ctx *test_ctx,
 			     const char *entry_dn)
 {
@@ -1139,6 +1169,87 @@ static void test_search_match_basedn(void **state)
 	assert_int_equal(ret, 0);
 }
 
+static int ldb_case_test_setup(void **state)
+{
+	int ret;
+	struct ldb_ldif *ldif;
+	struct ldbtest_ctx *ldb_test_ctx;
+	const char *attrs_ldif =  \
+		"dn: @ATTRIBUTES\n"
+		"cn: CASE_INSENSITIVE\n"
+		"\n";
+	struct keyval kvs[] = {
+		{ "cn", "CaseInsensitiveValue" },
+		{ "uid", "CaseSensitiveValue" },
+		{ NULL, NULL },
+	};
+
+
+	ldbtest_setup((void **) &ldb_test_ctx);
+
+	while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &attrs_ldif))) {
+		ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+		assert_int_equal(ret, LDB_SUCCESS);
+	}
+
+	ldb_test_add_data(ldb_test_ctx,
+			  ldb_test_ctx,
+			  "cn=CaseInsensitiveValue",
+			  kvs);
+
+	*state = ldb_test_ctx;
+	return 0;
+}
+
+static int ldb_case_test_teardown(void **state)
+{
+	int ret;
+	struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+			struct ldbtest_ctx);
+
+	struct ldb_dn *del_dn;
+
+	del_dn = ldb_dn_new_fmt(ldb_test_ctx,
+				ldb_test_ctx->ldb,
+				"@ATTRIBUTES");
+	assert_non_null(del_dn);
+
+	ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	assert_dn_doesnt_exist(ldb_test_ctx,
+			       "@ATTRIBUTES");
+
+	ldb_test_remove_data(ldb_test_ctx, ldb_test_ctx,
+			     "cn=CaseInsensitiveValue");
+
+	ldbtest_teardown((void **) &ldb_test_ctx);
+	return 0;
+}
+
+static void test_ldb_attrs_case_insensitive(void **state)
+{
+	int cnt;
+	struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
+			struct ldbtest_ctx);
+
+	/* cn matches exact case */
+	cnt = sub_search_count(ldb_test_ctx, "", "cn=CaseInsensitiveValue");
+	assert_int_equal(cnt, 1);
+
+	/* cn matches lower case */
+	cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
+	assert_int_equal(cnt, 1);
+
+	/* uid matches exact case */
+	cnt = sub_search_count(ldb_test_ctx, "", "uid=CaseSensitiveValue");
+	assert_int_equal(cnt, 1);
+
+	/* uid does not match lower case */
+	cnt = sub_search_count(ldb_test_ctx, "", "uid=casesensitivevalue");
+	assert_int_equal(cnt, 0);
+}
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
@@ -1202,6 +1313,9 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_search_match_basedn,
 						ldb_search_test_setup,
 						ldb_search_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_attrs_case_insensitive,
+						ldb_case_test_setup,
+						ldb_case_test_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2


>From 61215f4308091ba10c9d7973c617e8b6647ca1f8 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jakub.hrozek at posteo.se>
Date: Wed, 7 Oct 2015 18:07:13 +0200
Subject: [PATCH 14/14] ldb:tests: Unit test the ldb_rename() operation

Signed-off-by: Jakub Hrozek <jakub.hrozek at posteo.se>
Reviewed-by: Andreas Schneider <asn at samba.org>
---
 lib/ldb/tests/ldb_mod_op_test.c | 294 ++++++++++++++++++++++++++++++++++------
 1 file changed, 256 insertions(+), 38 deletions(-)

diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 1a0ca5299f2..e609d3a8492 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -23,6 +23,7 @@
 #include <talloc.h>
 #include <ldb.h>
 #include <string.h>
+#include <ctype.h>
 
 #define DEFAULT_BE  "tdb"
 
@@ -295,40 +296,52 @@ static void assert_dn_doesnt_exist(struct ldbtest_ctx *test_ctx,
 	assert_int_equal(count, 0);
 }
 
-static void test_ldb_del(void **state)
+static void add_dn_with_cn(struct ldbtest_ctx *test_ctx,
+			   struct ldb_dn *dn,
+			   const char *cn_value)
 {
 	int ret;
-	struct ldb_message *msg;
-	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
-							struct ldbtest_ctx);
 	TALLOC_CTX *tmp_ctx;
-	const char *basedn = "dc=ldb_del_test";
+	struct ldb_message *msg;
 
 	tmp_ctx = talloc_new(test_ctx);
 	assert_non_null(tmp_ctx);
 
-	assert_dn_doesnt_exist(test_ctx, basedn);
+	assert_dn_doesnt_exist(test_ctx,
+			       ldb_dn_get_linearized(dn));
 
 	msg = ldb_msg_new(tmp_ctx);
 	assert_non_null(msg);
+	msg->dn = dn;
 
-	msg->dn = ldb_dn_new_fmt(tmp_ctx, test_ctx->ldb, "%s", basedn);
-	assert_non_null(msg->dn);
-
-	ret = ldb_msg_add_string(msg, "cn", "test_del_cn_val");
+	ret = ldb_msg_add_string(msg, "cn", cn_value);
 	assert_int_equal(ret, LDB_SUCCESS);
 
 	ret = ldb_add(test_ctx->ldb, msg);
 	assert_int_equal(ret, LDB_SUCCESS);
 
-	assert_dn_exists(test_ctx, basedn);
+	assert_dn_exists(test_ctx,
+			 ldb_dn_get_linearized(dn));
+	talloc_free(tmp_ctx);
+}
 
-	ret = ldb_delete(test_ctx->ldb, msg->dn);
+static void test_ldb_del(void **state)
+{
+	int ret;
+	struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+							struct ldbtest_ctx);
+	const char *basedn = "dc=ldb_del_test";
+	struct ldb_dn *dn;
+
+	dn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "%s", basedn);
+	assert_non_null(dn);
+
+	add_dn_with_cn(test_ctx, dn, "test_del_cn_val");
+
+	ret = ldb_delete(test_ctx->ldb, dn);
 	assert_int_equal(ret, LDB_SUCCESS);
 
 	assert_dn_doesnt_exist(test_ctx, basedn);
-
-	talloc_free(tmp_ctx);
 }
 
 static void test_ldb_del_noexist(void **state)
@@ -499,9 +512,9 @@ static void ldb_test_remove_data(TALLOC_CTX *mem_ctx,
 				 const char *strdn)
 {
 	TALLOC_CTX *tmp_ctx;
-	struct ldb_result *result = NULL;
 	struct ldb_dn *basedn;
 	int ret;
+	size_t count;
 
 	tmp_ctx = talloc_new(mem_ctx);
 	assert_non_null(tmp_ctx);
@@ -513,11 +526,8 @@ static void ldb_test_remove_data(TALLOC_CTX *mem_ctx,
 	ret = ldb_delete(ldb_test_ctx->ldb, basedn);
 	assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_NO_SUCH_OBJECT);
 
-	ret = ldb_search(ldb_test_ctx->ldb, tmp_ctx, &result, basedn,
-			LDB_SCOPE_BASE, NULL, NULL);
-	assert_int_equal(ret, LDB_SUCCESS);
-	assert_non_null(result);
-	assert_int_equal(result->count, 0);
+	count = base_search_count(ldb_test_ctx, ldb_dn_get_linearized(basedn));
+	assert_int_equal(count, 0);
 
 	talloc_free(tmp_ctx);
 }
@@ -972,25 +982,11 @@ static void test_search_match_none(void **state)
 {
 	struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
 			struct search_test_ctx);
-	int ret;
-	struct ldb_dn *basedn;
-	struct ldb_result *result = NULL;
+	size_t count;
 
-	basedn = ldb_dn_new_fmt(search_test_ctx,
-			        search_test_ctx->ldb_test_ctx->ldb,
-				"%s",
-				search_test_ctx->base_dn);
-	assert_non_null(basedn);
-
-	ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
-			 search_test_ctx,
-			 &result,
-			 basedn,
-			 LDB_SCOPE_SUBTREE, NULL,
-			 "dc=no_such_entry");
-	assert_int_equal(ret, 0);
-	assert_non_null(result);
-	assert_int_equal(result->count, 0);
+	count = base_search_count(search_test_ctx->ldb_test_ctx,
+				  "dc=no_such_entry");
+	assert_int_equal(count, 0);
 }
 
 static void test_search_match_one(void **state)
@@ -1227,6 +1223,69 @@ static int ldb_case_test_teardown(void **state)
 	return 0;
 }
 
+struct rename_test_ctx {
+	struct ldbtest_ctx *ldb_test_ctx;
+
+	struct ldb_dn *basedn;
+	const char *str_basedn;
+
+	const char *teardown_dn;
+};
+
+static int ldb_rename_test_setup(void **state)
+{
+	struct ldbtest_ctx *ldb_test_ctx;
+	struct rename_test_ctx *rename_test_ctx;
+	const char *strdn = "dc=rename_test_entry_from";
+
+	ldbtest_setup((void **) &ldb_test_ctx);
+
+	rename_test_ctx = talloc(ldb_test_ctx, struct rename_test_ctx);
+	assert_non_null(rename_test_ctx);
+	rename_test_ctx->ldb_test_ctx = ldb_test_ctx;
+	assert_non_null(rename_test_ctx->ldb_test_ctx);
+
+	rename_test_ctx->basedn = ldb_dn_new_fmt(rename_test_ctx,
+				rename_test_ctx->ldb_test_ctx->ldb,
+				"%s", strdn);
+	assert_non_null(rename_test_ctx->basedn);
+
+	rename_test_ctx->str_basedn = strdn;
+	rename_test_ctx->teardown_dn = strdn;
+
+	add_dn_with_cn(ldb_test_ctx,
+		       rename_test_ctx->basedn,
+		       "test_rename_cn_val");
+
+	*state = rename_test_ctx;
+	return 0;
+}
+
+static int ldb_rename_test_teardown(void **state)
+{
+	int ret;
+	struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(*state,
+			struct rename_test_ctx);
+	struct ldbtest_ctx *ldb_test_ctx;
+	struct ldb_dn *del_dn;
+
+	ldb_test_ctx = rename_test_ctx->ldb_test_ctx;
+
+	del_dn = ldb_dn_new_fmt(rename_test_ctx,
+				rename_test_ctx->ldb_test_ctx->ldb,
+				"%s", rename_test_ctx->teardown_dn);
+	assert_non_null(del_dn);
+
+	ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	assert_dn_doesnt_exist(ldb_test_ctx,
+			       rename_test_ctx->teardown_dn);
+
+	ldbtest_teardown((void **) &ldb_test_ctx);
+	return 0;
+}
+
 static void test_ldb_attrs_case_insensitive(void **state)
 {
 	int cnt;
@@ -1250,6 +1309,150 @@ static void test_ldb_attrs_case_insensitive(void **state)
 	assert_int_equal(cnt, 0);
 }
 
+static void test_ldb_rename(void **state)
+{
+	struct rename_test_ctx *rename_test_ctx =
+		talloc_get_type_abort(*state, struct rename_test_ctx);
+	int ret;
+	const char *str_new_dn = "dc=rename_test_entry_to";
+	struct ldb_dn *new_dn;
+
+	new_dn = ldb_dn_new_fmt(rename_test_ctx,
+				rename_test_ctx->ldb_test_ctx->ldb,
+				"%s", str_new_dn);
+	assert_non_null(new_dn);
+
+	ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+			 rename_test_ctx->basedn,
+			 new_dn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	assert_dn_exists(rename_test_ctx->ldb_test_ctx, str_new_dn);
+	assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+			       rename_test_ctx->str_basedn);
+	rename_test_ctx->teardown_dn = str_new_dn;
+
+	/* FIXME - test the values which didn't change */
+}
+
+static void test_ldb_rename_from_doesnt_exist(void **state)
+{
+	struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+							*state,
+							struct rename_test_ctx);
+	int ret;
+	const char *str_new_dn = "dc=rename_test_entry_to";
+	const char *str_bad_old_dn = "dc=rename_test_no_such_entry";
+	struct ldb_dn *new_dn;
+	struct ldb_dn *bad_old_dn;
+
+	new_dn = ldb_dn_new_fmt(rename_test_ctx,
+				rename_test_ctx->ldb_test_ctx->ldb,
+				"%s", str_new_dn);
+	assert_non_null(new_dn);
+
+	bad_old_dn = ldb_dn_new_fmt(rename_test_ctx,
+				    rename_test_ctx->ldb_test_ctx->ldb,
+				    "%s", str_bad_old_dn);
+	assert_non_null(bad_old_dn);
+
+	assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+			       str_bad_old_dn);
+
+	ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+			 bad_old_dn, new_dn);
+	assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
+
+	assert_dn_doesnt_exist(rename_test_ctx->ldb_test_ctx,
+			       str_new_dn);
+}
+
+static void test_ldb_rename_to_exists(void **state)
+{
+	struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+							*state,
+							struct rename_test_ctx);
+	int ret;
+	const char *str_new_dn = "dc=rename_test_already_exists";
+	struct ldb_dn *new_dn;
+
+	new_dn = ldb_dn_new_fmt(rename_test_ctx,
+				rename_test_ctx->ldb_test_ctx->ldb,
+				"%s", str_new_dn);
+	assert_non_null(new_dn);
+
+	add_dn_with_cn(rename_test_ctx->ldb_test_ctx,
+		       new_dn,
+		       "test_rename_cn_val");
+
+	ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+			 rename_test_ctx->basedn,
+			 new_dn);
+	assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+	/* Old object must still exist */
+	assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+			 rename_test_ctx->str_basedn);
+
+	ret = ldb_delete(rename_test_ctx->ldb_test_ctx->ldb,
+			 new_dn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+			       rename_test_ctx->teardown_dn);
+}
+
+static void test_ldb_rename_self(void **state)
+{
+	struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+							*state,
+							struct rename_test_ctx);
+	int ret;
+
+	/* Oddly enough, this is a success in ldb.. */
+	ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+			 rename_test_ctx->basedn,
+			 rename_test_ctx->basedn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	/* Old object must still exist */
+	assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+			 rename_test_ctx->str_basedn);
+}
+
+static void test_ldb_rename_dn_case_change(void **state)
+{
+	struct rename_test_ctx *rename_test_ctx = talloc_get_type_abort(
+							*state,
+							struct rename_test_ctx);
+	int ret;
+	char *str_new_dn;
+	struct ldb_dn *new_dn;
+	unsigned i;
+
+	str_new_dn = talloc_strdup(rename_test_ctx, rename_test_ctx->str_basedn);
+	assert_non_null(str_new_dn);
+	for (i = 0; str_new_dn[i]; i++) {
+		str_new_dn[i] = toupper(str_new_dn[i]);
+	}
+
+	new_dn = ldb_dn_new_fmt(rename_test_ctx,
+				rename_test_ctx->ldb_test_ctx->ldb,
+				"%s", str_new_dn);
+	assert_non_null(new_dn);
+
+	ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
+			 rename_test_ctx->basedn,
+			 new_dn);
+	assert_int_equal(ret, LDB_SUCCESS);
+
+	/* DNs are case insensitive, so both searches will match */
+	assert_dn_exists(rename_test_ctx->ldb_test_ctx, str_new_dn);
+	assert_dn_exists(rename_test_ctx->ldb_test_ctx,
+			 rename_test_ctx->str_basedn);
+	/* FIXME - test the values didn't change */
+}
+
 int main(int argc, const char **argv)
 {
 	const struct CMUnitTest tests[] = {
@@ -1316,6 +1519,21 @@ int main(int argc, const char **argv)
 		cmocka_unit_test_setup_teardown(test_ldb_attrs_case_insensitive,
 						ldb_case_test_setup,
 						ldb_case_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_rename,
+						ldb_rename_test_setup,
+						ldb_rename_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_rename_from_doesnt_exist,
+						ldb_rename_test_setup,
+						ldb_rename_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_rename_to_exists,
+						ldb_rename_test_setup,
+						ldb_rename_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_rename_self,
+						ldb_rename_test_setup,
+						ldb_rename_test_teardown),
+		cmocka_unit_test_setup_teardown(test_ldb_rename_dn_case_change,
+						ldb_rename_test_setup,
+						ldb_rename_test_teardown),
 	};
 
 	return cmocka_run_group_tests(tests, NULL, NULL);
-- 
2.12.2



More information about the samba-technical mailing list