replace: Only link against librt if really needed
[Samba.git] / lib / ldb / tests / ldb_tdb_test.c
blobef91ba54756abd0532b45edb27056fa7a0b7d4f9
1 /*
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
28 * from cmocka.c:
29 * These headers or their equivalents should be included prior to
30 * including
31 * this header file.
33 * #include <stdarg.h>
34 * #include <stddef.h>
35 * #include <setjmp.h>
37 * This allows test applications to use custom definitions of C standard
38 * library functions and types.
41 #include <stdarg.h>
42 #include <stddef.h>
43 #include <stdint.h>
44 #include <setjmp.h>
45 #include <cmocka.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <talloc.h>
50 #include <tevent.h>
51 #include <ldb.h>
52 #include <ldb_module.h>
53 #include <ldb_private.h>
54 #include <string.h>
55 #include <ctype.h>
57 #include <sys/wait.h>
59 #include "../ldb_tdb/ldb_tdb.h"
60 #include "../ldb_key_value/ldb_kv.h"
62 #define TEST_BE "tdb"
64 struct ldbtest_ctx {
65 struct tevent_context *ev;
66 struct ldb_context *ldb;
68 const char *dbfile;
70 const char *dbpath;
73 static void unlink_old_db(struct ldbtest_ctx *test_ctx)
75 int ret;
77 errno = 0;
78 ret = unlink(test_ctx->dbfile);
79 if (ret == -1 && errno != ENOENT) {
80 fail();
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);
105 *state = test_ctx;
106 return 0;
109 static int ldbtest_noconn_teardown(void **state)
111 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
112 struct ldbtest_ctx);
114 unlink_old_db(test_ctx);
115 talloc_free(test_ctx);
116 return 0;
119 static int ldbtest_setup(void **state)
121 struct ldbtest_ctx *test_ctx;
122 int ret;
123 struct ldb_ldif *ldif;
124 const char *index_ldif = \
125 "dn: @INDEXLIST\n"
126 "@IDXGUID: objectUUID\n"
127 "@IDX_DN_GUID: GUID\n"
128 "\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);
139 *state = test_ctx;
140 return 0;
143 static int ldbtest_teardown(void **state)
145 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
146 struct ldbtest_ctx);
147 ldbtest_noconn_teardown((void **) &test_ctx);
148 return 0;
152 static TDB_CONTEXT *get_tdb_context(struct ldb_context *ldb)
154 void *data = NULL;
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);
164 tdb = ldb_kv->tdb;
165 assert_non_null(tdb);
167 return 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;
178 int ret;
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;
215 int ret;
216 struct ldbtest_ctx *test_ctx = NULL;
217 int pipes[2];
218 char buf[2];
219 int wstatus;
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);
238 ret = pipe(pipes);
239 assert_int_equal(ret, 0);
241 child_pid = fork();
242 if (child_pid == 0) {
243 struct ldb_context *ldb3 = NULL;
244 TDB_CONTEXT *tdb3 = NULL;
246 close(pipes[0]);
247 ldb3 = ldb_init(test_ctx, test_ctx->ev);
248 ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
249 if (ret != 0) {
250 print_error(__location__": ldb_connect returned (%d)\n",
251 ret);
252 exit(ret);
254 tdb3 = get_tdb_context(ldb3);
255 if (tdb1 != tdb2) {
256 print_error(__location__": tdb1 != tdb2\n");
257 exit(LDB_ERR_OPERATIONS_ERROR);
259 if (tdb1 != tdb3) {
260 print_error(__location__": tdb1 != tdb3\n");
261 exit(LDB_ERR_OPERATIONS_ERROR);
263 ret = write(pipes[1], "GO", 2);
264 if (ret != 2) {
265 print_error(__location__
266 " write returned (%d)",
267 ret);
268 exit(LDB_ERR_OPERATIONS_ERROR);
270 exit(LDB_SUCCESS);
272 close(pipes[1]);
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;
290 int ret;
291 struct ldbtest_ctx *test_ctx = NULL;
292 int pipes[2];
293 char buf[2];
294 int wstatus;
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
316 * transaction
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);
324 ret = pipe(pipes);
325 assert_int_equal(ret, 0);
327 child_pid = fork();
328 if (child_pid == 0) {
329 struct ldb_context *ldb3 = NULL;
331 close(pipes[0]);
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);
343 if (ret == 0) {
344 print_error(__location__": ldb_connect expected "
345 "LDB_ERR_OPERATIONS_ERROR "
346 "returned (%d)\n",
347 ret);
348 exit(5000);
350 ret = write(pipes[1], "GO", 2);
351 if (ret != 2) {
352 print_error(__location__
353 " write returned (%d)",
354 ret);
355 exit(LDB_ERR_OPERATIONS_ERROR);
357 exit(LDB_SUCCESS);
359 close(pipes[1]);
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(
375 test_multiple_opens,
376 ldbtest_setup,
377 ldbtest_teardown),
378 cmocka_unit_test_setup_teardown(
379 test_multiple_opens_across_fork,
380 ldbtest_setup,
381 ldbtest_teardown),
382 cmocka_unit_test_setup_teardown(
383 test_multiple_opens_across_fork_triggers_reopen,
384 ldbtest_setup,
385 ldbtest_teardown),
388 return cmocka_run_group_tests(tests, NULL, NULL);