From: Gary Lockyer Date: Fri, 2 Feb 2018 02:30:53 +0000 (+1300) Subject: ldb_mdb/tests: Add tests to check for max key length and DB size X-Git-Tag: ldb-1.4.0~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5a000b68ec8875bcc86217a6c32a97fc3d2723f;p=thirdparty%2Fsamba.git ldb_mdb/tests: Add tests to check for max key length and DB size Signed-off-by: Gary Lockyer Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam --- diff --git a/lib/ldb/tests/ldb_lmdb_size_test.c b/lib/ldb/tests/ldb_lmdb_size_test.c new file mode 100644 index 00000000000..af015fa72b5 --- /dev/null +++ b/lib/ldb/tests/ldb_lmdb_size_test.c @@ -0,0 +1,210 @@ +/* + * lmdb backend specific tests for ldb + * Tests for truncated index keys + * + * Copyright (C) Andrew Bartlett 2018 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* + * These tests confirm that database sizes of > 4GB are supported + * Due to the disk space requirement they are not run as part of the normal + * self test runs. + * + * Setup and tear down code copied from ldb_mod_op_test.c + */ + +/* + * from cmocka.c: + * These headers or their equivalents should be included prior to + * including + * this header file. + * + * #include + * #include + * #include + * + * This allows test applications to use custom definitions of C standard + * library functions and types. + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +#define TEST_BE "mdb" + +struct ldbtest_ctx { + struct tevent_context *ev; + struct ldb_context *ldb; + + const char *dbfile; + const char *lockfile; /* lockfile is separate */ + + const char *dbpath; +}; + +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; + + 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); + + unlink_old_db(test_ctx); + *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_old_db(test_ctx); + talloc_free(test_ctx); + return 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_db_size_gt_4GB(void **state) +{ + int ret, x; + struct ldb_message *msg; + struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, + struct ldbtest_ctx); + const int MB = 1024 * 1024; + char *blob = NULL; + + TALLOC_CTX *tmp_ctx; + + tmp_ctx = talloc_new(test_ctx); + assert_non_null(tmp_ctx); + + + blob = talloc_zero_size(tmp_ctx, (MB + 1)); + assert_non_null(blob); + memset(blob, 'x', MB); + + + for (x = 0; x < 6144; x++) { + msg = ldb_msg_new(tmp_ctx); + assert_non_null(msg); + + msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test%d", x); + assert_non_null(msg->dn); + + ldb_transaction_start(test_ctx->ldb); + ret = ldb_msg_add_string(msg, "blob", blob); + assert_int_equal(ret, 0); + + ret = ldb_add(test_ctx->ldb, msg); + assert_int_equal(ret, 0); + ldb_transaction_commit(test_ctx->ldb); + + TALLOC_FREE(msg); + } + talloc_free(tmp_ctx); + { + struct stat s; + ret = stat(test_ctx->dbfile, &s); + assert_int_equal(ret, 0); + assert_true(s.st_size > (6144LL * MB)); + } +} + +int main(int argc, const char **argv) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown( + test_db_size_gt_4GB, + ldbtest_setup, + ldbtest_teardown), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/lib/ldb/tests/ldb_lmdb_test.c b/lib/ldb/tests/ldb_lmdb_test.c new file mode 100644 index 00000000000..e47c7dbc70f --- /dev/null +++ b/lib/ldb/tests/ldb_lmdb_test.c @@ -0,0 +1,240 @@ +/* + * lmdb backend specific tests for ldb + * + * Copyright (C) Andrew Bartlett 2018 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* + * lmdb backend specific tests for ldb + * + * Setup and tear down code copied from ldb_mod_op_test.c + */ + +/* + * from cmocka.c: + * These headers or their equivalents should be included prior to + * including + * this header file. + * + * #include + * #include + * #include + * + * This allows test applications to use custom definitions of C standard + * library functions and types. + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +#define TEST_BE "mdb" + +#define LMDB_MAX_KEY_SIZE 511 + +struct ldbtest_ctx { + struct tevent_context *ev; + struct ldb_context *ldb; + + const char *dbfile; + const char *lockfile; /* lockfile is separate */ + + const char *dbpath; +}; + +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; + + 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); + + unlink_old_db(test_ctx); + *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_old_db(test_ctx); + talloc_free(test_ctx); + return 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_key_len_gt_max(void **state) +{ + int ret; + int xs_size = 0; + struct ldb_message *msg; + struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, + struct ldbtest_ctx); + char *xs = NULL; + 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); + + /* + * The zero terminator is part of the key + */ + + xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */ + xs_size += 1; /* want key on char too long */ + xs = talloc_zero_size(tmp_ctx, (xs_size + 1)); + memset(xs, 'x', xs_size); + + msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs); + 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, LDB_ERR_PROTOCOL_ERROR); + + talloc_free(tmp_ctx); +} + +static void test_ldb_add_key_len_eq_max(void **state) +{ + int ret; + int xs_size = 0; + struct ldb_message *msg; + struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, + struct ldbtest_ctx); + char *xs = NULL; + 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); + + /* + * The zero terminator is part of the key + */ + + xs_size = LMDB_MAX_KEY_SIZE - 7; /* "dn=dc=" and the zero terminator */ + xs = talloc_zero_size(tmp_ctx, (xs_size + 1)); + memset(xs, 'x', xs_size); + + msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=%s", xs); + 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_ldb_add_key_len_eq_max, + ldbtest_setup, + ldbtest_teardown), + cmocka_unit_test_setup_teardown( + test_ldb_add_key_len_gt_max, + ldbtest_setup, + ldbtest_teardown), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/lib/ldb/wscript b/lib/ldb/wscript index 8f4501aa796..244060f780a 100644 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -495,6 +495,17 @@ def build(bld): cflags='-DTEST_BE=\"mdb\" -DGUID_IDX=1', deps='cmocka ldb', install=False) + + bld.SAMBA_BINARY('ldb_lmdb_test', + source='tests/ldb_lmdb_test.c', + deps='cmocka ldb', + install=False) + + bld.SAMBA_BINARY('ldb_lmdb_size_test', + source='tests/ldb_lmdb_size_test.c', + deps='cmocka ldb', + install=False) + bld.SAMBA_BINARY('ldb_mdb_kv_ops_test', source='tests/ldb_kv_ops_test.c', cflags='-DTEST_BE=\"mdb\"', @@ -538,7 +549,11 @@ def test(ctx): 'ldb_tdb_guid_mod_op_test', 'ldb_msg_test', 'ldb_tdb_kv_ops_test', - 'ldb_tdb_test'] + 'ldb_tdb_test', + 'ldb_lmdb_test'] + # we don't want to run ldb_lmdb_size_test (which proves we can + # fit > 4G of data into the DB), it would fill up the disk on + # many of our test instances for test_exe in test_exes: cmd = os.path.join(Utils.g_module.blddir, test_exe)