lib/util: inline lib/util/util_runcmd.h again
[Samba.git] / lib / ldb / tests / ldb_tdb_test.c
blob8418dbfd671fb38398597a7b37057c407bce57c5
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 <setjmp.h>
44 #include <cmocka.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <talloc.h>
49 #include <tevent.h>
50 #include <ldb.h>
51 #include <ldb_module.h>
52 #include <ldb_private.h>
53 #include <string.h>
54 #include <ctype.h>
56 #include <sys/wait.h>
58 #include "../ldb_tdb/ldb_tdb.h"
59 #include "../ldb_key_value/ldb_kv.h"
61 #define TEST_BE "tdb"
63 struct ldbtest_ctx {
64 struct tevent_context *ev;
65 struct ldb_context *ldb;
67 const char *dbfile;
69 const char *dbpath;
72 static void unlink_old_db(struct ldbtest_ctx *test_ctx)
74 int ret;
76 errno = 0;
77 ret = unlink(test_ctx->dbfile);
78 if (ret == -1 && errno != ENOENT) {
79 fail();
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);
104 *state = test_ctx;
105 return 0;
108 static int ldbtest_noconn_teardown(void **state)
110 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
111 struct ldbtest_ctx);
113 unlink_old_db(test_ctx);
114 talloc_free(test_ctx);
115 return 0;
118 static int ldbtest_setup(void **state)
120 struct ldbtest_ctx *test_ctx;
121 int ret;
122 struct ldb_ldif *ldif;
123 const char *index_ldif = \
124 "dn: @INDEXLIST\n"
125 "@IDXGUID: objectUUID\n"
126 "@IDX_DN_GUID: GUID\n"
127 "\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);
138 *state = test_ctx;
139 return 0;
142 static int ldbtest_teardown(void **state)
144 struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
145 struct ldbtest_ctx);
146 ldbtest_noconn_teardown((void **) &test_ctx);
147 return 0;
151 static TDB_CONTEXT *get_tdb_context(struct ldb_context *ldb)
153 void *data = NULL;
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);
163 tdb = ldb_kv->tdb;
164 assert_non_null(tdb);
166 return 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;
177 int ret;
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;
214 int ret;
215 struct ldbtest_ctx *test_ctx = NULL;
216 int pipes[2];
217 char buf[2];
218 int wstatus;
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);
237 ret = pipe(pipes);
238 assert_int_equal(ret, 0);
240 child_pid = fork();
241 if (child_pid == 0) {
242 struct ldb_context *ldb3 = NULL;
243 TDB_CONTEXT *tdb3 = NULL;
245 close(pipes[0]);
246 ldb3 = ldb_init(test_ctx, test_ctx->ev);
247 ret = ldb_connect(ldb3, test_ctx->dbpath, 0, NULL);
248 if (ret != 0) {
249 print_error(__location__": ldb_connect returned (%d)\n",
250 ret);
251 exit(ret);
253 tdb3 = get_tdb_context(ldb3);
254 if (tdb1 != tdb2) {
255 print_error(__location__": tdb1 != tdb2\n");
256 exit(LDB_ERR_OPERATIONS_ERROR);
258 if (tdb1 != tdb3) {
259 print_error(__location__": tdb1 != tdb3\n");
260 exit(LDB_ERR_OPERATIONS_ERROR);
262 ret = write(pipes[1], "GO", 2);
263 if (ret != 2) {
264 print_error(__location__
265 " write returned (%d)",
266 ret);
267 exit(LDB_ERR_OPERATIONS_ERROR);
269 exit(LDB_SUCCESS);
271 close(pipes[1]);
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;
289 int ret;
290 struct ldbtest_ctx *test_ctx = NULL;
291 int pipes[2];
292 char buf[2];
293 int wstatus;
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
315 * transaction
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);
323 ret = pipe(pipes);
324 assert_int_equal(ret, 0);
326 child_pid = fork();
327 if (child_pid == 0) {
328 struct ldb_context *ldb3 = NULL;
330 close(pipes[0]);
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);
342 if (ret == 0) {
343 print_error(__location__": ldb_connect expected "
344 "LDB_ERR_OPERATIONS_ERROR "
345 "returned (%d)\n",
346 ret);
347 exit(5000);
349 ret = write(pipes[1], "GO", 2);
350 if (ret != 2) {
351 print_error(__location__
352 " write returned (%d)",
353 ret);
354 exit(LDB_ERR_OPERATIONS_ERROR);
356 exit(LDB_SUCCESS);
358 close(pipes[1]);
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(
374 test_multiple_opens,
375 ldbtest_setup,
376 ldbtest_teardown),
377 cmocka_unit_test_setup_teardown(
378 test_multiple_opens_across_fork,
379 ldbtest_setup,
380 ldbtest_teardown),
381 cmocka_unit_test_setup_teardown(
382 test_multiple_opens_across_fork_triggers_reopen,
383 ldbtest_setup,
384 ldbtest_teardown),
387 return cmocka_run_group_tests(tests, NULL, NULL);