TODO: ldb_mdb/tests: Add tests to check for max key length and DB size
authorGary Lockyer <gary@catalyst.net.nz>
Fri, 2 Feb 2018 02:30:53 +0000 (15:30 +1300)
committerStefan Metzmacher <metze@samba.org>
Thu, 12 Apr 2018 14:27:17 +0000 (16:27 +0200)
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
TODO: is "# we don't want to run ldb_lmdb_size_test" correct?

lib/ldb/tests/ldb_lmdb_size_test.c [new file with mode: 0644]
lib/ldb/tests/ldb_lmdb_test.c [new file with mode: 0644]
lib/ldb/wscript

diff --git a/lib/ldb/tests/ldb_lmdb_size_test.c b/lib/ldb/tests/ldb_lmdb_size_test.c
new file mode 100644 (file)
index 0000000..af015fa
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * lmdb backend specific tests for ldb
+ * Tests for truncated index keys
+ *
+ *  Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * 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 <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 <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include <lmdb.h>
+
+
+#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 (file)
index 0000000..e47c7db
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * lmdb backend specific tests for ldb
+ *
+ *  Copyright (C) Andrew Bartlett <abartlet@samba.org> 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * 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 <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 <errno.h>
+#include <unistd.h>
+#include <talloc.h>
+#include <tevent.h>
+#include <ldb.h>
+#include <ldb_module.h>
+#include <ldb_private.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sys/wait.h>
+
+#include <lmdb.h>
+
+
+#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);
+}
index 2ef6305eba2ac45c59282fb0e288bcf8a3ae6938..bdfc39100153644285ea37509b42e8b46a7f5da1 100644 (file)
@@ -446,6 +446,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\"',
@@ -497,6 +508,8 @@ def test(ctx):
 
     if env.ENABLE_MDB_BACKEND:
         test_exes.append('ldb_mdb_mod_op_test')
+        test_exes.append('ldb_lmdb_test')
+        # we don't want to run ldb_lmdb_size_test
         test_exes.append('ldb_mdb_kv_ops_test')
     for test_exe in test_exes:
             cmd = os.path.join(Utils.g_module.blddir, test_exe)