From: Gary Lockyer Date: Thu, 8 Mar 2018 03:47:59 +0000 (+1300) Subject: ldb_mdb/tests: Tests for wrap open X-Git-Tag: ldb-1.4.0~99 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be335f1fbc8ec1c4fb7b329138e742e5f2403b77;p=thirdparty%2Fsamba.git ldb_mdb/tests: Tests for wrap open Tests to ensure that the mdb_env wrapping code correctly handles multiple ldb's point to the same physical database file. The test_ldb_close_with_multiple_connections tests are in ldb_mod_op_test due to the utility code it uses from elsewhere in that test. Signed-off-by: Gary Lockyer Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam --- diff --git a/lib/ldb/tests/ldb_lmdb_test.c b/lib/ldb/tests/ldb_lmdb_test.c index eece2be8057..f2b04ecd0d7 100644 --- a/lib/ldb/tests/ldb_lmdb_test.c +++ b/lib/ldb/tests/ldb_lmdb_test.c @@ -55,8 +55,8 @@ #include -#include - +#include "../ldb_tdb/ldb_tdb.h" +#include "../ldb_mdb/ldb_mdb.h" #define TEST_BE "mdb" @@ -371,6 +371,67 @@ static void test_ldb_add_dn_no_guid_mode(void **state) talloc_free(tmp_ctx); } +static struct MDB_env *get_mdb_env(struct ldb_context *ldb) +{ + void *data = NULL; + struct ltdb_private *ltdb = NULL; + struct lmdb_private *lmdb = NULL; + struct MDB_env *env = NULL; + + data = ldb_module_get_private(ldb->modules); + assert_non_null(data); + + ltdb = talloc_get_type(data, struct ltdb_private); + assert_non_null(ltdb); + + lmdb = ltdb->lmdb_private; + assert_non_null(lmdb); + + env = lmdb->env; + assert_non_null(env); + + return env; +} + +static void test_multiple_opens(void **state) +{ + struct ldb_context *ldb1 = NULL; + struct ldb_context *ldb2 = NULL; + struct ldb_context *ldb3 = NULL; + struct MDB_env *env1 = NULL; + struct MDB_env *env2 = NULL; + struct MDB_env *env3 = NULL; + int ret; + struct ldbtest_ctx *test_ctx = NULL; + + 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, LDB_FLG_RDONLY, NULL); + assert_int_equal(ret, 0); + + ldb3 = ldb_init(test_ctx, test_ctx->ev); + ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL); + assert_int_equal(ret, 0); + /* + * We now have 3 ldb's open pointing to the same on disk database + * they should all share the same MDB_env + */ + env1 = get_mdb_env(ldb1); + env2 = get_mdb_env(ldb2); + env3 = get_mdb_env(ldb3); + + assert_ptr_equal(env1, env2); + assert_ptr_equal(env1, env3); +} + int main(int argc, const char **argv) { const struct CMUnitTest tests[] = { @@ -394,6 +455,10 @@ int main(int argc, const char **argv) test_ldb_add_dn_no_guid_mode, ldbtest_setup_noguid, ldbtest_teardown), + cmocka_unit_test_setup_teardown( + test_multiple_opens, + ldbtest_setup, + ldbtest_teardown), }; return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/lib/ldb/tests/ldb_mod_op_test.c b/lib/ldb/tests/ldb_mod_op_test.c index 67ac024db86..7b6f19c3a18 100644 --- a/lib/ldb/tests/ldb_mod_op_test.c +++ b/lib/ldb/tests/ldb_mod_op_test.c @@ -38,6 +38,12 @@ #define TEST_BE DEFAULT_BE #endif /* TEST_BE */ +#ifdef TEST_LMDB +#include "lmdb.h" +#include "../ldb_tdb/ldb_tdb.h" +#include "../ldb_mdb/ldb_mdb.h" +#endif + struct ldbtest_ctx { struct tevent_context *ev; struct ldb_context *ldb; @@ -3820,6 +3826,167 @@ static void test_ldb_talloc_destructor_transaction_cleanup(void **state) } } +#ifdef TEST_LMDB +static int test_ldb_multiple_connections_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + int ret; + int pipes[2]; + char buf[2]; + int pid, child_pid; + int wstatus; + + switch (ares->type) { + case LDB_REPLY_ENTRY: + break; + + case LDB_REPLY_REFERRAL: + return LDB_SUCCESS; + + case LDB_REPLY_DONE: + return ldb_request_done(req, LDB_SUCCESS); + } + + { + /* + * We open a new ldb on an ldb that is already open and + * then close it. + * + * If the multiple connection wrapping is correct the + * underlying MDB_env will be left open and we should see + * an active reader in the child we fork next + */ + struct ldb_context *ldb = NULL; + struct tevent_context *ev = NULL; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + ev = tevent_context_init(mem_ctx); + assert_non_null(ev); + + ldb = ldb_init(mem_ctx, ev); + assert_non_null(ldb); + + ret = ldb_connect(ldb, TEST_BE"://apitest.ldb" , 0, NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + TALLOC_FREE(ldb); + TALLOC_FREE(mem_ctx); + } + + ret = pipe(pipes); + assert_int_equal(ret, 0); + + child_pid = fork(); + if (child_pid == 0) { + struct MDB_env *env = NULL; + struct MDB_envinfo stat; + close(pipes[0]); + + /* + * Check that there are exactly two readers on the MDB file + * backing the ldb. + * + */ + ret = mdb_env_create(&env); + if (ret != 0) { + print_error(__location__ + " mdb_env_create returned (%d)", + ret); + exit(ret); + } + + ret = mdb_env_open(env, + "apitest.ldb", + MDB_NOSUBDIR | MDB_NOTLS, + 0644); + if (ret != 0) { + print_error(__location__ + " mdb_env_open returned (%d)", + ret); + exit(ret); + } + + ret = mdb_env_info(env, &stat); + if (ret != 0) { + print_error(__location__ + " mdb_env_info returned (%d)", + ret); + exit(ret); + } + if (stat.me_numreaders != 2) { + print_error(__location__ + " Incorrect number of readers (%d)", + stat.me_numreaders); + exit(LDB_ERR_CONSTRAINT_VIOLATION); + } + + 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); + return LDB_SUCCESS; + +} + +static void test_ldb_close_with_multiple_connections(void **state) +{ + struct search_test_ctx *search_test_ctx = NULL; + struct ldb_dn *search_dn = NULL; + struct ldb_request *req = NULL; + int ret = 0; + + search_test_ctx = talloc_get_type_abort(*state, struct search_test_ctx); + assert_non_null(search_test_ctx); + + 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); + + /* + * 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, + search_dn, + LDB_SCOPE_SUBTREE, + "(&(!(filterAttr=*))" + "(cn=test_search_cn))", + NULL, + NULL, + NULL, + test_ldb_multiple_connections_callback, + NULL); + assert_int_equal(ret, 0); + + ret = ldb_request(search_test_ctx->ldb_test_ctx->ldb, req); + assert_int_equal(ret, 0); + + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + assert_int_equal(ret, 0); +} + +#endif + static void test_transaction_start_across_fork(void **state) { struct ldb_context *ldb1 = NULL; @@ -4248,6 +4415,12 @@ int main(int argc, const char **argv) test_ldb_talloc_destructor_transaction_cleanup, ldbtest_setup, ldbtest_teardown), +#ifdef TEST_LMDB + cmocka_unit_test_setup_teardown( + test_ldb_close_with_multiple_connections, + ldb_search_test_setup, + ldb_search_test_teardown), +#endif cmocka_unit_test_setup_teardown( test_transaction_start_across_fork, ldbtest_setup, diff --git a/lib/ldb/wscript b/lib/ldb/wscript index 244060f780a..b8b97191fbb 100644 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -492,8 +492,9 @@ def build(bld): if bld.CONFIG_SET('HAVE_LMDB'): bld.SAMBA_BINARY('ldb_mdb_mod_op_test', source='tests/ldb_mod_op_test.c', - cflags='-DTEST_BE=\"mdb\" -DGUID_IDX=1', - deps='cmocka ldb', + cflags='-DTEST_BE=\"mdb\" -DGUID_IDX=1 ' + + '-DTEST_LMDB=1', + deps='cmocka ldb lmdb', install=False) bld.SAMBA_BINARY('ldb_lmdb_test',