2 * lmdb backend specific tests for ldb
4 * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * lmdb backend specific tests for ldb
24 * Setup and tear down code copied from ldb_mod_op_test.c
29 * These headers or their equivalents should be included prior to
37 * This allows test applications to use custom definitions of C standard
38 * library functions and types.
52 #include <ldb_module.h>
53 #include <ldb_private.h>
59 #include "../ldb_tdb/ldb_tdb.h"
60 #include "../ldb_key_value/ldb_kv.h"
65 struct tevent_context
*ev
;
66 struct ldb_context
*ldb
;
73 static void unlink_old_db(struct ldbtest_ctx
*test_ctx
)
78 ret
= unlink(test_ctx
->dbfile
);
79 if (ret
== -1 && errno
!= ENOENT
) {
84 static int ldbtest_noconn_setup(void **state
)
86 struct ldbtest_ctx
*test_ctx
;
88 test_ctx
= talloc_zero(NULL
, struct ldbtest_ctx
);
89 assert_non_null(test_ctx
);
91 test_ctx
->ev
= tevent_context_init(test_ctx
);
92 assert_non_null(test_ctx
->ev
);
94 test_ctx
->ldb
= ldb_init(test_ctx
, test_ctx
->ev
);
95 assert_non_null(test_ctx
->ldb
);
97 test_ctx
->dbfile
= talloc_strdup(test_ctx
, "apitest.ldb");
98 assert_non_null(test_ctx
->dbfile
);
100 test_ctx
->dbpath
= talloc_asprintf(test_ctx
,
101 TEST_BE
"://%s", test_ctx
->dbfile
);
102 assert_non_null(test_ctx
->dbpath
);
104 unlink_old_db(test_ctx
);
109 static int ldbtest_noconn_teardown(void **state
)
111 struct ldbtest_ctx
*test_ctx
= talloc_get_type_abort(*state
,
114 unlink_old_db(test_ctx
);
115 talloc_free(test_ctx
);
119 static int ldbtest_setup(void **state
)
121 struct ldbtest_ctx
*test_ctx
;
123 struct ldb_ldif
*ldif
;
124 const char *index_ldif
= \
126 "@IDXGUID: objectUUID\n"
127 "@IDX_DN_GUID: GUID\n"
130 ldbtest_noconn_setup((void **) &test_ctx
);
132 ret
= ldb_connect(test_ctx
->ldb
, test_ctx
->dbpath
, 0, NULL
);
133 assert_int_equal(ret
, 0);
135 while ((ldif
= ldb_ldif_read_string(test_ctx
->ldb
, &index_ldif
))) {
136 ret
= ldb_add(test_ctx
->ldb
, ldif
->msg
);
137 assert_int_equal(ret
, LDB_SUCCESS
);
143 static int ldbtest_teardown(void **state
)
145 struct ldbtest_ctx
*test_ctx
= talloc_get_type_abort(*state
,
147 ldbtest_noconn_teardown((void **) &test_ctx
);
152 static TDB_CONTEXT
*get_tdb_context(struct ldb_context
*ldb
)
155 struct ldb_kv_private
*ldb_kv
= NULL
;
156 TDB_CONTEXT
*tdb
= NULL
;
158 data
= ldb_module_get_private(ldb
->modules
);
159 assert_non_null(data
);
161 ldb_kv
= talloc_get_type(data
, struct ldb_kv_private
);
162 assert_non_null(ldb_kv
);
165 assert_non_null(tdb
);
170 static void test_multiple_opens(void **state
)
172 struct ldb_context
*ldb1
= NULL
;
173 struct ldb_context
*ldb2
= NULL
;
174 struct ldb_context
*ldb3
= NULL
;
175 TDB_CONTEXT
*tdb1
= NULL
;
176 TDB_CONTEXT
*tdb2
= NULL
;
177 TDB_CONTEXT
*tdb3
= NULL
;
179 struct ldbtest_ctx
*test_ctx
= NULL
;
181 test_ctx
= talloc_get_type_abort(*state
, struct ldbtest_ctx
);
184 * Open the database again
186 ldb1
= ldb_init(test_ctx
, test_ctx
->ev
);
187 ret
= ldb_connect(ldb1
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
188 assert_int_equal(ret
, 0);
190 ldb2
= ldb_init(test_ctx
, test_ctx
->ev
);
191 ret
= ldb_connect(ldb2
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
192 assert_int_equal(ret
, 0);
194 ldb3
= ldb_init(test_ctx
, test_ctx
->ev
);
195 ret
= ldb_connect(ldb3
, test_ctx
->dbpath
, 0, NULL
);
196 assert_int_equal(ret
, 0);
198 * We now have 3 ldb's open pointing to the same on disk database
199 * they should all share the same MDB_env
201 tdb1
= get_tdb_context(ldb1
);
202 tdb2
= get_tdb_context(ldb2
);
203 tdb3
= get_tdb_context(ldb3
);
205 assert_ptr_equal(tdb1
, tdb2
);
206 assert_ptr_equal(tdb1
, tdb3
);
209 static void test_multiple_opens_across_fork(void **state
)
211 struct ldb_context
*ldb1
= NULL
;
212 struct ldb_context
*ldb2
= NULL
;
213 TDB_CONTEXT
*tdb1
= NULL
;
214 TDB_CONTEXT
*tdb2
= NULL
;
216 struct ldbtest_ctx
*test_ctx
= NULL
;
220 pid_t pid
, child_pid
;
222 test_ctx
= talloc_get_type_abort(*state
, struct ldbtest_ctx
);
225 * Open the database again
227 ldb1
= ldb_init(test_ctx
, test_ctx
->ev
);
228 ret
= ldb_connect(ldb1
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
229 assert_int_equal(ret
, 0);
231 ldb2
= ldb_init(test_ctx
, test_ctx
->ev
);
232 ret
= ldb_connect(ldb2
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
233 assert_int_equal(ret
, 0);
235 tdb1
= get_tdb_context(ldb1
);
236 tdb2
= get_tdb_context(ldb2
);
239 assert_int_equal(ret
, 0);
242 if (child_pid
== 0) {
243 struct ldb_context
*ldb3
= NULL
;
244 TDB_CONTEXT
*tdb3
= NULL
;
247 ldb3
= ldb_init(test_ctx
, test_ctx
->ev
);
248 ret
= ldb_connect(ldb3
, test_ctx
->dbpath
, 0, NULL
);
250 print_error(__location__
": ldb_connect returned (%d)\n",
254 tdb3
= get_tdb_context(ldb3
);
256 print_error(__location__
": tdb1 != tdb2\n");
257 exit(LDB_ERR_OPERATIONS_ERROR
);
260 print_error(__location__
": tdb1 != tdb3\n");
261 exit(LDB_ERR_OPERATIONS_ERROR
);
263 ret
= write(pipes
[1], "GO", 2);
265 print_error(__location__
266 " write returned (%d)",
268 exit(LDB_ERR_OPERATIONS_ERROR
);
273 ret
= read(pipes
[0], buf
, 2);
274 assert_int_equal(ret
, 2);
276 pid
= waitpid(child_pid
, &wstatus
, 0);
277 assert_int_equal(pid
, child_pid
);
279 assert_true(WIFEXITED(wstatus
));
281 assert_int_equal(WEXITSTATUS(wstatus
), 0);
284 static void test_multiple_opens_across_fork_triggers_reopen(void **state
)
286 struct ldb_context
*ldb1
= NULL
;
287 struct ldb_context
*ldb2
= NULL
;
288 TDB_CONTEXT
*tdb1
= NULL
;
289 TDB_CONTEXT
*tdb2
= NULL
;
291 struct ldbtest_ctx
*test_ctx
= NULL
;
295 pid_t pid
, child_pid
;
297 test_ctx
= talloc_get_type_abort(*state
, struct ldbtest_ctx
);
300 * Open the database again
302 ldb1
= ldb_init(test_ctx
, test_ctx
->ev
);
303 ret
= ldb_connect(ldb1
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
304 assert_int_equal(ret
, 0);
306 ldb2
= ldb_init(test_ctx
, test_ctx
->ev
);
307 ret
= ldb_connect(ldb2
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
308 assert_int_equal(ret
, 0);
310 tdb1
= get_tdb_context(ldb1
);
311 tdb2
= get_tdb_context(ldb2
);
312 assert_ptr_equal(tdb1
, tdb2
);
315 * Break the internal tdb_reopen() by making a
318 * This shows that the tdb_reopen() is called, which is
319 * essential if the host OS does not have pread()
321 ret
= tdb_transaction_start(tdb1
);
322 assert_int_equal(ret
, 0);
325 assert_int_equal(ret
, 0);
328 if (child_pid
== 0) {
329 struct ldb_context
*ldb3
= NULL
;
332 ldb3
= ldb_init(test_ctx
, test_ctx
->ev
);
335 * This should fail as we have taken out a lock
336 * against the raw TDB above, and tdb_reopen()
337 * will fail in that state.
339 * This check matters as tdb_reopen() is important
340 * if the host does not have pread()
342 ret
= ldb_connect(ldb3
, test_ctx
->dbpath
, 0, NULL
);
344 print_error(__location__
": ldb_connect expected "
345 "LDB_ERR_OPERATIONS_ERROR "
350 ret
= write(pipes
[1], "GO", 2);
352 print_error(__location__
353 " write returned (%d)",
355 exit(LDB_ERR_OPERATIONS_ERROR
);
360 ret
= read(pipes
[0], buf
, 2);
361 assert_int_equal(ret
, 2);
363 pid
= waitpid(child_pid
, &wstatus
, 0);
364 assert_int_equal(pid
, child_pid
);
366 assert_true(WIFEXITED(wstatus
));
368 assert_int_equal(WEXITSTATUS(wstatus
), 0);
371 int main(int argc
, const char **argv
)
373 const struct CMUnitTest tests
[] = {
374 cmocka_unit_test_setup_teardown(
378 cmocka_unit_test_setup_teardown(
379 test_multiple_opens_across_fork
,
382 cmocka_unit_test_setup_teardown(
383 test_multiple_opens_across_fork_triggers_reopen
,
388 return cmocka_run_group_tests(tests
, NULL
, NULL
);