Line data Source code
1 : /*
2 : * Tests exercising the ldb key value operations.
3 : *
4 : * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2018
5 : *
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.
10 : *
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.
15 : *
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/>.
18 : *
19 : */
20 :
21 : /*
22 : * from cmocka.c:
23 : * These headers or their equivalents should be included prior to
24 : * including
25 : * this header file.
26 : *
27 : * #include <stdarg.h>
28 : * #include <stddef.h>
29 : * #include <setjmp.h>
30 : *
31 : * This allows test applications to use custom definitions of C standard
32 : * library functions and types.
33 : *
34 : */
35 :
36 : /*
37 : * A KV module is expected to have the following behaviour
38 : *
39 : * - A transaction must be open to perform any read, write or delete operation
40 : * - Writes and Deletes should not be visible until a transaction is committed
41 : * - Nested transactions are not permitted
42 : * - transactions can be rolled back and committed.
43 : * - supports iteration over all records in the database
44 : * - supports the update_in_iterate operation allowing entries to be
45 : * re-keyed.
46 : * - has a get_size implementation that returns an estimate of the number of
47 : * records in the database. Note that this can be an estimate rather than
48 : * an accurate size.
49 : */
50 : #include <stdarg.h>
51 : #include <stddef.h>
52 : #include <stdint.h>
53 : #include <setjmp.h>
54 : #include <cmocka.h>
55 :
56 : #include <errno.h>
57 : #include <unistd.h>
58 : #include <talloc.h>
59 : #include <tevent.h>
60 : #include <ldb.h>
61 : #include <ldb_module.h>
62 : #include <ldb_private.h>
63 : #include <string.h>
64 : #include <ctype.h>
65 :
66 : #include <sys/wait.h>
67 :
68 : #include "ldb_tdb/ldb_tdb.h"
69 : #include "ldb_key_value/ldb_kv.h"
70 :
71 :
72 : #define DEFAULT_BE "tdb"
73 :
74 : #ifndef TEST_BE
75 : #define TEST_BE DEFAULT_BE
76 : #endif /* TEST_BE */
77 :
78 : #define NUM_RECS 1024
79 :
80 :
81 : struct test_ctx {
82 : struct tevent_context *ev;
83 : struct ldb_context *ldb;
84 :
85 : const char *dbfile;
86 : const char *lockfile; /* lockfile is separate */
87 :
88 : const char *dbpath;
89 : };
90 :
91 26 : static void unlink_old_db(struct test_ctx *test_ctx)
92 : {
93 : int ret;
94 :
95 26 : errno = 0;
96 26 : ret = unlink(test_ctx->lockfile);
97 26 : if (ret == -1 && errno != ENOENT) {
98 0 : fail();
99 : }
100 :
101 26 : errno = 0;
102 26 : ret = unlink(test_ctx->dbfile);
103 26 : if (ret == -1 && errno != ENOENT) {
104 0 : fail();
105 : }
106 26 : }
107 :
108 13 : static int noconn_setup(void **state)
109 : {
110 : struct test_ctx *test_ctx;
111 :
112 13 : test_ctx = talloc_zero(NULL, struct test_ctx);
113 13 : assert_non_null(test_ctx);
114 :
115 13 : test_ctx->ev = tevent_context_init(test_ctx);
116 13 : assert_non_null(test_ctx->ev);
117 :
118 13 : test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
119 13 : assert_non_null(test_ctx->ldb);
120 :
121 13 : test_ctx->dbfile = talloc_strdup(test_ctx, "kvopstest.ldb");
122 13 : assert_non_null(test_ctx->dbfile);
123 :
124 13 : test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
125 : test_ctx->dbfile);
126 13 : assert_non_null(test_ctx->lockfile);
127 :
128 13 : test_ctx->dbpath = talloc_asprintf(test_ctx,
129 : TEST_BE"://%s", test_ctx->dbfile);
130 13 : assert_non_null(test_ctx->dbpath);
131 :
132 13 : unlink_old_db(test_ctx);
133 13 : *state = test_ctx;
134 13 : return 0;
135 : }
136 :
137 13 : static int noconn_teardown(void **state)
138 : {
139 13 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
140 : struct test_ctx);
141 :
142 13 : unlink_old_db(test_ctx);
143 13 : talloc_free(test_ctx);
144 13 : return 0;
145 : }
146 :
147 13 : static int setup(void **state)
148 : {
149 : struct test_ctx *test_ctx;
150 : int ret;
151 : struct ldb_ldif *ldif;
152 13 : const char *index_ldif = \
153 : "dn: @INDEXLIST\n"
154 : "@IDXGUID: objectUUID\n"
155 : "@IDX_DN_GUID: GUID\n"
156 : "\n";
157 :
158 13 : noconn_setup((void **) &test_ctx);
159 :
160 13 : ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
161 13 : assert_int_equal(ret, 0);
162 :
163 26 : while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
164 13 : ret = ldb_add(test_ctx->ldb, ldif->msg);
165 13 : assert_int_equal(ret, LDB_SUCCESS);
166 : }
167 13 : *state = test_ctx;
168 13 : return 0;
169 : }
170 :
171 13 : static int teardown(void **state)
172 : {
173 13 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
174 : struct test_ctx);
175 13 : noconn_teardown((void **) &test_ctx);
176 13 : return 0;
177 : }
178 :
179 20 : static struct ldb_kv_private *get_ldb_kv(struct ldb_context *ldb)
180 : {
181 20 : void *data = NULL;
182 20 : struct ldb_kv_private *ldb_kv = NULL;
183 :
184 20 : data = ldb_module_get_private(ldb->modules);
185 20 : assert_non_null(data);
186 :
187 20 : ldb_kv = talloc_get_type(data, struct ldb_kv_private);
188 20 : assert_non_null(ldb_kv);
189 :
190 20 : return ldb_kv;
191 : }
192 :
193 13 : static int parse(struct ldb_val key,
194 : struct ldb_val data,
195 : void *private_data)
196 : {
197 13 : struct ldb_val* read = private_data;
198 :
199 : /* Yes, we leak this. That is OK */
200 13 : read->data = talloc_size(NULL,
201 : data.length);
202 13 : assert_non_null(read->data);
203 :
204 13 : memcpy(read->data, data.data, data.length);
205 13 : read->length = data.length;
206 13 : return LDB_SUCCESS;
207 : }
208 :
209 : /*
210 : * Parse function that just returns the int we pass it.
211 : */
212 50 : static int parse_return(struct ldb_val key,
213 : struct ldb_val data,
214 : void *private_data)
215 : {
216 50 : int *rcode = private_data;
217 50 : return *rcode;
218 : }
219 :
220 : /*
221 : * Test that data can be written to the kv store and be read back.
222 : */
223 1 : static void test_add_get(void **state)
224 : {
225 : int ret;
226 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
227 : struct test_ctx);
228 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
229 1 : uint8_t key_val[] = "TheKey";
230 1 : struct ldb_val key = {
231 : .data = key_val,
232 : .length = sizeof(key_val)
233 : };
234 :
235 1 : uint8_t value[] = "The record contents";
236 1 : struct ldb_val data = {
237 : .data = value,
238 : .length = sizeof(value)
239 : };
240 :
241 : struct ldb_val read;
242 : int rcode;
243 :
244 1 : int flags = 0;
245 : TALLOC_CTX *tmp_ctx;
246 :
247 1 : tmp_ctx = talloc_new(test_ctx);
248 1 : assert_non_null(tmp_ctx);
249 :
250 : /*
251 : * Begin a transaction
252 : */
253 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
254 1 : assert_int_equal(ret, 0);
255 :
256 : /*
257 : * Write the record
258 : */
259 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
260 1 : assert_int_equal(ret, 0);
261 :
262 : /*
263 : * Commit the transaction
264 : */
265 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
266 1 : assert_int_equal(ret, 0);
267 :
268 : /*
269 : * And now read it back
270 : */
271 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
272 1 : assert_int_equal(ret, 0);
273 :
274 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
275 1 : assert_int_equal(ret, 0);
276 :
277 1 : assert_int_equal(sizeof(value), read.length);
278 1 : assert_memory_equal(value, read.data, sizeof(value));
279 :
280 : /*
281 : * Now check that the error code we return in the
282 : * parse function is returned by fetch_and_parse.
283 : */
284 51 : for (rcode=0; rcode<50; rcode++) {
285 50 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key,
286 : parse_return,
287 : &rcode);
288 50 : assert_int_equal(ret, rcode);
289 : }
290 :
291 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
292 1 : assert_int_equal(ret, 0);
293 1 : talloc_free(tmp_ctx);
294 1 : }
295 :
296 : /*
297 : * Test that attempts to read data without a read transaction fail.
298 : */
299 1 : static void test_read_outside_transaction(void **state)
300 : {
301 : int ret;
302 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
303 : struct test_ctx);
304 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
305 1 : uint8_t key_val[] = "TheKey";
306 1 : struct ldb_val key = {
307 : .data = key_val,
308 : .length = sizeof(key_val)
309 : };
310 :
311 1 : uint8_t value[] = "The record contents";
312 1 : struct ldb_val data = {
313 : .data = value,
314 : .length = sizeof(value)
315 : };
316 :
317 : struct ldb_val read;
318 :
319 1 : int flags = 0;
320 : TALLOC_CTX *tmp_ctx;
321 :
322 1 : tmp_ctx = talloc_new(test_ctx);
323 1 : assert_non_null(tmp_ctx);
324 :
325 : /*
326 : * Begin a transaction
327 : */
328 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
329 1 : assert_int_equal(ret, 0);
330 :
331 : /*
332 : * Write the record
333 : */
334 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
335 1 : assert_int_equal(ret, 0);
336 :
337 : /*
338 : * Commit the transaction
339 : */
340 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
341 1 : assert_int_equal(ret, 0);
342 :
343 : /*
344 : * And now read it back
345 : * Note there is no read transaction active
346 : */
347 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
348 1 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
349 :
350 1 : talloc_free(tmp_ctx);
351 1 : }
352 :
353 : /*
354 : * Test that data can be deleted from the kv store
355 : */
356 1 : static void test_delete(void **state)
357 : {
358 : int ret;
359 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
360 : struct test_ctx);
361 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
362 1 : uint8_t key_val[] = "TheKey";
363 1 : struct ldb_val key = {
364 : .data = key_val,
365 : .length = sizeof(key_val)
366 : };
367 :
368 1 : uint8_t value[] = "The record contents";
369 1 : struct ldb_val data = {
370 : .data = value,
371 : .length = sizeof(value)
372 : };
373 :
374 : struct ldb_val read;
375 :
376 1 : int flags = 0;
377 : TALLOC_CTX *tmp_ctx;
378 :
379 1 : tmp_ctx = talloc_new(test_ctx);
380 1 : assert_non_null(tmp_ctx);
381 :
382 : /*
383 : * Begin a transaction
384 : */
385 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
386 1 : assert_int_equal(ret, 0);
387 :
388 : /*
389 : * Write the record
390 : */
391 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
392 1 : assert_int_equal(ret, 0);
393 :
394 : /*
395 : * Commit the transaction
396 : */
397 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
398 1 : assert_int_equal(ret, 0);
399 :
400 : /*
401 : * And now read it back
402 : */
403 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
404 1 : assert_int_equal(ret, 0);
405 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
406 1 : assert_int_equal(ret, 0);
407 1 : assert_int_equal(sizeof(value), read.length);
408 1 : assert_memory_equal(value, read.data, sizeof(value));
409 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
410 1 : assert_int_equal(ret, 0);
411 :
412 : /*
413 : * Begin a transaction
414 : */
415 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
416 1 : assert_int_equal(ret, 0);
417 :
418 : /*
419 : * Now delete it.
420 : */
421 1 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
422 1 : assert_int_equal(ret, 0);
423 :
424 : /*
425 : * Commit the transaction
426 : */
427 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
428 1 : assert_int_equal(ret, 0);
429 :
430 : /*
431 : * And now try to read it back
432 : */
433 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
434 1 : assert_int_equal(ret, 0);
435 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
436 1 : assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
437 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
438 1 : assert_int_equal(ret, 0);
439 :
440 1 : talloc_free(tmp_ctx);
441 1 : }
442 :
443 : /*
444 : * Check that writes are correctly rolled back when a transaction
445 : * is rolled back.
446 : */
447 1 : static void test_transaction_abort_write(void **state)
448 : {
449 : int ret;
450 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
451 : struct test_ctx);
452 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
453 1 : uint8_t key_val[] = "TheKey";
454 1 : struct ldb_val key = {
455 : .data = key_val,
456 : .length = sizeof(key_val)
457 : };
458 :
459 1 : uint8_t value[] = "The record contents";
460 1 : struct ldb_val data = {
461 : .data = value,
462 : .length = sizeof(value)
463 : };
464 :
465 : struct ldb_val read;
466 :
467 1 : int flags = 0;
468 : TALLOC_CTX *tmp_ctx;
469 :
470 1 : tmp_ctx = talloc_new(test_ctx);
471 1 : assert_non_null(tmp_ctx);
472 :
473 : /*
474 : * Begin a transaction
475 : */
476 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
477 1 : assert_int_equal(ret, 0);
478 :
479 : /*
480 : * Write the record
481 : */
482 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
483 1 : assert_int_equal(ret, 0);
484 :
485 : /*
486 : * And now read it back
487 : */
488 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
489 1 : assert_int_equal(ret, 0);
490 1 : assert_int_equal(sizeof(value), read.length);
491 1 : assert_memory_equal(value, read.data, sizeof(value));
492 :
493 :
494 : /*
495 : * Now abort the transaction
496 : */
497 1 : ret = ldb_kv->kv_ops->abort_write(ldb_kv);
498 1 : assert_int_equal(ret, 0);
499 :
500 : /*
501 : * And now read it back, should not be there
502 : */
503 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
504 1 : assert_int_equal(ret, 0);
505 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
506 1 : assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
507 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
508 1 : assert_int_equal(ret, 0);
509 :
510 1 : talloc_free(tmp_ctx);
511 1 : }
512 :
513 : /*
514 : * Check that deletes are correctly rolled back when a transaction is
515 : * aborted.
516 : */
517 1 : static void test_transaction_abort_delete(void **state)
518 : {
519 : int ret;
520 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
521 : struct test_ctx);
522 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
523 1 : uint8_t key_val[] = "TheKey";
524 1 : struct ldb_val key = {
525 : .data = key_val,
526 : .length = sizeof(key_val)
527 : };
528 :
529 1 : uint8_t value[] = "The record contents";
530 1 : struct ldb_val data = {
531 : .data = value,
532 : .length = sizeof(value)
533 : };
534 :
535 : struct ldb_val read;
536 :
537 1 : int flags = 0;
538 : TALLOC_CTX *tmp_ctx;
539 :
540 1 : tmp_ctx = talloc_new(test_ctx);
541 1 : assert_non_null(tmp_ctx);
542 :
543 : /*
544 : * Begin a transaction
545 : */
546 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
547 1 : assert_int_equal(ret, 0);
548 :
549 : /*
550 : * Write the record
551 : */
552 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
553 1 : assert_int_equal(ret, 0);
554 :
555 : /*
556 : * Commit the transaction
557 : */
558 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
559 1 : assert_int_equal(ret, 0);
560 :
561 : /*
562 : * And now read it back
563 : */
564 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
565 1 : assert_int_equal(ret, 0);
566 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
567 1 : assert_int_equal(ret, 0);
568 1 : assert_int_equal(sizeof(value), read.length);
569 1 : assert_memory_equal(value, read.data, sizeof(value));
570 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
571 1 : assert_int_equal(ret, 0);
572 :
573 : /*
574 : * Begin a transaction
575 : */
576 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
577 1 : assert_int_equal(ret, 0);
578 :
579 : /*
580 : * Now delete it.
581 : */
582 1 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
583 1 : assert_int_equal(ret, 0);
584 :
585 : /*
586 : * And now read it back
587 : */
588 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
589 1 : assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
590 :
591 : /*
592 : * Abort the transaction
593 : */
594 1 : ret = ldb_kv->kv_ops->abort_write(ldb_kv);
595 1 : assert_int_equal(ret, 0);
596 :
597 : /*
598 : * And now try to read it back
599 : */
600 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
601 1 : assert_int_equal(ret, 0);
602 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
603 1 : assert_int_equal(ret, 0);
604 1 : assert_int_equal(sizeof(value), read.length);
605 1 : assert_memory_equal(value, read.data, sizeof(value));
606 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
607 1 : assert_int_equal(ret, 0);
608 :
609 1 : talloc_free(tmp_ctx);
610 1 : }
611 :
612 : /*
613 : * Test that writes outside a transaction fail
614 : */
615 1 : static void test_write_outside_transaction(void **state)
616 : {
617 : int ret;
618 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
619 : struct test_ctx);
620 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
621 1 : uint8_t key_val[] = "TheKey";
622 1 : struct ldb_val key = {
623 : .data = key_val,
624 : .length = sizeof(key_val)
625 : };
626 :
627 1 : uint8_t value[] = "The record contents";
628 1 : struct ldb_val data = {
629 : .data = value,
630 : .length = sizeof(value)
631 : };
632 :
633 :
634 1 : int flags = 0;
635 : TALLOC_CTX *tmp_ctx;
636 :
637 1 : tmp_ctx = talloc_new(test_ctx);
638 1 : assert_non_null(tmp_ctx);
639 :
640 : /*
641 : * Attempt to write the record
642 : */
643 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
644 1 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
645 :
646 1 : talloc_free(tmp_ctx);
647 1 : }
648 :
649 : /*
650 : * Test data can not be deleted outside a transaction
651 : */
652 1 : static void test_delete_outside_transaction(void **state)
653 : {
654 : int ret;
655 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
656 : struct test_ctx);
657 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
658 1 : uint8_t key_val[] = "TheKey";
659 1 : struct ldb_val key = {
660 : .data = key_val,
661 : .length = sizeof(key_val)
662 : };
663 :
664 1 : uint8_t value[] = "The record contents";
665 1 : struct ldb_val data = {
666 : .data = value,
667 : .length = sizeof(value)
668 : };
669 :
670 : struct ldb_val read;
671 :
672 1 : int flags = 0;
673 : TALLOC_CTX *tmp_ctx;
674 :
675 1 : tmp_ctx = talloc_new(test_ctx);
676 1 : assert_non_null(tmp_ctx);
677 :
678 : /*
679 : * Begin a transaction
680 : */
681 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
682 1 : assert_int_equal(ret, 0);
683 :
684 : /*
685 : * Write the record
686 : */
687 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
688 1 : assert_int_equal(ret, 0);
689 :
690 : /*
691 : * Commit the transaction
692 : */
693 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
694 1 : assert_int_equal(ret, 0);
695 :
696 : /*
697 : * And now read it back
698 : */
699 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
700 1 : assert_int_equal(ret, 0);
701 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
702 1 : assert_int_equal(ret, 0);
703 1 : assert_int_equal(sizeof(value), read.length);
704 1 : assert_memory_equal(value, read.data, sizeof(value));
705 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
706 1 : assert_int_equal(ret, 0);
707 :
708 : /*
709 : * Now attempt to delete a record
710 : */
711 1 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
712 1 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
713 :
714 : /*
715 : * And now read it back
716 : */
717 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
718 1 : assert_int_equal(ret, 0);
719 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
720 1 : assert_int_equal(ret, 0);
721 1 : assert_int_equal(sizeof(value), read.length);
722 1 : assert_memory_equal(value, read.data, sizeof(value));
723 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
724 1 : assert_int_equal(ret, 0);
725 :
726 1 : talloc_free(tmp_ctx);
727 1 : }
728 :
729 1026 : static int traverse_fn(struct ldb_kv_private *ldb_kv,
730 : struct ldb_val key,
731 : struct ldb_val data,
732 : void *ctx)
733 : {
734 :
735 1026 : int *visits = ctx;
736 : int i;
737 :
738 1026 : if (strncmp("key ", (char *) key.data, 4) == 0) {
739 1024 : i = strtol((char *) &key.data[4], NULL, 10);
740 1024 : visits[i]++;
741 : }
742 1026 : return LDB_SUCCESS;
743 : }
744 :
745 : /*
746 : * Test that iterate visits all the records.
747 : */
748 1 : static void test_iterate(void **state)
749 1 : {
750 : int ret;
751 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
752 : struct test_ctx);
753 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
754 : int i;
755 1 : int num_recs = 1024;
756 1 : int visits[num_recs];
757 :
758 : TALLOC_CTX *tmp_ctx;
759 :
760 1 : tmp_ctx = talloc_new(test_ctx);
761 1 : assert_non_null(tmp_ctx);
762 :
763 : /*
764 : * Begin a transaction
765 : */
766 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
767 1 : assert_int_equal(ret, 0);
768 :
769 : /*
770 : * Write the records
771 : */
772 1025 : for (i = 0; i < num_recs; i++) {
773 : struct ldb_val key;
774 : struct ldb_val rec;
775 1024 : int flags = 0;
776 :
777 1024 : visits[i] = 0;
778 1024 : key.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
779 1024 : key.length = strlen((char *)key.data) + 1;
780 :
781 1024 : rec.data = (uint8_t *) talloc_asprintf(tmp_ctx,
782 : "data for record (%04d)",
783 : i);
784 1024 : rec.length = strlen((char *)rec.data) + 1;
785 :
786 1024 : ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
787 1024 : assert_int_equal(ret, 0);
788 :
789 1024 : TALLOC_FREE(key.data);
790 1024 : TALLOC_FREE(rec.data);
791 : }
792 :
793 : /*
794 : * Commit the transaction
795 : */
796 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
797 1 : assert_int_equal(ret, 0);
798 :
799 : /*
800 : * Now iterate over the kv store and ensure that all the
801 : * records are visited.
802 : */
803 1 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
804 1 : assert_int_equal(ret, 0);
805 1 : ret = ldb_kv->kv_ops->iterate(ldb_kv, traverse_fn, visits);
806 1025 : for (i = 0; i <num_recs; i++) {
807 1024 : assert_int_equal(1, visits[i]);
808 : }
809 1 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
810 1 : assert_int_equal(ret, 0);
811 :
812 1 : TALLOC_FREE(tmp_ctx);
813 1 : }
814 :
815 6 : static void do_iterate_range_test(void **state, int range_start,
816 : int range_end, bool fail)
817 6 : {
818 : int ret;
819 6 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
820 : struct test_ctx);
821 6 : struct ldb_kv_private *ldb_kv = NULL;
822 : int i;
823 6 : int num_recs = 1024;
824 6 : int skip_recs = 10;
825 6 : int visits[num_recs];
826 : struct ldb_val sk, ek;
827 :
828 : TALLOC_CTX *tmp_ctx;
829 :
830 6 : ldb_kv = get_ldb_kv(test_ctx->ldb);
831 6 : assert_non_null(ldb_kv);
832 :
833 6150 : for (i = 0; i < num_recs; i++){
834 6144 : visits[i] = 0;
835 : }
836 :
837 : /*
838 : * No iterate_range on tdb
839 : */
840 : if (strcmp(TEST_BE, "tdb") == 0) {
841 6 : return;
842 : }
843 :
844 : tmp_ctx = talloc_new(test_ctx);
845 : assert_non_null(tmp_ctx);
846 :
847 : /*
848 : * Begin a transaction
849 : */
850 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
851 : assert_int_equal(ret, 0);
852 :
853 : /*
854 : * Write the records
855 : */
856 : for (i = skip_recs; i <= num_recs - skip_recs; i++) {
857 : struct ldb_val key;
858 : struct ldb_val rec;
859 : int flags = 0;
860 :
861 : key.data = (uint8_t *)talloc_asprintf(tmp_ctx,
862 : "key %04d",
863 : i);
864 : key.length = strlen((char *)key.data);
865 :
866 : rec.data = (uint8_t *)talloc_asprintf(tmp_ctx,
867 : "data for record (%04d)",
868 : i);
869 : rec.length = strlen((char *)rec.data) + 1;
870 :
871 : ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
872 : assert_int_equal(ret, 0);
873 :
874 : TALLOC_FREE(key.data);
875 : TALLOC_FREE(rec.data);
876 : }
877 :
878 : /*
879 : * Commit the transaction
880 : */
881 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
882 : assert_int_equal(ret, 0);
883 :
884 : sk.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", range_start);
885 : sk.length = strlen((char *)sk.data);
886 :
887 : ek.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", range_end);
888 : ek.length = strlen((char *)ek.data) + 1;
889 :
890 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
891 : assert_int_equal(ret, 0);
892 : ret = ldb_kv->kv_ops->iterate_range(ldb_kv, sk, ek,
893 : traverse_fn, visits);
894 : if (fail){
895 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
896 : TALLOC_FREE(tmp_ctx);
897 : return;
898 : } else{
899 : assert_int_equal(ret, 0);
900 : }
901 : for (i = 0; i < num_recs; i++) {
902 : if (i >= skip_recs && i <= num_recs - skip_recs &&
903 : i >= range_start && i <= range_end){
904 : assert_int_equal(1, visits[i]);
905 : } else {
906 : assert_int_equal(0, visits[i]);
907 : }
908 : }
909 :
910 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
911 : assert_int_equal(ret, 0);
912 :
913 : TALLOC_FREE(tmp_ctx);
914 : }
915 :
916 : /*
917 : * Test that iterate_range visits all the records between two keys.
918 : */
919 1 : static void test_iterate_range(void **state)
920 : {
921 1 : do_iterate_range_test(state, 300, 900, false);
922 :
923 : /*
924 : * test start_key = end_key
925 : */
926 1 : do_iterate_range_test(state, 20, 20, false);
927 :
928 : /*
929 : * test reverse range fails
930 : */
931 1 : do_iterate_range_test(state, 50, 40, true);
932 :
933 : /*
934 : * keys are between 10-1014 so test with keys outside that range
935 : */
936 1 : do_iterate_range_test(state, 0, 20, false);
937 1 : do_iterate_range_test(state, 1010, 1030, false);
938 1 : do_iterate_range_test(state, 0, 1030, false);
939 1 : }
940 :
941 : struct update_context {
942 : struct ldb_context* ldb;
943 : int visits[NUM_RECS];
944 : };
945 :
946 1829 : static int update_fn(struct ldb_kv_private *ldb_kv,
947 : struct ldb_val key,
948 : struct ldb_val data,
949 : void *ctx)
950 : {
951 :
952 : struct ldb_val new_key;
953 1829 : struct ldb_module *module = NULL;
954 1829 : struct update_context *context =NULL;
955 1829 : int ret = LDB_SUCCESS;
956 : TALLOC_CTX *tmp_ctx;
957 :
958 1829 : tmp_ctx = talloc_new(ldb_kv);
959 1829 : assert_non_null(tmp_ctx);
960 :
961 1829 : context = talloc_get_type_abort(ctx, struct update_context);
962 :
963 1829 : module = talloc_zero(tmp_ctx, struct ldb_module);
964 1829 : module->ldb = context->ldb;
965 :
966 1829 : if (strncmp("key ", (char *) key.data, 4) == 0) {
967 1024 : int i = strtol((char *) &key.data[4], NULL, 10);
968 1024 : context->visits[i]++;
969 1024 : new_key.data = talloc_memdup(tmp_ctx, key.data, key.length);
970 1024 : new_key.length = key.length;
971 1024 : new_key.data[0] = 'K';
972 :
973 1024 : ret = ldb_kv->kv_ops->update_in_iterate(
974 : ldb_kv, key, new_key, data, &module);
975 : }
976 1829 : TALLOC_FREE(tmp_ctx);
977 1829 : return ret;
978 : }
979 :
980 : /*
981 : * Test that update_in_iterate behaves as expected.
982 : */
983 1 : static void test_update_in_iterate(void **state)
984 : {
985 : int ret;
986 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
987 : struct test_ctx);
988 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
989 : int i;
990 1 : struct update_context *context = NULL;
991 :
992 :
993 : TALLOC_CTX *tmp_ctx;
994 :
995 1 : tmp_ctx = talloc_new(test_ctx);
996 1 : assert_non_null(tmp_ctx);
997 :
998 1 : context = talloc_zero(tmp_ctx, struct update_context);
999 1 : assert_non_null(context);
1000 1 : context->ldb = test_ctx->ldb;
1001 : /*
1002 : * Begin a transaction
1003 : */
1004 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1005 1 : assert_int_equal(ret, 0);
1006 :
1007 : /*
1008 : * Write the records
1009 : */
1010 1025 : for (i = 0; i < NUM_RECS; i++) {
1011 : struct ldb_val key;
1012 : struct ldb_val rec;
1013 1024 : int flags = 0;
1014 :
1015 1024 : key.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
1016 1024 : key.length = strlen((char *)key.data) + 1;
1017 :
1018 1024 : rec.data = (uint8_t *) talloc_asprintf(tmp_ctx,
1019 : "data for record (%04d)",
1020 : i);
1021 1024 : rec.length = strlen((char *)rec.data) + 1;
1022 :
1023 1024 : ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
1024 1024 : assert_int_equal(ret, 0);
1025 :
1026 1024 : TALLOC_FREE(key.data);
1027 1024 : TALLOC_FREE(rec.data);
1028 : }
1029 :
1030 : /*
1031 : * Commit the transaction
1032 : */
1033 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1034 1 : assert_int_equal(ret, 0);
1035 :
1036 : /*
1037 : * Now iterate over the kv store and ensure that all the
1038 : * records are visited.
1039 : */
1040 :
1041 : /*
1042 : * Needs to be done inside a transaction
1043 : */
1044 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1045 1 : assert_int_equal(ret, 0);
1046 :
1047 1 : ret = ldb_kv->kv_ops->iterate(ldb_kv, update_fn, context);
1048 1025 : for (i = 0; i < NUM_RECS; i++) {
1049 1024 : assert_int_equal(1, context->visits[i]);
1050 : }
1051 :
1052 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1053 1 : assert_int_equal(ret, 0);
1054 :
1055 1 : TALLOC_FREE(tmp_ctx);
1056 1 : }
1057 :
1058 : /*
1059 : * Ensure that writes are not visible until the transaction has been
1060 : * committed.
1061 : */
1062 1 : static void test_write_transaction_isolation(void **state)
1063 : {
1064 : int ret;
1065 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
1066 : struct test_ctx);
1067 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
1068 : struct ldb_val key;
1069 : struct ldb_val val;
1070 :
1071 1 : const char *KEY1 = "KEY01";
1072 1 : const char *VAL1 = "VALUE01";
1073 :
1074 1 : const char *KEY2 = "KEY02";
1075 1 : const char *VAL2 = "VALUE02";
1076 :
1077 : /*
1078 : * Pipes etc to coordinate the processes
1079 : */
1080 : int to_child[2];
1081 : int to_parent[2];
1082 : char buf[2];
1083 : pid_t pid, w_pid;
1084 : int wstatus;
1085 :
1086 : TALLOC_CTX *tmp_ctx;
1087 1 : tmp_ctx = talloc_new(test_ctx);
1088 1 : assert_non_null(tmp_ctx);
1089 :
1090 :
1091 : /*
1092 : * Add a record to the database
1093 : */
1094 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1095 1 : assert_int_equal(ret, 0);
1096 :
1097 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1098 1 : key.length = strlen(KEY1) + 1;
1099 :
1100 1 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL1);
1101 1 : val.length = strlen(VAL1) + 1;
1102 :
1103 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1104 1 : assert_int_equal(ret, 0);
1105 :
1106 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1107 1 : assert_int_equal(ret, 0);
1108 :
1109 :
1110 1 : ret = pipe(to_child);
1111 1 : assert_int_equal(ret, 0);
1112 1 : ret = pipe(to_parent);
1113 1 : assert_int_equal(ret, 0);
1114 : /*
1115 : * Now fork a new process
1116 : */
1117 :
1118 1 : pid = fork();
1119 2 : if (pid == 0) {
1120 :
1121 1 : struct ldb_context *ldb = NULL;
1122 1 : close(to_child[1]);
1123 1 : close(to_parent[0]);
1124 :
1125 : /*
1126 : * Wait for the transaction to start
1127 : */
1128 1 : ret = read(to_child[0], buf, 2);
1129 1 : if (ret != 2) {
1130 0 : print_error(__location__": read returned (%d)\n",
1131 : ret);
1132 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1133 : }
1134 1 : ldb = ldb_init(test_ctx, test_ctx->ev);
1135 1 : ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
1136 1 : if (ret != LDB_SUCCESS) {
1137 0 : print_error(__location__": ldb_connect returned (%d)\n",
1138 : ret);
1139 0 : exit(ret);
1140 : }
1141 :
1142 1 : ldb_kv = get_ldb_kv(ldb);
1143 :
1144 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1145 1 : if (ret != LDB_SUCCESS) {
1146 0 : print_error(__location__": lock_read returned (%d)\n",
1147 : ret);
1148 0 : exit(ret);
1149 : }
1150 :
1151 : /*
1152 : * Check that KEY1 is there
1153 : */
1154 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1155 1 : key.length = strlen(KEY1) + 1;
1156 :
1157 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1158 1 : if (ret != LDB_SUCCESS) {
1159 0 : print_error(__location__": fetch_and_parse returned "
1160 : "(%d)\n",
1161 : ret);
1162 0 : exit(ret);
1163 : }
1164 :
1165 1 : if ((strlen(VAL1) + 1) != val.length) {
1166 0 : print_error(__location__": KEY1 value lengths different"
1167 : ", expected (%d) actual(%d)\n",
1168 0 : (int)(strlen(VAL1) + 1), (int)val.length);
1169 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1170 : }
1171 1 : if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
1172 0 : print_error(__location__": KEY1 values different, "
1173 : "expected (%s) actual(%s)\n",
1174 : VAL1,
1175 : val.data);
1176 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1177 : }
1178 :
1179 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1180 1 : if (ret != LDB_SUCCESS) {
1181 0 : print_error(__location__": unlock_read returned (%d)\n",
1182 : ret);
1183 0 : exit(ret);
1184 : }
1185 :
1186 : /*
1187 : * Check that KEY2 is not there
1188 : */
1189 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1190 1 : key.length = strlen(KEY2 + 1);
1191 :
1192 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1193 1 : if (ret != LDB_SUCCESS) {
1194 0 : print_error(__location__": lock_read returned (%d)\n",
1195 : ret);
1196 0 : exit(ret);
1197 : }
1198 :
1199 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1200 1 : if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1201 0 : print_error(__location__": fetch_and_parse returned "
1202 : "(%d)\n",
1203 : ret);
1204 0 : exit(ret);
1205 : }
1206 :
1207 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1208 1 : if (ret != LDB_SUCCESS) {
1209 0 : print_error(__location__": unlock_read returned (%d)\n",
1210 : ret);
1211 0 : exit(ret);
1212 : }
1213 :
1214 : /*
1215 : * Signal the other process to commit the transaction
1216 : */
1217 1 : ret = write(to_parent[1], "GO", 2);
1218 1 : if (ret != 2) {
1219 0 : print_error(__location__": write returned (%d)\n",
1220 : ret);
1221 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1222 : }
1223 :
1224 : /*
1225 : * Wait for the transaction to be committed
1226 : */
1227 1 : ret = read(to_child[0], buf, 2);
1228 1 : if (ret != 2) {
1229 0 : print_error(__location__": read returned (%d)\n",
1230 : ret);
1231 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1232 : }
1233 :
1234 : /*
1235 : * Check that KEY1 is there
1236 : */
1237 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1238 1 : if (ret != LDB_SUCCESS) {
1239 0 : print_error(__location__": unlock_read returned (%d)\n",
1240 : ret);
1241 0 : exit(ret);
1242 : }
1243 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1244 1 : key.length = strlen(KEY1) + 1;
1245 :
1246 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1247 1 : if (ret != LDB_SUCCESS) {
1248 0 : print_error(__location__": fetch_and_parse returned "
1249 : "(%d)\n",
1250 : ret);
1251 0 : exit(ret);
1252 : }
1253 :
1254 1 : if ((strlen(VAL1) + 1) != val.length) {
1255 0 : print_error(__location__": KEY1 value lengths different"
1256 : ", expected (%d) actual(%d)\n",
1257 0 : (int)(strlen(VAL1) + 1), (int)val.length);
1258 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1259 : }
1260 1 : if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
1261 0 : print_error(__location__": KEY1 values different, "
1262 : "expected (%s) actual(%s)\n",
1263 : VAL1,
1264 : val.data);
1265 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1266 : }
1267 :
1268 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1269 1 : if (ret != LDB_SUCCESS) {
1270 0 : print_error(__location__": unlock_read returned (%d)\n",
1271 : ret);
1272 0 : exit(ret);
1273 : }
1274 :
1275 :
1276 : /*
1277 : * Check that KEY2 is there
1278 : */
1279 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1280 1 : if (ret != LDB_SUCCESS) {
1281 0 : print_error(__location__": unlock_read returned (%d)\n",
1282 : ret);
1283 0 : exit(ret);
1284 : }
1285 :
1286 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1287 1 : key.length = strlen(KEY2) + 1;
1288 :
1289 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1290 1 : if (ret != LDB_SUCCESS) {
1291 0 : print_error(__location__": fetch_and_parse returned "
1292 : "(%d)\n",
1293 : ret);
1294 0 : exit(ret);
1295 : }
1296 :
1297 1 : if ((strlen(VAL2) + 1) != val.length) {
1298 0 : print_error(__location__": KEY2 value lengths different"
1299 : ", expected (%d) actual(%d)\n",
1300 0 : (int)(strlen(VAL2) + 1), (int)val.length);
1301 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1302 : }
1303 1 : if (memcmp(VAL2, val.data, strlen(VAL2)) != 0) {
1304 0 : print_error(__location__": KEY2 values different, "
1305 : "expected (%s) actual(%s)\n",
1306 : VAL2,
1307 : val.data);
1308 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1309 : }
1310 :
1311 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1312 1 : if (ret != LDB_SUCCESS) {
1313 0 : print_error(__location__": unlock_read returned (%d)\n",
1314 : ret);
1315 0 : exit(ret);
1316 : }
1317 :
1318 1 : exit(0);
1319 : }
1320 1 : close(to_child[0]);
1321 1 : close(to_parent[1]);
1322 :
1323 : /*
1324 : * Begin a transaction and add a record to the database
1325 : * but leave the transaction open
1326 : */
1327 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1328 1 : assert_int_equal(ret, 0);
1329 :
1330 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1331 1 : key.length = strlen(KEY2) + 1;
1332 :
1333 1 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL2);
1334 1 : val.length = strlen(VAL2) + 1;
1335 :
1336 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1337 1 : assert_int_equal(ret, 0);
1338 :
1339 : /*
1340 : * Signal the child process
1341 : */
1342 1 : ret = write(to_child[1], "GO", 2);
1343 1 : assert_int_equal(2, ret);
1344 :
1345 : /*
1346 : * Wait for the child process to check the DB state while the
1347 : * transaction is active
1348 : */
1349 1 : ret = read(to_parent[0], buf, 2);
1350 1 : assert_int_equal(2, ret);
1351 :
1352 : /*
1353 : * commit the transaction
1354 : */
1355 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1356 1 : assert_int_equal(0, ret);
1357 :
1358 : /*
1359 : * Signal the child process
1360 : */
1361 1 : ret = write(to_child[1], "GO", 2);
1362 1 : assert_int_equal(2, ret);
1363 :
1364 1 : w_pid = waitpid(pid, &wstatus, 0);
1365 1 : assert_int_equal(pid, w_pid);
1366 :
1367 1 : assert_true(WIFEXITED(wstatus));
1368 :
1369 1 : assert_int_equal(WEXITSTATUS(wstatus), 0);
1370 :
1371 :
1372 1 : TALLOC_FREE(tmp_ctx);
1373 1 : }
1374 :
1375 : /*
1376 : * Ensure that deletes are not visible until the transaction has been
1377 : * committed.
1378 : */
1379 1 : static void test_delete_transaction_isolation(void **state)
1380 : {
1381 : int ret;
1382 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
1383 : struct test_ctx);
1384 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
1385 : struct ldb_val key;
1386 : struct ldb_val val;
1387 :
1388 1 : const char *KEY1 = "KEY01";
1389 1 : const char *VAL1 = "VALUE01";
1390 :
1391 1 : const char *KEY2 = "KEY02";
1392 1 : const char *VAL2 = "VALUE02";
1393 :
1394 : /*
1395 : * Pipes etc to coordinate the processes
1396 : */
1397 : int to_child[2];
1398 : int to_parent[2];
1399 : char buf[2];
1400 : pid_t pid, w_pid;
1401 : int wstatus;
1402 :
1403 : TALLOC_CTX *tmp_ctx;
1404 1 : tmp_ctx = talloc_new(test_ctx);
1405 1 : assert_non_null(tmp_ctx);
1406 :
1407 :
1408 : /*
1409 : * Add records to the database
1410 : */
1411 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1412 1 : assert_int_equal(ret, 0);
1413 :
1414 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1415 1 : key.length = strlen(KEY1) + 1;
1416 :
1417 1 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL1);
1418 1 : val.length = strlen(VAL1) + 1;
1419 :
1420 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1421 1 : assert_int_equal(ret, 0);
1422 :
1423 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1424 1 : key.length = strlen(KEY2) + 1;
1425 :
1426 1 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL2);
1427 1 : val.length = strlen(VAL2) + 1;
1428 :
1429 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1430 1 : assert_int_equal(ret, 0);
1431 :
1432 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1433 1 : assert_int_equal(ret, 0);
1434 :
1435 :
1436 1 : ret = pipe(to_child);
1437 1 : assert_int_equal(ret, 0);
1438 1 : ret = pipe(to_parent);
1439 1 : assert_int_equal(ret, 0);
1440 : /*
1441 : * Now fork a new process
1442 : */
1443 :
1444 1 : pid = fork();
1445 2 : if (pid == 0) {
1446 :
1447 1 : struct ldb_context *ldb = NULL;
1448 1 : close(to_child[1]);
1449 1 : close(to_parent[0]);
1450 :
1451 : /*
1452 : * Wait for the transaction to be started
1453 : */
1454 1 : ret = read(to_child[0], buf, 2);
1455 1 : if (ret != 2) {
1456 0 : print_error(__location__": read returned (%d)\n",
1457 : ret);
1458 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1459 : }
1460 :
1461 1 : ldb = ldb_init(test_ctx, test_ctx->ev);
1462 1 : ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
1463 1 : if (ret != LDB_SUCCESS) {
1464 0 : print_error(__location__": ldb_connect returned (%d)\n",
1465 : ret);
1466 0 : exit(ret);
1467 : }
1468 :
1469 1 : ldb_kv = get_ldb_kv(ldb);
1470 :
1471 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1472 1 : if (ret != LDB_SUCCESS) {
1473 0 : print_error(__location__": lock_read returned (%d)\n",
1474 : ret);
1475 0 : exit(ret);
1476 : }
1477 :
1478 : /*
1479 : * Check that KEY1 is there
1480 : */
1481 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1482 1 : key.length = strlen(KEY1) + 1;
1483 :
1484 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1485 1 : if (ret != LDB_SUCCESS) {
1486 0 : print_error(__location__": fetch_and_parse returned "
1487 : "(%d)\n",
1488 : ret);
1489 0 : exit(ret);
1490 : }
1491 :
1492 1 : if ((strlen(VAL1) + 1) != val.length) {
1493 0 : print_error(__location__": KEY1 value lengths different"
1494 : ", expected (%d) actual(%d)\n",
1495 0 : (int)(strlen(VAL1) + 1), (int)val.length);
1496 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1497 : }
1498 1 : if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
1499 0 : print_error(__location__": KEY1 values different, "
1500 : "expected (%s) actual(%s)\n",
1501 : VAL1,
1502 : val.data);
1503 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1504 : }
1505 :
1506 : /*
1507 : * Check that KEY2 is there
1508 : */
1509 :
1510 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1511 1 : key.length = strlen(KEY2) + 1;
1512 :
1513 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1514 1 : if (ret != LDB_SUCCESS) {
1515 0 : print_error(__location__": fetch_and_parse returned "
1516 : "(%d)\n",
1517 : ret);
1518 0 : exit(ret);
1519 : }
1520 :
1521 1 : if ((strlen(VAL2) + 1) != val.length) {
1522 0 : print_error(__location__": KEY2 value lengths different"
1523 : ", expected (%d) actual(%d)\n",
1524 0 : (int)(strlen(VAL2) + 1), (int)val.length);
1525 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1526 : }
1527 1 : if (memcmp(VAL2, val.data, strlen(VAL2)) != 0) {
1528 0 : print_error(__location__": KEY2 values different, "
1529 : "expected (%s) actual(%s)\n",
1530 : VAL2,
1531 : val.data);
1532 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1533 : }
1534 :
1535 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1536 1 : if (ret != LDB_SUCCESS) {
1537 0 : print_error(__location__": unlock_read returned (%d)\n",
1538 : ret);
1539 0 : exit(ret);
1540 : }
1541 :
1542 : /*
1543 : * Signal the other process to commit the transaction
1544 : */
1545 1 : ret = write(to_parent[1], "GO", 2);
1546 1 : if (ret != 2) {
1547 0 : print_error(__location__": write returned (%d)\n",
1548 : ret);
1549 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1550 : }
1551 :
1552 : /*
1553 : * Wait for the transaction to be committed
1554 : */
1555 1 : ret = read(to_child[0], buf, 2);
1556 1 : if (ret != 2) {
1557 0 : print_error(__location__": read returned (%d)\n",
1558 : ret);
1559 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1560 : }
1561 :
1562 : /*
1563 : * Check that KEY1 is there
1564 : */
1565 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1566 1 : if (ret != LDB_SUCCESS) {
1567 0 : print_error(__location__": unlock_read returned (%d)\n",
1568 : ret);
1569 0 : exit(ret);
1570 : }
1571 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1572 1 : key.length = strlen(KEY1) + 1;
1573 :
1574 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1575 1 : if (ret != LDB_SUCCESS) {
1576 0 : print_error(__location__": fetch_and_parse returned "
1577 : "(%d)\n",
1578 : ret);
1579 0 : exit(ret);
1580 : }
1581 :
1582 1 : if ((strlen(VAL1) + 1) != val.length) {
1583 0 : print_error(__location__": KEY1 value lengths different"
1584 : ", expected (%d) actual(%d)\n",
1585 0 : (int)(strlen(VAL1) + 1), (int)val.length);
1586 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1587 : }
1588 1 : if (memcmp(VAL1, val.data, strlen(VAL1)) != 0) {
1589 0 : print_error(__location__": KEY1 values different, "
1590 : "expected (%s) actual(%s)\n",
1591 : VAL1,
1592 : val.data);
1593 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1594 : }
1595 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1596 1 : if (ret != LDB_SUCCESS) {
1597 0 : print_error(__location__": unlock_read returned (%d)\n",
1598 : ret);
1599 0 : exit(ret);
1600 : }
1601 :
1602 : /*
1603 : * Check that KEY2 is not there
1604 : */
1605 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1606 1 : key.length = strlen(KEY2 + 1);
1607 :
1608 1 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1609 1 : if (ret != LDB_SUCCESS) {
1610 0 : print_error(__location__": lock_read returned (%d)\n",
1611 : ret);
1612 0 : exit(ret);
1613 : }
1614 :
1615 1 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1616 1 : if (ret != LDB_ERR_NO_SUCH_OBJECT) {
1617 0 : print_error(__location__": fetch_and_parse returned "
1618 : "(%d)\n",
1619 : ret);
1620 0 : exit(ret);
1621 : }
1622 :
1623 1 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1624 1 : if (ret != LDB_SUCCESS) {
1625 0 : print_error(__location__": unlock_read returned (%d)\n",
1626 : ret);
1627 0 : exit(ret);
1628 : }
1629 1 : TALLOC_FREE(tmp_ctx);
1630 1 : exit(0);
1631 : }
1632 1 : close(to_child[0]);
1633 1 : close(to_parent[1]);
1634 :
1635 : /*
1636 : * Begin a transaction and delete a record from the database
1637 : * but leave the transaction open
1638 : */
1639 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1640 1 : assert_int_equal(ret, 0);
1641 :
1642 1 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1643 1 : key.length = strlen(KEY2) + 1;
1644 :
1645 1 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
1646 1 : assert_int_equal(ret, 0);
1647 : /*
1648 : * Signal the child process
1649 : */
1650 1 : ret = write(to_child[1], "GO", 2);
1651 1 : assert_int_equal(2, ret);
1652 :
1653 : /*
1654 : * Wait for the child process to check the DB state while the
1655 : * transaction is active
1656 : */
1657 1 : ret = read(to_parent[0], buf, 2);
1658 1 : assert_int_equal(2, ret);
1659 :
1660 : /*
1661 : * commit the transaction
1662 : */
1663 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1664 1 : assert_int_equal(0, ret);
1665 :
1666 : /*
1667 : * Signal the child process
1668 : */
1669 1 : ret = write(to_child[1], "GO", 2);
1670 1 : assert_int_equal(2, ret);
1671 :
1672 1 : w_pid = waitpid(pid, &wstatus, 0);
1673 1 : assert_int_equal(pid, w_pid);
1674 :
1675 1 : assert_true(WIFEXITED(wstatus));
1676 :
1677 1 : assert_int_equal(WEXITSTATUS(wstatus), 0);
1678 :
1679 :
1680 1 : TALLOC_FREE(tmp_ctx);
1681 1 : }
1682 :
1683 :
1684 : /*
1685 : * Test that get_size returns a sensible estimate of the number of records
1686 : * in the database.
1687 : */
1688 1 : static void test_get_size(void **state)
1689 : {
1690 : int ret;
1691 1 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
1692 : struct test_ctx);
1693 1 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
1694 1 : uint8_t key_val[] = "TheKey";
1695 1 : struct ldb_val key = {
1696 : .data = key_val,
1697 : .length = sizeof(key_val)
1698 : };
1699 :
1700 1 : uint8_t value[] = "The record contents";
1701 1 : struct ldb_val data = {
1702 : .data = value,
1703 : .length = sizeof(value)
1704 : };
1705 1 : size_t size = 0;
1706 :
1707 1 : int flags = 0;
1708 : TALLOC_CTX *tmp_ctx;
1709 :
1710 1 : tmp_ctx = talloc_new(test_ctx);
1711 1 : assert_non_null(tmp_ctx);
1712 :
1713 1 : size = ldb_kv->kv_ops->get_size(ldb_kv);
1714 : #if defined(TEST_LMDB)
1715 : assert_int_equal(2, size);
1716 : #else
1717 : /*
1718 : * The tdb implementation of get_size over estimates for sparse files
1719 : * which is perfectly acceptable for it's intended use.
1720 : * mipsel, ia64: 9994
1721 : * ppc64el, powerpc, ppc64: 13369
1722 : * sparc64: 5046
1723 : */
1724 1 : assert_in_range(size, 2500, 15000);
1725 : #endif
1726 :
1727 : /*
1728 : * Begin a transaction
1729 : */
1730 1 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1731 1 : assert_int_equal(ret, 0);
1732 :
1733 : /*
1734 : * Write the record
1735 : */
1736 1 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
1737 1 : assert_int_equal(ret, 0);
1738 :
1739 : /*
1740 : * Commit the transaction
1741 : */
1742 1 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1743 1 : assert_int_equal(ret, 0);
1744 :
1745 1 : size = ldb_kv->kv_ops->get_size(ldb_kv);
1746 : #ifdef TEST_LMDB
1747 : assert_int_equal(3, size);
1748 : #else
1749 : /*
1750 : * The tdb implementation of get_size over estimates for sparse files
1751 : * which is perfectly acceptable for it's intended use.
1752 : * mipsel, ia64: 9994
1753 : * ppc64el, powerpc, ppc64: 13369
1754 : * sparc64: 5046
1755 : */
1756 1 : assert_in_range(size, 2500, 15000);
1757 : #endif
1758 1 : talloc_free(tmp_ctx);
1759 1 : }
1760 :
1761 1 : int main(int argc, const char **argv)
1762 : {
1763 1 : const struct CMUnitTest tests[] = {
1764 : cmocka_unit_test_setup_teardown(
1765 : test_add_get,
1766 : setup,
1767 : teardown),
1768 : cmocka_unit_test_setup_teardown(
1769 : test_delete,
1770 : setup,
1771 : teardown),
1772 : cmocka_unit_test_setup_teardown(
1773 : test_transaction_abort_write,
1774 : setup,
1775 : teardown),
1776 : cmocka_unit_test_setup_teardown(
1777 : test_transaction_abort_delete,
1778 : setup,
1779 : teardown),
1780 : cmocka_unit_test_setup_teardown(
1781 : test_read_outside_transaction,
1782 : setup,
1783 : teardown),
1784 : cmocka_unit_test_setup_teardown(
1785 : test_write_outside_transaction,
1786 : setup,
1787 : teardown),
1788 : cmocka_unit_test_setup_teardown(
1789 : test_delete_outside_transaction,
1790 : setup,
1791 : teardown),
1792 : cmocka_unit_test_setup_teardown(
1793 : test_iterate,
1794 : setup,
1795 : teardown),
1796 : cmocka_unit_test_setup_teardown(
1797 : test_iterate_range,
1798 : setup,
1799 : teardown),
1800 : cmocka_unit_test_setup_teardown(
1801 : test_update_in_iterate,
1802 : setup,
1803 : teardown),
1804 : cmocka_unit_test_setup_teardown(
1805 : test_write_transaction_isolation,
1806 : setup,
1807 : teardown),
1808 : cmocka_unit_test_setup_teardown(
1809 : test_delete_transaction_isolation,
1810 : setup,
1811 : teardown),
1812 : cmocka_unit_test_setup_teardown(
1813 : test_get_size,
1814 : setup,
1815 : teardown),
1816 : };
1817 :
1818 1 : return cmocka_run_group_tests(tests, NULL, NULL);
1819 : }
|