1 /* 2 * lmdb backend specific tests for ldb 3 * Tests for truncated index keys 4 * 5 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * 20 */ 21 22 /* 23 * These tests confirm that database sizes of > 4GB are supported 24 * Due to the disk space requirement they are not run as part of the normal 25 * self test runs. 26 * 27 * Setup and tear down code copied from ldb_mod_op_test.c 28 */ 29 30 /* 31 * from cmocka.c: 32 * These headers or their equivalents should be included prior to 33 * including 34 * this header file. 35 * tevent_req_is_unix_error(struct tevent_req * req,int * perrno)36 * #include <stdarg.h> 37 * #include <stddef.h> 38 * #include <setjmp.h> 39 * 40 * This allows test applications to use custom definitions of C standard 41 * library functions and types. 42 * 43 */ 44 #include <stdarg.h> 45 #include <stddef.h> 46 #include <stdint.h> 47 #include <setjmp.h> 48 #include <cmocka.h> 49 50 #include <errno.h> 51 #include <unistd.h> 52 #include <talloc.h> 53 #include <tevent.h> 54 #include <ldb.h> 55 #include <ldb_module.h> 56 #include <ldb_private.h> 57 #include <string.h> 58 #include <ctype.h> 59 60 #include <sys/wait.h> 61 62 #include <lmdb.h> 63 64 65 #define TEST_BE "mdb" 66 67 struct ldbtest_ctx { 68 struct tevent_context *ev; 69 struct ldb_context *ldb; 70 71 const char *dbfile; 72 const char *lockfile; /* lockfile is separate */ 73 74 const char *dbpath; 75 }; accept_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int listen_sock)76 77 static void unlink_old_db(struct ldbtest_ctx *test_ctx) 78 { 79 int ret; 80 81 errno = 0; 82 ret = unlink(test_ctx->lockfile); 83 if (ret == -1 && errno != ENOENT) { 84 fail(); 85 } 86 87 errno = 0; 88 ret = unlink(test_ctx->dbfile); 89 if (ret == -1 && errno != ENOENT) { 90 fail(); 91 } 92 } 93 94 static int ldbtest_noconn_setup(void **state) 95 { 96 struct ldbtest_ctx *test_ctx; 97 accept_handler(struct tevent_context * ev,struct tevent_fd * fde,uint16_t flags,void * private_data)98 test_ctx = talloc_zero(NULL, struct ldbtest_ctx); 99 assert_non_null(test_ctx); 100 101 test_ctx->ev = tevent_context_init(test_ctx); 102 assert_non_null(test_ctx->ev); 103 104 test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev); 105 assert_non_null(test_ctx->ldb); 106 107 test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb"); 108 assert_non_null(test_ctx->dbfile); 109 110 test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock", 111 test_ctx->dbfile); 112 assert_non_null(test_ctx->lockfile); 113 114 test_ctx->dbpath = talloc_asprintf(test_ctx, 115 TEST_BE"://%s", test_ctx->dbfile); 116 assert_non_null(test_ctx->dbpath); 117 118 unlink_old_db(test_ctx); 119 *state = test_ctx; 120 return 0; 121 } 122 123 static int ldbtest_noconn_teardown(void **state) 124 { 125 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, accept_recv(struct tevent_req * req,struct sockaddr * paddr,socklen_t * paddrlen,int * perr)126 struct ldbtest_ctx); 127 128 unlink_old_db(test_ctx); 129 talloc_free(test_ctx); 130 return 0; 131 } 132 133 static int ldbtest_setup(void **state) 134 { 135 struct ldbtest_ctx *test_ctx; 136 int ret; 137 /* 138 * We need to to set GUID index mode as it's required now required 139 * by LDB 140 */ 141 struct ldb_ldif *ldif; 142 const char *index_ldif = 143 "dn: @INDEXLIST\n" 144 "@IDXGUID: objectUUID\n" 145 "@IDX_DN_GUID: GUID\n" 146 "\n"; 147 /* 148 * Set the lmdb map size to 8Gb 149 */ 150 const char *options[] = {"lmdb_env_size:8589934592", NULL}; 151 152 ldbtest_noconn_setup((void **) &test_ctx); 153 154 155 ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, options); 156 assert_int_equal(ret, 0); 157 158 while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) { 159 ret = ldb_add(test_ctx->ldb, ldif->msg); 160 assert_int_equal(ret, LDB_SUCCESS); 161 } 162 read_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int fd,void * buf,size_t count)163 *state = test_ctx; 164 return 0; 165 } 166 167 static int ldbtest_teardown(void **state) 168 { 169 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, 170 struct ldbtest_ctx); 171 ldbtest_noconn_teardown((void **) &test_ctx); 172 return 0; 173 } 174 175 static void test_db_size_gt_4GB(void **state) 176 { 177 int ret, x; 178 struct ldb_message *msg; 179 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state, 180 struct ldbtest_ctx); 181 const int MB = 1024 * 1024; 182 char *blob = NULL; 183 184 TALLOC_CTX *tmp_ctx; 185 186 tmp_ctx = talloc_new(test_ctx); read_handler(struct tevent_context * ev,struct tevent_fd * fde,uint16_t flags,void * private_data)187 assert_non_null(tmp_ctx); 188 189 190 blob = talloc_zero_size(tmp_ctx, (MB + 1)); 191 assert_non_null(blob); 192 memset(blob, 'x', MB); 193 194 195 /* 196 * Write 6144 1Mb records to the database, this will require more than 197 * 4GiB of disk space 198 */ 199 for (x = 0; x < 6144; x++) { 200 char uuid[24]; 201 msg = ldb_msg_new(tmp_ctx); 202 assert_non_null(msg); 203 204 /* 205 * Generate a unique dn for each record 206 */ 207 msg->dn = ldb_dn_new_fmt(msg, test_ctx->ldb, "dc=test%d", x); 208 assert_non_null(msg->dn); 209 210 /* read_recv(struct tevent_req * req,int * perr)211 * Generate a unique uuid for each added record 212 */ 213 sprintf(uuid, "000000000000%04d", x); 214 ret = ldb_msg_add_string(msg, "objectUUID", uuid); 215 assert_int_equal(ret, 0); 216 217 ldb_transaction_start(test_ctx->ldb); 218 ret = ldb_msg_add_string(msg, "blob", blob); 219 assert_int_equal(ret, 0); 220 221 ret = ldb_add(test_ctx->ldb, msg); 222 assert_int_equal(ret, 0); 223 ldb_transaction_commit(test_ctx->ldb); 224 225 TALLOC_FREE(msg); 226 } 227 talloc_free(tmp_ctx); 228 { 229 struct stat s; 230 ret = stat(test_ctx->dbfile, &s); 231 assert_int_equal(ret, 0); 232 /* 233 * There should have been at least 6GiB written to disk 234 */ 235 assert_true(s.st_size > (6144LL * MB)); 236 } 237 } 238 239 int main(int argc, const char **argv) 240 { write_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int fd,const void * buf,size_t count)241 const struct CMUnitTest tests[] = { 242 cmocka_unit_test_setup_teardown( 243 test_db_size_gt_4GB, 244 ldbtest_setup, 245 ldbtest_teardown), 246 }; 247 248 return cmocka_run_group_tests(tests, NULL, NULL); 249 } 250