assert_int_equal(ret, 0);
}
+static struct ldb_message *get_test_ldb_message(TALLOC_CTX *mem_ctx,
+ struct ldb_context *ldb)
+{
+ struct ldb_message *msg = ldb_msg_new(mem_ctx);
+ int ret;
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new(msg, ldb, "dc=samba,dc=org");
+ assert_non_null(msg->dn);
+ ret = ldb_msg_add_string(msg, "public", "key");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "supersecret", "password");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "binary", "\xff\xff\0");
+ assert_int_equal(ret, LDB_SUCCESS);
+ return msg;
+}
+
+static void test_ldif_message(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ char *got_ldif;
+ const char *expected_ldif =
+ "dn: dc=samba,dc=org\n"
+ "changetype: add\n"
+ "public: key\n"
+ "supersecret: password\n"
+ "binary:: //8=\n"
+ "\n";
+
+ struct ldb_message *msg = get_test_ldb_message(test_ctx,
+ test_ctx->ldb);
+
+ got_ldif = ldb_ldif_message_string(test_ctx->ldb,
+ test_ctx,
+ LDB_CHANGETYPE_ADD,
+ msg);
+ assert_string_equal(got_ldif, expected_ldif);
+ TALLOC_FREE(got_ldif);
+}
+
+static void test_ldif_message_redacted(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ int ret;
+ char *got_ldif;
+ const char *expected_ldif =
+ "dn: dc=samba,dc=org\n"
+ "changetype: add\n"
+ "public: key\n"
+ "# supersecret::: REDACTED SECRET ATTRIBUTE\n"
+ "binary:: //8=\n"
+ "\n";
+
+ const char *secret_attrs[] = {
+ "supersecret",
+ NULL
+ };
+
+ struct ldb_message *msg = ldb_msg_new(test_ctx);
+
+ ldb_set_opaque(test_ctx->ldb,
+ LDB_SECRET_ATTRIBUTE_LIST_OPAQUE,
+ secret_attrs);
+
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new(msg, test_ctx->ldb, "dc=samba,dc=org");
+ ret = ldb_msg_add_string(msg, "public", "key");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "supersecret", "password");
+ assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "binary", "\xff\xff\0");
+ assert_int_equal(ret, LDB_SUCCESS);
+ got_ldif = ldb_ldif_message_redacted_string(test_ctx->ldb,
+ test_ctx,
+ LDB_CHANGETYPE_ADD,
+ msg);
+ assert_string_equal(got_ldif, expected_ldif);
+ TALLOC_FREE(got_ldif);
+ assert_int_equal(ret, 0);
+}
+
static int ldbtest_setup(void **state)
{
struct ldbtest_ctx *test_ctx;
+ struct ldb_ldif *ldif;
+#ifdef GUID_IDX
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+#else
+ const char *index_ldif = "\n";
+#endif
int ret;
ldbtest_noconn_setup((void **) &test_ctx);
ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
assert_int_equal(ret, 0);
+ while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
*state = test_ctx;
return 0;
}
ret = ldb_msg_add_string(msg, "cn", "test_cn_val");
assert_int_equal(ret, 0);
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, 0);
+
ret = ldb_add(test_ctx->ldb, msg);
assert_int_equal(ret, 0);
ret = ldb_msg_add_string(msg, "cn", "test_cn_val1");
assert_int_equal(ret, 0);
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcde1");
+ assert_int_equal(ret, 0);
+
ret = ldb_add(test_ctx->ldb, msg);
assert_int_equal(ret, 0);
ret = ldb_msg_add_string(msg, "cn", "test_cn_val2");
assert_int_equal(ret, 0);
+ ret = ldb_msg_add_string(msg, "objectUUID", "0123456789abcde2");
+ assert_int_equal(ret, 0);
+
ret = ldb_add(test_ctx->ldb, msg);
assert_int_equal(ret, 0);
static void add_dn_with_cn(struct ldbtest_ctx *test_ctx,
struct ldb_dn *dn,
- const char *cn_value)
+ const char *cn_value,
+ const char *uuid_value)
{
int ret;
TALLOC_CTX *tmp_ctx;
ret = ldb_msg_add_string(msg, "cn", cn_value);
assert_int_equal(ret, LDB_SUCCESS);
+ ret = ldb_msg_add_string(msg, "objectUUID", uuid_value);
+ assert_int_equal(ret, 0);
+
ret = ldb_add(test_ctx->ldb, msg);
assert_int_equal(ret, LDB_SUCCESS);
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");
+ add_dn_with_cn(test_ctx, dn,
+ "test_del_cn_val",
+ "0123456789abcdef");
ret = ldb_delete(test_ctx->ldb, dn);
assert_int_equal(ret, LDB_SUCCESS);
static void add_keyval(struct ldbtest_ctx *test_ctx,
const char *key,
- const char *val)
+ const char *val,
+ const char *uuid)
{
int ret;
struct ldb_message *msg;
ret = ldb_msg_add_string(msg, key, val);
assert_int_equal(ret, 0);
+ ret = ldb_msg_add_string(msg, "objectUUID", uuid);
+ assert_int_equal(ret, 0);
+
ret = ldb_add(test_ctx->ldb, msg);
assert_int_equal(ret, 0);
ret = ldb_transaction_start(test_ctx->ldb);
assert_int_equal(ret, 0);
- add_keyval(test_ctx, "vegetable", "carrot");
+ add_keyval(test_ctx, "vegetable", "carrot",
+ "0123456789abcde0");
/* commit lev-0 transaction */
ret = ldb_transaction_commit(test_ctx->ldb);
ret = ldb_transaction_start(test_ctx->ldb);
assert_int_equal(ret, 0);
- add_keyval(test_ctx, "fruit", "apple");
+ add_keyval(test_ctx, "fruit", "apple",
+ "0123456789abcde1");
/* abort lev-1 nested transaction */
ret = ldb_transaction_cancel(test_ctx->ldb);
assert_int_equal(res->count, 0);
}
+static void test_nested_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",
+ "0123456789abcde0");
+
+
+ /* start another lev-1 nested transaction */
+ ret = ldb_transaction_start(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ add_keyval(test_ctx, "fruit", "apple",
+ "0123456789abcde1");
+
+ /* abort lev-1 nested transaction */
+ ret = ldb_transaction_cancel(test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ /* commit lev-0 transaction */
+ ret = ldb_transaction_commit(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);
+
+ /* This documents the current ldb behaviour, i.e. nested
+ * transactions are not supported. And the cancellation of the nested
+ * transaction has no effect.
+ */
+ res = get_keyval(test_ctx, "fruit", "apple");
+ assert_non_null(res);
+ assert_int_equal(res->count, 1);
+}
struct ldb_mod_test_ctx {
struct ldbtest_ctx *ldb_test_ctx;
const char *entry_dn;
struct ldb_mod_test_ctx *mod_test_ctx;
struct keyval kvs[] = {
{ "cn", "test_mod_cn" },
+ { "objectUUID", "0123456789abcdef"},
{ NULL, NULL },
};
{ "cn", "test_search_cn2" },
{ "uid", "test_search_uid" },
{ "uid", "test_search_uid2" },
+ { "objectUUID", "0123456789abcde0"},
{ NULL, NULL },
};
struct keyval kvs2[] = {
{ "cn", "test_search_2_cn2" },
{ "uid", "test_search_2_uid" },
{ "uid", "test_search_2_uid2" },
+ { "objectUUID", "0123456789abcde1"},
{ NULL, NULL },
};
* - (2) the ldb_transaction_commit() is called.
* This returns LDB_ERR_BUSY if the deadlock is detected
*
- * With ldb 1.1.29 and tdb 1.3.12 we avoid this only due to a missing
+ * With ldb 1.1.31 and tdb 1.3.12 we avoid this only due to a missing
* lock call in ltdb_search() due to a refcounting bug in
* ltdb_lock_read()
*/
* we take any locks in the tdb_traverse_read() handler.
*
* In tdb 1.3.12 tdb_traverse_read() take the read transaction lock
- * however in ldb 1.1.29 ltdb_search() forgets to take the all-record
+ * however in ldb 1.1.31 ltdb_search() forgets to take the all-record
* lock (except the very first time) due to a ref-counting bug.
*
*/
struct ldb_message *msg;
TALLOC_FREE(ctx->test_ctx->ldb);
TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
if (ctx->test_ctx->ev == NULL) {
exit(LDB_ERR_OPERATIONS_ERROR);
exit(LDB_ERR_OPERATIONS_ERROR);
}
+ ret = ldb_msg_add_string(msg, "objectUUID",
+ "0123456789abcdef");
+ if (ret != 0) {
+ exit(ret);
+ }
+
ret = ldb_add(ctx->test_ctx->ldb, msg);
if (ret != 0) {
exit(ret);
ret = ldb_transaction_commit(ctx->test_ctx->ldb);
exit(ret);
}
-
+ close(pipes[1]);
ret = read(pipes[0], buf, 2);
assert_int_equal(ret, 2);
struct ldb_dn *dn, *new_dn;
TALLOC_FREE(ctx->test_ctx->ldb);
TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
if (ctx->test_ctx->ev == NULL) {
exit(LDB_ERR_OPERATIONS_ERROR);
struct ldb_message_element *el;
TALLOC_FREE(ctx->test_ctx->ldb);
TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
if (ctx->test_ctx->ev == NULL) {
exit(LDB_ERR_OPERATIONS_ERROR);
* sending the "GO" as it is blocked at ldb_transaction_start().
*/
+ close(pipes[1]);
ret = read(pipes[0], buf, 2);
assert_int_equal(ret, 2);
ret = ldb_msg_add_string(msg, "@IDXATTR", "cn");
assert_int_equal(ret, LDB_SUCCESS);
-
ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb,
msg);
-
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ }
assert_int_equal(ret, LDB_SUCCESS);
}
static void test_ldb_modify_during_indexed_search(void **state)
{
- return test_ldb_modify_during_search(state, true, false);
+ test_ldb_modify_during_search(state, true, false);
}
static void test_ldb_modify_during_unindexed_search(void **state)
{
- return test_ldb_modify_during_search(state, false, false);
+ test_ldb_modify_during_search(state, false, false);
}
static void test_ldb_rename_during_indexed_search(void **state)
{
- return test_ldb_modify_during_search(state, true, true);
+ test_ldb_modify_during_search(state, true, true);
}
static void test_ldb_rename_during_unindexed_search(void **state)
{
- return test_ldb_modify_during_search(state, false, true);
+ test_ldb_modify_during_search(state, false, true);
}
/*
struct ldb_message_element *el;
TALLOC_FREE(ctx->test_ctx->ldb);
TALLOC_FREE(ctx->test_ctx->ev);
+ close(pipes[0]);
ctx->test_ctx->ev = tevent_context_init(ctx->test_ctx);
if (ctx->test_ctx->ev == NULL) {
exit(LDB_ERR_OPERATIONS_ERROR);
exit(ret);
}
+ close(pipes[1]);
ret = read(pipes[0], buf, 2);
assert_int_equal(ret, 2);
assert_int_equal(res2->count, 1);
}
-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 },
- };
+/*
+ * This test is also complex.
+ *
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * before the request is destroyed with TALLOC_FREE()
+ *
+ * This would be a failure if in process
+ * (1) and (2):
+ * - (1) ldb_search() starts and waits
+ * - (2) an entry in the DB is allowed to change before the ldb_wait() is called
+ * - (1) the original process can see the modification before the TALLOC_FREE()
+ * also we check that
+ * - (1) the original process can see the modification after the TALLOC_FREE()
+ *
+ */
+/*
+ * This purpose of this callback is to trigger a write in
+ * the child process before the ldb_wait() is called
+ *
+ * In ldb 1.1.31 ldb_search() omitted to take a all-record
+ * lock for the full duration of the search and callbacks
+ *
+ * We assume that if the write will proceed, it will proceed in a 3
+ * second window after the function is called.
+ */
- ldbtest_setup((void **) &ldb_test_ctx);
+static int test_ldb_modify_before_ldb_wait_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
- 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);
+ case LDB_REPLY_DONE:
+ break;
}
- ldb_test_add_data(ldb_test_ctx,
- ldb_test_ctx,
- "cn=CaseInsensitiveValue",
- kvs);
-
- *state = ldb_test_ctx;
- return 0;
+ return ldb_request_done(req, LDB_SUCCESS);
}
-static int ldb_case_test_teardown(void **state)
+static void test_ldb_modify_before_ldb_wait(void **state)
{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
int ret;
- struct ldbtest_ctx *ldb_test_ctx = talloc_get_type_abort(*state,
- struct ldbtest_ctx);
+ struct ldb_request *req;
+ pid_t pid;
+ int wstatus;
+ struct ldb_dn *search_dn;
+ struct ldb_dn *basedn;
+ struct ldb_result *res2;
+ int pipes[2];
+ char buf[2];
+ pid_t child_pid;
+ unsigned res_count;
- struct ldb_dn *del_dn;
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+ assert_non_null(search_dn);
- del_dn = ldb_dn_new_fmt(ldb_test_ctx,
- ldb_test_ctx->ldb,
- "@ATTRIBUTES");
- assert_non_null(del_dn);
+ 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_delete(ldb_test_ctx->ldb, del_dn);
- assert_int_equal(ret, LDB_SUCCESS);
+ /*
+ * The search just needs to call DONE, we don't care about the
+ * contents of the search for this test
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ basedn,
+ LDB_SCOPE_SUBTREE,
+ "(&(!(filterAttr=*))"
+ "(cn=test_search_cn))",
+ NULL,
+ NULL,
+ NULL,
+ test_ldb_modify_before_ldb_wait_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
- assert_dn_doesnt_exist(ldb_test_ctx,
- "@ATTRIBUTES");
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
- ldb_test_remove_data(ldb_test_ctx, ldb_test_ctx,
- "cn=CaseInsensitiveValue");
+ child_pid = fork();
+ if (child_pid == 0) {
+ TALLOC_CTX *tmp_ctx = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *el;
+ TALLOC_FREE(search_test_ctx->ldb_test_ctx->ldb);
+ TALLOC_FREE(search_test_ctx->ldb_test_ctx->ev);
+ close(pipes[0]);
+ search_test_ctx->ldb_test_ctx->ev = tevent_context_init(search_test_ctx->ldb_test_ctx);
+ if (search_test_ctx->ldb_test_ctx->ev == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
- ldbtest_teardown((void **) &ldb_test_ctx);
- return 0;
-}
+ search_test_ctx->ldb_test_ctx->ldb = ldb_init(search_test_ctx->ldb_test_ctx,
+ search_test_ctx->ldb_test_ctx->ev);
+ if (search_test_ctx->ldb_test_ctx->ldb == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
-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);
+ ret = ldb_connect(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx->ldb_test_ctx->dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ exit(ret);
+ }
- /* cn matches exact case */
- cnt = sub_search_count(ldb_test_ctx, "", "cn=CaseInsensitiveValue");
- assert_int_equal(cnt, 1);
+ tmp_ctx = talloc_new(search_test_ctx->ldb_test_ctx);
+ if (tmp_ctx == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
- /* cn matches lower case */
- cnt = sub_search_count(ldb_test_ctx, "", "cn=caseinsensitivevalue");
- assert_int_equal(cnt, 1);
+ msg = ldb_msg_new(tmp_ctx);
+ if (msg == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
- /* uid matches exact case */
- cnt = sub_search_count(ldb_test_ctx, "", "uid=CaseSensitiveValue");
- assert_int_equal(cnt, 1);
+ /*
+ * We must re-create this DN from a string to ensure
+ * it does not reference the now-gone LDB context of
+ * the parent
+ */
+ msg->dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
- /* uid does not match lower case */
- cnt = sub_search_count(ldb_test_ctx, "", "uid=casesensitivevalue");
- assert_int_equal(cnt, 0);
-}
+ if (msg->dn == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
-static struct ldb_schema_attribute cn_attr_1;
-static struct ldb_schema_attribute cn_attr_2;
-static struct ldb_schema_attribute default_attr;
+ ret = ldb_msg_add_string(msg, "filterAttr", "TRUE");
+ if (ret != 0) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el = ldb_msg_find_element(msg, "filterAttr");
+ if (el == NULL) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ el->flags = LDB_FLAG_MOD_REPLACE;
-/*
- override the name to attribute handler function
- */
-static const struct ldb_schema_attribute *ldb_test_attribute_handler_override(struct ldb_context *ldb,
- void *private_data,
- const char *name)
-{
- if (private_data != NULL && ldb_attr_cmp(name, "cn") == 0) {
+ ret = ldb_transaction_start(search_test_ctx->ldb_test_ctx->ldb);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ if (write(pipes[1], "GO", 2) != 2) {
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb, msg);
+ if (ret != 0) {
+ exit(ret);
+ }
+
+ ret = ldb_transaction_commit(search_test_ctx->ldb_test_ctx->ldb);
+ exit(ret);
+ }
+ close(pipes[1]);
+
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ sleep(3);
+
+ /*
+ * If writes are not blocked until after the (never called) ldb_wait(), we
+ * will be able to successfully search for this modification
+ * here
+ */
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb, search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+
+ /*
+ * We avoid making assertions before TALLOC_FREE()ing the request,
+ * lest the assert fail and mess with the clean-up because we still
+ * have locks.
+ */
+ res_count = res2->count;
+ TALLOC_FREE(req);
+
+ /* We should not have got the result */
+ assert_int_equal(res_count, 0);
+ assert_int_equal(ret, 0);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ /*
+ * If writes are blocked until after the search request was freed, we
+ * will be able to successfully search for this modification
+ * now
+ */
+
+ search_dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn,"
+ "dc=search_test_entry");
+
+ ret = ldb_search(search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ &res2, search_dn, LDB_SCOPE_BASE, NULL,
+ "filterAttr=TRUE");
+ assert_int_equal(ret, 0);
+
+ /* We got the result */
+ assert_int_equal(res2->count, 1);
+}
+
+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" },
+ { "objectUUID", "0123456789abcdef" },
+ { 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);
+}
+
+static struct ldb_schema_attribute cn_attr_1;
+static struct ldb_schema_attribute cn_attr_2;
+static struct ldb_schema_attribute default_attr;
+
+/*
+ override the name to attribute handler function
+ */
+static const struct ldb_schema_attribute *ldb_test_attribute_handler_override(struct ldb_context *ldb,
+ void *private_data,
+ const char *name)
+{
+ if (private_data != NULL && ldb_attr_cmp(name, "cn") == 0) {
return &cn_attr_1;
} else if (private_data == NULL && ldb_attr_cmp(name, "cn") == 0) {
return &cn_attr_2;
syntax, &cn_attr_2);
assert_int_equal(ret, LDB_SUCCESS);
+ syntax = ldb_standard_syntax_by_name(ldb, LDB_SYNTAX_OCTET_STRING);
+ assert_non_null(syntax);
+
+ ret = ldb_schema_attribute_fill_with_syntax(ldb, ldb,
+ "", 0,
+ syntax, &default_attr);
+ assert_int_equal(ret, LDB_SUCCESS);
+
/*
* Set an attribute handler
*/
/* Add the index (actually any modify will do) */
while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+ ldif->msg->elements[0].flags = LDB_FLAG_MOD_ADD;
+ ret = ldb_modify(ldb_test_ctx->ldb,
+ ldif->msg);
+ }
assert_int_equal(ret, LDB_SUCCESS);
}
add_dn_with_cn(ldb_test_ctx,
rename_test_ctx->basedn,
- "test_rename_cn_val");
+ "test_rename_cn_val",
+ "0123456789abcde0");
*state = rename_test_ctx;
return 0;
add_dn_with_cn(rename_test_ctx->ldb_test_ctx,
new_dn,
- "test_rename_cn_val");
+ "test_rename_cn_val",
+ "0123456789abcde1");
ret = ldb_rename(rename_test_ctx->ldb_test_ctx->ldb,
rename_test_ctx->basedn,
/* FIXME - test the values didn't change */
}
-int main(int argc, const char **argv)
+static int ldb_read_only_setup(void **state)
{
- 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),
- 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),
- cmocka_unit_test_setup_teardown(test_ldb_handle,
- ldbtest_setup,
- ldbtest_teardown),
- cmocka_unit_test_setup_teardown(test_ldb_build_search_req,
- ldbtest_setup,
- ldbtest_teardown),
- 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),
- 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),
- cmocka_unit_test_setup_teardown(test_ldb_search_against_transaction,
- ldb_search_test_setup,
- ldb_search_test_teardown),
- cmocka_unit_test_setup_teardown(test_ldb_modify_during_unindexed_search,
- ldb_search_test_setup,
- ldb_search_test_teardown),
- cmocka_unit_test_setup_teardown(test_ldb_modify_during_indexed_search,
- ldb_search_test_setup,
- ldb_search_test_teardown),
- cmocka_unit_test_setup_teardown(test_ldb_rename_during_unindexed_search,
- ldb_search_test_setup,
- ldb_search_test_teardown),
- cmocka_unit_test_setup_teardown(test_ldb_rename_during_indexed_search,
- ldb_search_test_setup,
- ldb_search_test_teardown),
- cmocka_unit_test_setup_teardown(test_ldb_modify_during_whole_search,
+ struct ldbtest_ctx *test_ctx;
+
+ ldbtest_setup((void **) &test_ctx);
+
+ *state = test_ctx;
+ return 0;
+}
+
+static int ldb_read_only_teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ ldbtest_teardown((void **) &test_ctx);
+ return 0;
+}
+
+static void test_read_only(void **state)
+{
+ struct ldb_context *ro_ldb = NULL;
+ struct ldb_context *rw_ldb = NULL;
+ int ret;
+ TALLOC_CTX *tmp_ctx = NULL;
+
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ /*
+ * Close the ldb context freeing it this will ensure it exists on
+ * disk and can be opened in read only mode
+ */
+ TALLOC_FREE(test_ctx->ldb);
+
+ /*
+ * Open the database in read only and read write mode,
+ * ensure it's opend in read only mode first
+ */
+ ro_ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ro_ldb, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ rw_ldb = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(rw_ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+
+ /*
+ * Set up a context for the temporary variables
+ */
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ /*
+ * Ensure that we can search the read write database
+ */
+ {
+ struct ldb_result *result = NULL;
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, rw_ldb,
+ "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_search(rw_ldb, tmp_ctx, &result, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(result);
+ TALLOC_FREE(dn);
+ }
+
+ /*
+ * Ensure that we can search the read only database
+ */
+ {
+ struct ldb_result *result = NULL;
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, ro_ldb,
+ "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_search(ro_ldb, tmp_ctx, &result, dn,
+ LDB_SCOPE_BASE, NULL, NULL);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(result);
+ TALLOC_FREE(dn);
+ }
+ /*
+ * Ensure that a write to the read only database fails
+ */
+ {
+ struct ldb_message *msg = NULL;
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, ro_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_msg_add_string(msg, "objectUUID",
+ "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(ro_ldb, msg);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+ TALLOC_FREE(msg);
+ }
+
+ /*
+ * Ensure that a write to the read write database succeeds
+ */
+ {
+ struct ldb_message *msg = NULL;
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(msg, rw_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_msg_add_string(msg, "objectUUID",
+ "0123456789abcde2");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(rw_ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(msg);
+ }
+
+ /*
+ * Ensure that a delete from a read only database fails
+ */
+ {
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, ro_ldb, "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_delete(ro_ldb, dn);
+ assert_int_equal(ret, LDB_ERR_UNWILLING_TO_PERFORM);
+ TALLOC_FREE(dn);
+ }
+
+
+ /*
+ * Ensure that a delete from a read write succeeds
+ */
+ {
+ struct ldb_dn *dn = ldb_dn_new_fmt(tmp_ctx, rw_ldb, "dc=test");
+ assert_non_null(dn);
+
+ ret = ldb_delete(rw_ldb, dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+ TALLOC_FREE(dn);
+ }
+ TALLOC_FREE(tmp_ctx);
+}
+
+static bool unique_values = false;
+
+static int unique_index_test_module_add(
+ struct ldb_module *module,
+ struct ldb_request *req)
+{
+ if (unique_values) {
+ struct ldb_message *msg = discard_const(req->op.add.message);
+ struct ldb_message_element *el = NULL;
+ el = ldb_msg_find_element(msg, "cn");
+ if (el != NULL) {
+ el->flags |= LDB_FLAG_INTERNAL_FORCE_UNIQUE_INDEX;
+ }
+ }
+
+ return ldb_next_request(module, req);
+}
+
+static int unique_index_test_module_init(struct ldb_module *module)
+{
+ return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_unique_index_test_module_ops = {
+ .name = "unique_index_test",
+ .init_context = unique_index_test_module_init,
+ .add = unique_index_test_module_add,
+};
+
+static int ldb_unique_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: UNIQUE_INDEX\n"
+ "\n";
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+#ifdef GUID_IDX
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+#endif
+ "\n";
+ const char *options[] = {"modules:unique_index_test", NULL};
+
+
+ ret = ldb_register_module(&ldb_unique_index_test_module_ops);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_ENTRY_ALREADY_EXISTS);
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ 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);
+ }
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ unique_values = true;
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_unique_index_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,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(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);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+
+static void test_ldb_add_unique_value_to_unique_index(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_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg, "objectUUID",
+ "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ talloc_free(tmp_ctx);
+}
+
+static int ldb_non_unique_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+#ifdef GUID_IDX
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+#endif
+ "\n";
+ const char *options[] = {"modules:unique_index_test", NULL};
+
+
+ ret = ldb_register_module(&ldb_unique_index_test_module_ops);
+ assert_true(ret == LDB_SUCCESS || ret == LDB_ERR_ENTRY_ALREADY_EXISTS);
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, options);
+ assert_int_equal(ret, 0);
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ unique_values = true;
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_non_unique_index_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,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(del_dn);
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+static void test_ldb_add_duplicate_value_to_unique_index(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ 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);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_to_index_duplicates_allowed(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ unique_values = false;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_SUCCESS);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_add_to_index_unique_values_required(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+
+ unique_values = true;
+
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+ talloc_free(tmp_ctx);
+}
+
+static void ldb_debug_string(void *context, enum ldb_debug_level level,
+ const char *fmt, va_list ap)
+{
+
+ if (level <= LDB_DEBUG_WARNING) {
+ *((char **)context) = talloc_vasprintf(NULL, fmt, ap);
+ }
+}
+
+static void test_ldb_unique_index_duplicate_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+ char *p = NULL;
+
+ /* The GUID mode is not compatible with this test */
+#ifdef GUID_IDX
+ return;
+#endif
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+
+ assert_non_null(debug_string);
+ p = strstr(
+ debug_string,
+ "unique index violation on cn "
+ "in dc=test02, conficts with dc=test01 in "
+ "@INDEX:CN:test_unique_index");
+ assert_non_null(p);
+ TALLOC_FREE(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_duplicate_dn_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+
+ /* The GUID mode is not compatible with this test */
+#ifdef GUID_IDX
+ return;
+#endif
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index01");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID",
+ "0123456789abcde1");
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index02");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ assert_null(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static int ldb_guid_index_test_setup(void **state)
+{
+ int ret;
+ struct ldb_ldif *ldif;
+ struct ldbtest_ctx *ldb_test_ctx;
+ const char *attrs_ldif = \
+ "dn: @ATTRIBUTES\n"
+ "cn: UNIQUE_INDEX\n"
+ "\n";
+ const char *index_ldif = \
+ "dn: @INDEXLIST\n"
+ "@IDXATTR: cn\n"
+ "@IDXGUID: objectUUID\n"
+ "@IDX_DN_GUID: GUID\n"
+ "\n";
+
+ ldbtest_noconn_setup((void **) &ldb_test_ctx);
+
+
+ ret = ldb_connect(ldb_test_ctx->ldb, ldb_test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ 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);
+ }
+
+ while ((ldif = ldb_ldif_read_string(ldb_test_ctx->ldb, &index_ldif))) {
+ ret = ldb_add(ldb_test_ctx->ldb, ldif->msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ *state = ldb_test_ctx;
+ return 0;
+}
+
+static int ldb_guid_index_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,
+ "@INDEXLIST");
+ assert_non_null(del_dn);
+
+ ret = ldb_delete(ldb_test_ctx->ldb, del_dn);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@INDEXLIST");
+
+ TALLOC_FREE(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);
+ if (ret != LDB_ERR_NO_SUCH_OBJECT) {
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ assert_dn_doesnt_exist(ldb_test_ctx,
+ "@ATTRIBUTES");
+
+ ldbtest_teardown((void **) &ldb_test_ctx);
+ return 0;
+}
+
+
+static void test_ldb_unique_index_duplicate_with_guid(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+ char *p = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test02");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID", "0123456789abcde0");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_CONSTRAINT_VIOLATION);
+
+ assert_non_null(debug_string);
+ p = strstr(
+ debug_string,
+ "unique index violation on cn in dc=test02, conficts with "
+ "objectUUID 0123456789abcdef in @INDEX:CN:test_unique_index");
+ assert_non_null(p);
+ TALLOC_FREE(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_guid_index_duplicate_dn_logging(void **state)
+{
+ int ret;
+ struct ldb_message *msg01;
+ struct ldb_message *msg02;
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ TALLOC_CTX *tmp_ctx;
+ char *debug_string = NULL;
+
+ ldb_set_debug(test_ctx->ldb, ldb_debug_string, &debug_string);
+ tmp_ctx = talloc_new(test_ctx);
+ assert_non_null(tmp_ctx);
+
+ msg01 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg01);
+
+ msg01->dn = ldb_dn_new_fmt(msg01, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg01->dn);
+
+ ret = ldb_msg_add_string(msg01, "cn", "test_unique_index01");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg01, "objectUUID", "0123456789abcdef");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg01);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ msg02 = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg02);
+
+ msg02->dn = ldb_dn_new_fmt(msg02, test_ctx->ldb, "dc=test01");
+ assert_non_null(msg02->dn);
+
+ ret = ldb_msg_add_string(msg02, "cn", "test_unique_index02");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_msg_add_string(msg02, "objectUUID", "0123456789abcde1");
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_add(test_ctx->ldb, msg02);
+ assert_int_equal(ret, LDB_ERR_ENTRY_ALREADY_EXISTS);
+
+ assert_null(debug_string);
+ talloc_free(tmp_ctx);
+}
+
+static void test_ldb_talloc_destructor_transaction_cleanup(void **state)
+{
+ struct ldbtest_ctx *test_ctx = NULL;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ ldb_transaction_start(test_ctx->ldb);
+
+ /*
+ * Trigger the destructor
+ */
+ TALLOC_FREE(test_ctx->ldb);
+
+ /*
+ * Now ensure that a new connection can be opened
+ */
+ {
+ TALLOC_CTX *tctx = talloc_new(test_ctx);
+ struct ldbtest_ctx *ctx = talloc_zero(tctx, struct ldbtest_ctx);
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+ int ret;
+
+ ldbtest_setup((void *)&ctx);
+
+ basedn = ldb_dn_new_fmt(tctx, ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(ctx->ldb,
+ tctx,
+ &result,
+ basedn,
+ LDB_SCOPE_BASE,
+ NULL,
+ NULL);
+ assert_int_equal(ret, 0);
+ assert_non_null(result);
+ assert_int_equal(result->count, 0);
+
+ ldbtest_teardown((void *)&ctx);
+ }
+}
+
+static void test_transaction_start_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ close(pipes[0]);
+ ret = ldb_transaction_start(ldb1);
+ if (ret != LDB_ERR_PROTOCOL_ERROR) {
+ print_error(__location__": ldb_transaction_start "
+ "returned (%d) %s\n",
+ ret,
+ ldb1->err_string);
+ exit(LDB_ERR_OTHER);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+static void test_transaction_commit_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_transaction_start(ldb1);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ close(pipes[0]);
+ ret = ldb_transaction_commit(ldb1);
+
+ if (ret != LDB_ERR_PROTOCOL_ERROR) {
+ print_error(__location__": ldb_transaction_commit "
+ "returned (%d) %s\n",
+ ret,
+ ldb1->err_string);
+ exit(LDB_ERR_OTHER);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+}
+
+static void test_lock_read_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+
+ close(pipes[0]);
+
+ basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb,
+ test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_BASE,
+ NULL,
+ NULL);
+ if (ret != LDB_ERR_PROTOCOL_ERROR) {
+ print_error(__location__": ldb_search "
+ "returned (%d) %s\n",
+ ret,
+ ldb1->err_string);
+ exit(LDB_ERR_OTHER);
+ }
+
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 0);
+
+ {
+ /*
+ * Ensure that the search actually succeeds on the opening
+ * pid
+ */
+ struct ldb_dn *basedn;
+ struct ldb_result *result = NULL;
+
+ close(pipes[0]);
+
+ basedn = ldb_dn_new_fmt(test_ctx, test_ctx->ldb, "dc=test");
+ assert_non_null(basedn);
+
+ ret = ldb_search(test_ctx->ldb,
+ test_ctx,
+ &result,
+ basedn,
+ LDB_SCOPE_BASE,
+ NULL,
+ NULL);
+ assert_int_equal(0, ret);
+ }
+}
+
+static void test_multiple_opens_across_fork(void **state)
+{
+ struct ldb_context *ldb1 = NULL;
+ struct ldb_context *ldb2 = NULL;
+ int ret;
+ struct ldbtest_ctx *test_ctx = NULL;
+ int pipes[2];
+ char buf[2];
+ int wstatus;
+ pid_t pid, child_pid;
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ /*
+ * Open the database again
+ */
+ ldb1 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb1, test_ctx->dbpath, LDB_FLG_RDONLY, NULL);
+ assert_int_equal(ret, 0);
+
+ ldb2 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb2, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(ret, 0);
+
+ ret = pipe(pipes);
+ assert_int_equal(ret, 0);
+
+ child_pid = fork();
+ if (child_pid == 0) {
+ struct ldb_context *ldb3 = NULL;
+
+ close(pipes[0]);
+ ldb3 = ldb_init(test_ctx, test_ctx->ev);
+ ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
+ if (ret != 0) {
+ print_error(__location__": ldb_connect returned (%d)\n",
+ ret);
+ exit(ret);
+ }
+ ret = write(pipes[1], "GO", 2);
+ if (ret != 2) {
+ print_error(__location__
+ " write returned (%d)",
+ ret);
+ exit(LDB_ERR_OPERATIONS_ERROR);
+ }
+ exit(LDB_SUCCESS);
+ }
+ close(pipes[1]);
+ ret = read(pipes[0], buf, 2);
+ assert_int_equal(ret, 2);
+
+ pid = waitpid(child_pid, &wstatus, 0);
+ assert_int_equal(pid, child_pid);
+
+ assert_true(WIFEXITED(wstatus));
+
+ assert_int_equal(WEXITSTATUS(wstatus), 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),
+ cmocka_unit_test_setup_teardown(test_ldif_message,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldif_message_redacted,
+ ldbtest_noconn_setup,
+ ldbtest_noconn_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_add,
+ ldbtest_setup,
+ ldbtest_teardown),
+ 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),
+ cmocka_unit_test_setup_teardown(test_ldb_handle,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_build_search_req,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_transactions,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(test_nested_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),
+ 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),
+ cmocka_unit_test_setup_teardown(test_ldb_search_against_transaction,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_rename_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_during_whole_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_modify_before_ldb_wait,
ldb_search_test_setup,
ldb_search_test_teardown),
cmocka_unit_test_setup_teardown(test_ldb_attrs_case_insensitive,
cmocka_unit_test_setup_teardown(test_ldb_rename_dn_case_change,
ldb_rename_test_setup,
ldb_rename_test_teardown),
+ cmocka_unit_test_setup_teardown(test_read_only,
+ ldb_read_only_setup,
+ ldb_read_only_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_unique_value_to_unique_index,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_duplicate_value_to_unique_index,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_to_index_duplicates_allowed,
+ ldb_non_unique_index_test_setup,
+ ldb_non_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_add_to_index_unique_values_required,
+ ldb_non_unique_index_test_setup,
+ ldb_non_unique_index_test_teardown),
+ /* These tests are not compatible with mdb */
+ cmocka_unit_test_setup_teardown(
+ test_ldb_unique_index_duplicate_logging,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_duplicate_dn_logging,
+ ldb_unique_index_test_setup,
+ ldb_unique_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_guid_index_duplicate_dn_logging,
+ ldb_guid_index_test_setup,
+ ldb_guid_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_unique_index_duplicate_with_guid,
+ ldb_guid_index_test_setup,
+ ldb_guid_index_test_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_ldb_talloc_destructor_transaction_cleanup,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_transaction_start_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_transaction_commit_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_lock_read_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
+ cmocka_unit_test_setup_teardown(
+ test_multiple_opens_across_fork,
+ ldbtest_setup,
+ ldbtest_teardown),
};
return cmocka_run_group_tests(tests, NULL, NULL);