summaryrefslogtreecommitdiff
path: root/lib/ldb/tests/ldb_mod_op_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ldb/tests/ldb_mod_op_test.c')
-rw-r--r--lib/ldb/tests/ldb_mod_op_test.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c
index 0f8642d00a9..c8b9c1aa9ff 100644
--- a/lib/ldb/tests/ldb_mod_op_test.c
+++ b/lib/ldb/tests/ldb_mod_op_test.c
@@ -2384,6 +2384,269 @@ static void test_ldb_modify_before_ldb_wait(void **state)
assert_int_equal(res2->count, 1);
}
+/*
+ * This test is also complex.
+ * The purpose is to test if a modify can occur during an ldb_search()
+ * This would be a failure if if in process
+ * (1) and (2):
+ * - (1) ltdb_search() starts and calls back for one entry
+ * - (2) one of the entries to be matched is modified
+ * - (1) the indexed search tries to return the modified entry, but
+ * it is no longer found, either:
+ * - despite it still matching (dn changed)
+ * - it no longer matching (attrs changed)
+ *
+ * We also try un-indexed to show that the behaviour differs on this
+ * point, which it should not (an index should only impact search
+ * speed).
+ */
+
+/*
+ * This purpose of this callback is to trigger a write in the callback
+ * so as to change in in-memory index code while looping over the
+ * index result.
+ */
+
+static int test_ldb_callback_modify_during_search_callback1(struct ldb_request *req,
+ struct ldb_reply *ares)
+{
+ int ret;
+ struct modify_during_search_test_ctx *ctx = req->context;
+ struct ldb_dn *dn = NULL, *new_dn = NULL;
+ TALLOC_CTX *tmp_ctx = talloc_new(ctx->test_ctx);
+ struct ldb_message *msg = NULL;
+
+ assert_non_null(tmp_ctx);
+
+ switch (ares->type) {
+ case LDB_REPLY_ENTRY:
+ {
+ const struct ldb_val *cn_val
+ = ldb_dn_get_component_val(ares->message->dn, 0);
+ const char *cn = (char *)cn_val->data;
+ ctx->res_count++;
+ if (strcmp(cn, "test_search_cn") == 0) {
+ ctx->got_cn = true;
+ } else if (strcmp(cn, "test_search_2_cn") == 0) {
+ ctx->got_2_cn = true;
+ }
+ if (ctx->res_count == 2) {
+ return LDB_SUCCESS;
+ }
+ break;
+ }
+ case LDB_REPLY_REFERRAL:
+ return LDB_SUCCESS;
+
+ case LDB_REPLY_DONE:
+ return ldb_request_done(req, LDB_SUCCESS);
+ }
+
+ if (ctx->rename) {
+ if (ctx->got_2_cn) {
+ /* Modify this one */
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ } else {
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ }
+ assert_non_null(dn);
+
+ new_dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_cn_renamed,"
+ "dc=not_search_test_entry");
+ assert_non_null(new_dn);
+
+ ret = ldb_rename(ctx->test_ctx->ldb, dn, new_dn);
+ assert_int_equal(ret, 0);
+
+ } else {
+ if (ctx->got_2_cn) {
+ /* Delete this one */
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_2_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ } else {
+ dn = ldb_dn_new_fmt(tmp_ctx,
+ ctx->test_ctx->ldb,
+ "cn=test_search_cn,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+ }
+ assert_non_null(dn);
+
+ ret = ldb_delete(ctx->test_ctx->ldb, dn);
+ assert_int_equal(ret, 0);
+ }
+
+ /*
+ * Now fill in the position we just removed from the
+ * index to ensure we fail the test (otherwise we just read
+ * past the end of the array and find the value we wanted to
+ * skip)
+ */
+ msg = ldb_msg_new(tmp_ctx);
+ assert_non_null(msg);
+
+ /* We deliberatly use ou= not cn= here */
+ msg->dn = ldb_dn_new_fmt(msg,
+ ctx->test_ctx->ldb,
+ "ou=test_search_cn_extra,%s",
+ ldb_dn_get_linearized(ctx->basedn));
+
+ ret = ldb_msg_add_string(msg,
+ "objectUUID",
+ "0123456789abcde3");
+
+ ret = ldb_add(ctx->test_ctx->ldb,
+ msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ TALLOC_FREE(tmp_ctx);
+ return LDB_SUCCESS;
+}
+
+static void test_ldb_callback_modify_during_search(void **state, bool add_index,
+ bool rename)
+{
+ struct search_test_ctx *search_test_ctx = talloc_get_type_abort(*state,
+ struct search_test_ctx);
+ struct modify_during_search_test_ctx
+ ctx =
+ { .res_count = 0,
+ .test_ctx = search_test_ctx->ldb_test_ctx,
+ .rename = rename
+ };
+
+ int ret;
+ struct ldb_request *req;
+
+ ret = ldb_transaction_start(search_test_ctx->ldb_test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ if (add_index) {
+ struct ldb_message *msg;
+ struct ldb_dn *indexlist = ldb_dn_new(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "@INDEXLIST");
+ assert_non_null(indexlist);
+
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = indexlist;
+
+ ret = ldb_msg_add_string(msg, "@IDXONE", "1");
+ assert_int_equal(ret, LDB_SUCCESS);
+ 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;
+ msg->elements[1].flags = LDB_FLAG_MOD_ADD;
+ ret = ldb_modify(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ }
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ /*
+ * Now bring the IDXONE index into memory by modifying
+ * it. This exposes an issue in ldb_tdb
+ */
+ msg = ldb_msg_new(search_test_ctx);
+ assert_non_null(msg);
+
+ msg->dn = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "cn=test_search_cn_extra,%s",
+ search_test_ctx->base_dn);
+
+ ret = ldb_msg_add_string(msg,
+ "objectUUID",
+ "0123456789abcde2");
+
+ ret = ldb_add(search_test_ctx->ldb_test_ctx->ldb,
+ msg);
+ assert_int_equal(ret, LDB_SUCCESS);
+
+ ret = ldb_delete(search_test_ctx->ldb_test_ctx->ldb,
+ msg->dn);
+ assert_int_equal(ret, LDB_SUCCESS);
+ }
+
+ tevent_loop_allow_nesting(search_test_ctx->ldb_test_ctx->ev);
+
+ ctx.basedn
+ = ldb_dn_new_fmt(search_test_ctx,
+ search_test_ctx->ldb_test_ctx->ldb,
+ "%s",
+ search_test_ctx->base_dn);
+ assert_non_null(ctx.basedn);
+
+
+ /*
+ * This search must be over multiple items, and should include
+ * the new name after a rename, to show that it would match
+ * both before and after that modify
+ *
+ * This needs to be a search that isn't matched by an index so
+ * that we just use the one-level index.
+ */
+ ret = ldb_build_search_req(&req,
+ search_test_ctx->ldb_test_ctx->ldb,
+ search_test_ctx,
+ ctx.basedn,
+ LDB_SCOPE_ONELEVEL,
+ "(cn=*)",
+ NULL,
+ NULL,
+ &ctx,
+ test_ldb_callback_modify_during_search_callback1,
+ NULL);
+ assert_int_equal(ret, 0);
+
+ ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req);
+
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ assert_int_equal(ret, 0);
+
+ ret = ldb_transaction_commit(search_test_ctx->ldb_test_ctx->ldb);
+ assert_int_equal(ret, 0);
+
+ assert_int_equal(ctx.res_count, 2);
+ assert_int_equal(ctx.got_cn, true);
+ assert_int_equal(ctx.got_2_cn, true);
+}
+
+static void test_ldb_callback_delete_during_indexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, true, false);
+}
+
+static void test_ldb_callback_delete_during_unindexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, false, false);
+}
+
+static void test_ldb_callback_rename_during_indexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, true, true);
+}
+
+static void test_ldb_callback_rename_during_unindexed_search(void **state)
+{
+ test_ldb_callback_modify_during_search(state, false, true);
+}
+
static int ldb_case_test_setup(void **state)
{
int ret;
@@ -3692,6 +3955,18 @@ int main(int argc, const char **argv)
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_callback_rename_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_rename_during_indexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_delete_during_unindexed_search,
+ ldb_search_test_setup,
+ ldb_search_test_teardown),
+ cmocka_unit_test_setup_teardown(test_ldb_callback_delete_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),