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.
51 #include <ldb_module.h>
52 #include <ldb_private.h>
58 #include "../ldb_tdb/ldb_tdb.h"
59 #include "../ldb_key_value/ldb_kv.h"
64 struct tevent_context
*ev
;
65 struct ldb_context
*ldb
;
72 static void unlink_old_db(struct ldbtest_ctx
*test_ctx
)
77 ret
= unlink(test_ctx
->dbfile
);
78 if (ret
== -1 && errno
!= ENOENT
) {
83 static int ldbtest_noconn_setup(void **state
)
85 struct ldbtest_ctx
*test_ctx
;
87 test_ctx
= talloc_zero(NULL
, struct ldbtest_ctx
);
88 assert_non_null(test_ctx
);
90 test_ctx
->ev
= tevent_context_init(test_ctx
);
91 assert_non_null(test_ctx
->ev
);
93 test_ctx
->ldb
= ldb_init(test_ctx
, test_ctx
->ev
);
94 assert_non_null(test_ctx
->ldb
);
96 test_ctx
->dbfile
= talloc_strdup(test_ctx
, "apitest.ldb");
97 assert_non_null(test_ctx
->dbfile
);
99 test_ctx
->dbpath
= talloc_asprintf(test_ctx
,
100 TEST_BE
"://%s", test_ctx
->dbfile
);
101 assert_non_null(test_ctx
->dbpath
);
103 unlink_old_db(test_ctx
);
108 static int ldbtest_noconn_teardown(void **state
)
110 struct ldbtest_ctx
*test_ctx
= talloc_get_type_abort(*state
,
113 unlink_old_db(test_ctx
);
114 talloc_free(test_ctx
);
118 static int ldbtest_setup(void **state
)
120 struct ldbtest_ctx
*test_ctx
;
122 struct ldb_ldif
*ldif
;
123 const char *index_ldif
= \
125 "@IDXGUID: objectUUID\n"
126 "@IDX_DN_GUID: GUID\n"
129 ldbtest_noconn_setup((void **) &test_ctx
);
131 ret
= ldb_connect(test_ctx
->ldb
, test_ctx
->dbpath
, 0, NULL
);
132 assert_int_equal(ret
, 0);
134 while ((ldif
= ldb_ldif_read_string(test_ctx
->ldb
, &index_ldif
))) {
135 ret
= ldb_add(test_ctx
->ldb
, ldif
->msg
);
136 assert_int_equal(ret
, LDB_SUCCESS
);
142 static int ldbtest_teardown(void **state
)
144 struct ldbtest_ctx
*test_ctx
= talloc_get_type_abort(*state
,
146 ldbtest_noconn_teardown((void **) &test_ctx
);
151 static TDB_CONTEXT
*get_tdb_context(struct ldb_context
*ldb
)
154 struct ldb_kv_private
*ldb_kv
= NULL
;
155 TDB_CONTEXT
*tdb
= NULL
;
157 data
= ldb_module_get_private(ldb
->modules
);
158 assert_non_null(data
);
160 ldb_kv
= talloc_get_type(data
, struct ldb_kv_private
);
161 assert_non_null(ldb_kv
);
164 assert_non_null(tdb
);
169 static void test_multiple_opens(void **state
)
171 struct ldb_context
*ldb1
= NULL
;
172 struct ldb_context
*ldb2
= NULL
;
173 struct ldb_context
*ldb3
= NULL
;
174 TDB_CONTEXT
*tdb1
= NULL
;
175 TDB_CONTEXT
*tdb2
= NULL
;
176 TDB_CONTEXT
*tdb3
= NULL
;
178 struct ldbtest_ctx
*test_ctx
= NULL
;
180 test_ctx
= talloc_get_type_abort(*state
, struct ldbtest_ctx
);
183 * Open the database again
185 ldb1
= ldb_init(test_ctx
, test_ctx
->ev
);
186 ret
= ldb_connect(ldb1
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
187 assert_int_equal(ret
, 0);
189 ldb2
= ldb_init(test_ctx
, test_ctx
->ev
);
190 ret
= ldb_connect(ldb2
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
191 assert_int_equal(ret
, 0);
193 ldb3
= ldb_init(test_ctx
, test_ctx
->ev
);
194 ret
= ldb_connect(ldb3
, test_ctx
->dbpath
, 0, NULL
);
195 assert_int_equal(ret
, 0);
197 * We now have 3 ldb's open pointing to the same on disk database
198 * they should all share the same MDB_env
200 tdb1
= get_tdb_context(ldb1
);
201 tdb2
= get_tdb_context(ldb2
);
202 tdb3
= get_tdb_context(ldb3
);
204 assert_ptr_equal(tdb1
, tdb2
);
205 assert_ptr_equal(tdb1
, tdb3
);
208 static void test_multiple_opens_across_fork(void **state
)
210 struct ldb_context
*ldb1
= NULL
;
211 struct ldb_context
*ldb2
= NULL
;
212 TDB_CONTEXT
*tdb1
= NULL
;
213 TDB_CONTEXT
*tdb2
= NULL
;
215 struct ldbtest_ctx
*test_ctx
= NULL
;
219 pid_t pid
, child_pid
;
221 test_ctx
= talloc_get_type_abort(*state
, struct ldbtest_ctx
);
224 * Open the database again
226 ldb1
= ldb_init(test_ctx
, test_ctx
->ev
);
227 ret
= ldb_connect(ldb1
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
228 assert_int_equal(ret
, 0);
230 ldb2
= ldb_init(test_ctx
, test_ctx
->ev
);
231 ret
= ldb_connect(ldb2
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
232 assert_int_equal(ret
, 0);
234 tdb1
= get_tdb_context(ldb1
);
235 tdb2
= get_tdb_context(ldb2
);
238 assert_int_equal(ret
, 0);
241 if (child_pid
== 0) {
242 struct ldb_context
*ldb3
= NULL
;
243 TDB_CONTEXT
*tdb3
= NULL
;
246 ldb3
= ldb_init(test_ctx
, test_ctx
->ev
);
247 ret
= ldb_connect(ldb3
, test_ctx
->dbpath
, 0, NULL
);
249 print_error(__location__
": ldb_connect returned (%d)\n",
253 tdb3
= get_tdb_context(ldb3
);
255 print_error(__location__
": tdb1 != tdb2\n");
256 exit(LDB_ERR_OPERATIONS_ERROR
);
259 print_error(__location__
": tdb1 != tdb3\n");
260 exit(LDB_ERR_OPERATIONS_ERROR
);
262 ret
= write(pipes
[1], "GO", 2);
264 print_error(__location__
265 " write returned (%d)",
267 exit(LDB_ERR_OPERATIONS_ERROR
);
272 ret
= read(pipes
[0], buf
, 2);
273 assert_int_equal(ret
, 2);
275 pid
= waitpid(child_pid
, &wstatus
, 0);
276 assert_int_equal(pid
, child_pid
);
278 assert_true(WIFEXITED(wstatus
));
280 assert_int_equal(WEXITSTATUS(wstatus
), 0);
283 static void test_multiple_opens_across_fork_triggers_reopen(void **state
)
285 struct ldb_context
*ldb1
= NULL
;
286 struct ldb_context
*ldb2
= NULL
;
287 TDB_CONTEXT
*tdb1
= NULL
;
288 TDB_CONTEXT
*tdb2
= NULL
;
290 struct ldbtest_ctx
*test_ctx
= NULL
;
294 pid_t pid
, child_pid
;
296 test_ctx
= talloc_get_type_abort(*state
, struct ldbtest_ctx
);
299 * Open the database again
301 ldb1
= ldb_init(test_ctx
, test_ctx
->ev
);
302 ret
= ldb_connect(ldb1
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
303 assert_int_equal(ret
, 0);
305 ldb2
= ldb_init(test_ctx
, test_ctx
->ev
);
306 ret
= ldb_connect(ldb2
, test_ctx
->dbpath
, LDB_FLG_RDONLY
, NULL
);
307 assert_int_equal(ret
, 0);
309 tdb1
= get_tdb_context(ldb1
);
310 tdb2
= get_tdb_context(ldb2
);
311 assert_ptr_equal(tdb1
, tdb2
);
314 * Break the internal tdb_reopen() by making a
317 * This shows that the tdb_reopen() is called, which is
318 * essential if the host OS does not have pread()
320 ret
= tdb_transaction_start(tdb1
);
321 assert_int_equal(ret
, 0);
324 assert_int_equal(ret
, 0);
327 if (child_pid
== 0) {
328 struct ldb_context
*ldb3
= NULL
;
331 ldb3
= ldb_init(test_ctx
, test_ctx
->ev
);
334 * This should fail as we have taken out a lock
335 * against the raw TDB above, and tdb_reopen()
336 * will fail in that state.
338 * This check matters as tdb_reopen() is important
339 * if the host does not have pread()
341 ret
= ldb_connect(ldb3
, test_ctx
->dbpath
, 0, NULL
);
343 print_error(__location__
": ldb_connect expected "
344 "LDB_ERR_OPERATIONS_ERROR "
349 ret
= write(pipes
[1], "GO", 2);
351 print_error(__location__
352 " write returned (%d)",
354 exit(LDB_ERR_OPERATIONS_ERROR
);
359 ret
= read(pipes
[0], buf
, 2);
360 assert_int_equal(ret
, 2);
362 pid
= waitpid(child_pid
, &wstatus
, 0);
363 assert_int_equal(pid
, child_pid
);
365 assert_true(WIFEXITED(wstatus
));
367 assert_int_equal(WEXITSTATUS(wstatus
), 0);
370 int main(int argc
, const char **argv
)
372 const struct CMUnitTest tests
[] = {
373 cmocka_unit_test_setup_teardown(
377 cmocka_unit_test_setup_teardown(
378 test_multiple_opens_across_fork
,
381 cmocka_unit_test_setup_teardown(
382 test_multiple_opens_across_fork_triggers_reopen
,
387 return cmocka_run_group_tests(tests
, NULL
, NULL
);