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 52 : static void unlink_old_db(struct test_ctx *test_ctx)
92 : {
93 52 : int ret;
94 :
95 52 : errno = 0;
96 52 : ret = unlink(test_ctx->lockfile);
97 52 : if (ret == -1 && errno != ENOENT) {
98 0 : fail();
99 : }
100 :
101 52 : errno = 0;
102 52 : ret = unlink(test_ctx->dbfile);
103 52 : if (ret == -1 && errno != ENOENT) {
104 0 : fail();
105 : }
106 52 : }
107 :
108 26 : static int noconn_setup(void **state)
109 : {
110 26 : struct test_ctx *test_ctx;
111 :
112 26 : test_ctx = talloc_zero(NULL, struct test_ctx);
113 26 : assert_non_null(test_ctx);
114 :
115 26 : test_ctx->ev = tevent_context_init(test_ctx);
116 26 : assert_non_null(test_ctx->ev);
117 :
118 26 : test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
119 26 : assert_non_null(test_ctx->ldb);
120 :
121 26 : test_ctx->dbfile = talloc_strdup(test_ctx, "kvopstest.ldb");
122 26 : assert_non_null(test_ctx->dbfile);
123 :
124 26 : test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
125 : test_ctx->dbfile);
126 26 : assert_non_null(test_ctx->lockfile);
127 :
128 26 : test_ctx->dbpath = talloc_asprintf(test_ctx,
129 : TEST_BE"://%s", test_ctx->dbfile);
130 26 : assert_non_null(test_ctx->dbpath);
131 :
132 26 : unlink_old_db(test_ctx);
133 26 : *state = test_ctx;
134 26 : return 0;
135 : }
136 :
137 26 : static int noconn_teardown(void **state)
138 : {
139 26 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
140 : struct test_ctx);
141 :
142 26 : unlink_old_db(test_ctx);
143 26 : talloc_free(test_ctx);
144 26 : return 0;
145 : }
146 :
147 26 : static int setup(void **state)
148 : {
149 26 : struct test_ctx *test_ctx;
150 26 : int ret;
151 26 : struct ldb_ldif *ldif;
152 26 : const char *index_ldif = \
153 : "dn: @INDEXLIST\n"
154 : "@IDXGUID: objectUUID\n"
155 : "@IDX_DN_GUID: GUID\n"
156 : "\n";
157 :
158 26 : noconn_setup((void **) &test_ctx);
159 :
160 26 : ret = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
161 26 : assert_int_equal(ret, 0);
162 :
163 52 : while ((ldif = ldb_ldif_read_string(test_ctx->ldb, &index_ldif))) {
164 26 : ret = ldb_add(test_ctx->ldb, ldif->msg);
165 26 : assert_int_equal(ret, LDB_SUCCESS);
166 : }
167 26 : *state = test_ctx;
168 26 : return 0;
169 : }
170 :
171 26 : static int teardown(void **state)
172 : {
173 26 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
174 : struct test_ctx);
175 26 : noconn_teardown((void **) &test_ctx);
176 26 : return 0;
177 : }
178 :
179 40 : static struct ldb_kv_private *get_ldb_kv(struct ldb_context *ldb)
180 : {
181 40 : void *data = NULL;
182 40 : struct ldb_kv_private *ldb_kv = NULL;
183 :
184 40 : data = ldb_module_get_private(ldb->modules);
185 40 : assert_non_null(data);
186 :
187 40 : ldb_kv = talloc_get_type(data, struct ldb_kv_private);
188 40 : assert_non_null(ldb_kv);
189 :
190 40 : return ldb_kv;
191 : }
192 :
193 26 : static int parse(struct ldb_val key,
194 : struct ldb_val data,
195 : void *private_data)
196 : {
197 26 : struct ldb_val* read = private_data;
198 :
199 : /* Yes, we leak this. That is OK */
200 26 : read->data = talloc_size(NULL,
201 : data.length);
202 26 : assert_non_null(read->data);
203 :
204 26 : memcpy(read->data, data.data, data.length);
205 26 : read->length = data.length;
206 26 : return LDB_SUCCESS;
207 : }
208 :
209 : /*
210 : * Parse function that just returns the int we pass it.
211 : */
212 100 : static int parse_return(struct ldb_val key,
213 : struct ldb_val data,
214 : void *private_data)
215 : {
216 100 : int *rcode = private_data;
217 100 : return *rcode;
218 : }
219 :
220 : /*
221 : * Test that data can be written to the kv store and be read back.
222 : */
223 2 : static void test_add_get(void **state)
224 : {
225 2 : int ret;
226 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
227 : struct test_ctx);
228 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
229 2 : uint8_t key_val[] = "TheKey";
230 2 : struct ldb_val key = {
231 : .data = key_val,
232 : .length = sizeof(key_val)
233 : };
234 :
235 2 : uint8_t value[] = "The record contents";
236 2 : struct ldb_val data = {
237 : .data = value,
238 : .length = sizeof(value)
239 : };
240 :
241 2 : struct ldb_val read;
242 2 : int rcode;
243 :
244 2 : int flags = 0;
245 2 : TALLOC_CTX *tmp_ctx;
246 :
247 2 : tmp_ctx = talloc_new(test_ctx);
248 2 : assert_non_null(tmp_ctx);
249 :
250 : /*
251 : * Begin a transaction
252 : */
253 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
254 2 : assert_int_equal(ret, 0);
255 :
256 : /*
257 : * Write the record
258 : */
259 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
260 2 : assert_int_equal(ret, 0);
261 :
262 : /*
263 : * Commit the transaction
264 : */
265 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
266 2 : assert_int_equal(ret, 0);
267 :
268 : /*
269 : * And now read it back
270 : */
271 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
272 2 : assert_int_equal(ret, 0);
273 :
274 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
275 2 : assert_int_equal(ret, 0);
276 :
277 2 : assert_int_equal(sizeof(value), read.length);
278 2 : 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 102 : for (rcode=0; rcode<50; rcode++) {
285 100 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key,
286 : parse_return,
287 : &rcode);
288 100 : assert_int_equal(ret, rcode);
289 : }
290 :
291 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
292 2 : assert_int_equal(ret, 0);
293 2 : talloc_free(tmp_ctx);
294 2 : }
295 :
296 : /*
297 : * Test that attempts to read data without a read transaction fail.
298 : */
299 2 : static void test_read_outside_transaction(void **state)
300 : {
301 2 : int ret;
302 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
303 : struct test_ctx);
304 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
305 2 : uint8_t key_val[] = "TheKey";
306 2 : struct ldb_val key = {
307 : .data = key_val,
308 : .length = sizeof(key_val)
309 : };
310 :
311 2 : uint8_t value[] = "The record contents";
312 2 : struct ldb_val data = {
313 : .data = value,
314 : .length = sizeof(value)
315 : };
316 :
317 2 : struct ldb_val read;
318 :
319 2 : int flags = 0;
320 2 : TALLOC_CTX *tmp_ctx;
321 :
322 2 : tmp_ctx = talloc_new(test_ctx);
323 2 : assert_non_null(tmp_ctx);
324 :
325 : /*
326 : * Begin a transaction
327 : */
328 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
329 2 : assert_int_equal(ret, 0);
330 :
331 : /*
332 : * Write the record
333 : */
334 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
335 2 : assert_int_equal(ret, 0);
336 :
337 : /*
338 : * Commit the transaction
339 : */
340 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
341 2 : assert_int_equal(ret, 0);
342 :
343 : /*
344 : * And now read it back
345 : * Note there is no read transaction active
346 : */
347 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
348 2 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
349 :
350 2 : talloc_free(tmp_ctx);
351 2 : }
352 :
353 : /*
354 : * Test that data can be deleted from the kv store
355 : */
356 2 : static void test_delete(void **state)
357 : {
358 2 : int ret;
359 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
360 : struct test_ctx);
361 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
362 2 : uint8_t key_val[] = "TheKey";
363 2 : struct ldb_val key = {
364 : .data = key_val,
365 : .length = sizeof(key_val)
366 : };
367 :
368 2 : uint8_t value[] = "The record contents";
369 2 : struct ldb_val data = {
370 : .data = value,
371 : .length = sizeof(value)
372 : };
373 :
374 2 : struct ldb_val read;
375 :
376 2 : int flags = 0;
377 2 : TALLOC_CTX *tmp_ctx;
378 :
379 2 : tmp_ctx = talloc_new(test_ctx);
380 2 : assert_non_null(tmp_ctx);
381 :
382 : /*
383 : * Begin a transaction
384 : */
385 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
386 2 : assert_int_equal(ret, 0);
387 :
388 : /*
389 : * Write the record
390 : */
391 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
392 2 : assert_int_equal(ret, 0);
393 :
394 : /*
395 : * Commit the transaction
396 : */
397 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
398 2 : assert_int_equal(ret, 0);
399 :
400 : /*
401 : * And now read it back
402 : */
403 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
404 2 : assert_int_equal(ret, 0);
405 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
406 2 : assert_int_equal(ret, 0);
407 2 : assert_int_equal(sizeof(value), read.length);
408 2 : assert_memory_equal(value, read.data, sizeof(value));
409 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
410 2 : assert_int_equal(ret, 0);
411 :
412 : /*
413 : * Begin a transaction
414 : */
415 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
416 2 : assert_int_equal(ret, 0);
417 :
418 : /*
419 : * Now delete it.
420 : */
421 2 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
422 2 : assert_int_equal(ret, 0);
423 :
424 : /*
425 : * Commit the transaction
426 : */
427 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
428 2 : assert_int_equal(ret, 0);
429 :
430 : /*
431 : * And now try to read it back
432 : */
433 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
434 2 : assert_int_equal(ret, 0);
435 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
436 2 : assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
437 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
438 2 : assert_int_equal(ret, 0);
439 :
440 2 : talloc_free(tmp_ctx);
441 2 : }
442 :
443 : /*
444 : * Check that writes are correctly rolled back when a transaction
445 : * is rolled back.
446 : */
447 2 : static void test_transaction_abort_write(void **state)
448 : {
449 2 : int ret;
450 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
451 : struct test_ctx);
452 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
453 2 : uint8_t key_val[] = "TheKey";
454 2 : struct ldb_val key = {
455 : .data = key_val,
456 : .length = sizeof(key_val)
457 : };
458 :
459 2 : uint8_t value[] = "The record contents";
460 2 : struct ldb_val data = {
461 : .data = value,
462 : .length = sizeof(value)
463 : };
464 :
465 2 : struct ldb_val read;
466 :
467 2 : int flags = 0;
468 2 : TALLOC_CTX *tmp_ctx;
469 :
470 2 : tmp_ctx = talloc_new(test_ctx);
471 2 : assert_non_null(tmp_ctx);
472 :
473 : /*
474 : * Begin a transaction
475 : */
476 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
477 2 : assert_int_equal(ret, 0);
478 :
479 : /*
480 : * Write the record
481 : */
482 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
483 2 : assert_int_equal(ret, 0);
484 :
485 : /*
486 : * And now read it back
487 : */
488 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
489 2 : assert_int_equal(ret, 0);
490 2 : assert_int_equal(sizeof(value), read.length);
491 2 : assert_memory_equal(value, read.data, sizeof(value));
492 :
493 :
494 : /*
495 : * Now abort the transaction
496 : */
497 2 : ret = ldb_kv->kv_ops->abort_write(ldb_kv);
498 2 : assert_int_equal(ret, 0);
499 :
500 : /*
501 : * And now read it back, should not be there
502 : */
503 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
504 2 : assert_int_equal(ret, 0);
505 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
506 2 : assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
507 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
508 2 : assert_int_equal(ret, 0);
509 :
510 2 : talloc_free(tmp_ctx);
511 2 : }
512 :
513 : /*
514 : * Check that deletes are correctly rolled back when a transaction is
515 : * aborted.
516 : */
517 2 : static void test_transaction_abort_delete(void **state)
518 : {
519 2 : int ret;
520 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
521 : struct test_ctx);
522 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
523 2 : uint8_t key_val[] = "TheKey";
524 2 : struct ldb_val key = {
525 : .data = key_val,
526 : .length = sizeof(key_val)
527 : };
528 :
529 2 : uint8_t value[] = "The record contents";
530 2 : struct ldb_val data = {
531 : .data = value,
532 : .length = sizeof(value)
533 : };
534 :
535 2 : struct ldb_val read;
536 :
537 2 : int flags = 0;
538 2 : TALLOC_CTX *tmp_ctx;
539 :
540 2 : tmp_ctx = talloc_new(test_ctx);
541 2 : assert_non_null(tmp_ctx);
542 :
543 : /*
544 : * Begin a transaction
545 : */
546 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
547 2 : assert_int_equal(ret, 0);
548 :
549 : /*
550 : * Write the record
551 : */
552 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
553 2 : assert_int_equal(ret, 0);
554 :
555 : /*
556 : * Commit the transaction
557 : */
558 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
559 2 : assert_int_equal(ret, 0);
560 :
561 : /*
562 : * And now read it back
563 : */
564 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
565 2 : assert_int_equal(ret, 0);
566 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
567 2 : assert_int_equal(ret, 0);
568 2 : assert_int_equal(sizeof(value), read.length);
569 2 : assert_memory_equal(value, read.data, sizeof(value));
570 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
571 2 : assert_int_equal(ret, 0);
572 :
573 : /*
574 : * Begin a transaction
575 : */
576 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
577 2 : assert_int_equal(ret, 0);
578 :
579 : /*
580 : * Now delete it.
581 : */
582 2 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
583 2 : assert_int_equal(ret, 0);
584 :
585 : /*
586 : * And now read it back
587 : */
588 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
589 2 : assert_int_equal(ret, LDB_ERR_NO_SUCH_OBJECT);
590 :
591 : /*
592 : * Abort the transaction
593 : */
594 2 : ret = ldb_kv->kv_ops->abort_write(ldb_kv);
595 2 : assert_int_equal(ret, 0);
596 :
597 : /*
598 : * And now try to read it back
599 : */
600 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
601 2 : assert_int_equal(ret, 0);
602 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
603 2 : assert_int_equal(ret, 0);
604 2 : assert_int_equal(sizeof(value), read.length);
605 2 : assert_memory_equal(value, read.data, sizeof(value));
606 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
607 2 : assert_int_equal(ret, 0);
608 :
609 2 : talloc_free(tmp_ctx);
610 2 : }
611 :
612 : /*
613 : * Test that writes outside a transaction fail
614 : */
615 2 : static void test_write_outside_transaction(void **state)
616 : {
617 2 : int ret;
618 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
619 : struct test_ctx);
620 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
621 2 : uint8_t key_val[] = "TheKey";
622 2 : struct ldb_val key = {
623 : .data = key_val,
624 : .length = sizeof(key_val)
625 : };
626 :
627 2 : uint8_t value[] = "The record contents";
628 2 : struct ldb_val data = {
629 : .data = value,
630 : .length = sizeof(value)
631 : };
632 :
633 :
634 2 : int flags = 0;
635 2 : TALLOC_CTX *tmp_ctx;
636 :
637 2 : tmp_ctx = talloc_new(test_ctx);
638 2 : assert_non_null(tmp_ctx);
639 :
640 : /*
641 : * Attempt to write the record
642 : */
643 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
644 2 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
645 :
646 2 : talloc_free(tmp_ctx);
647 2 : }
648 :
649 : /*
650 : * Test data can not be deleted outside a transaction
651 : */
652 2 : static void test_delete_outside_transaction(void **state)
653 : {
654 2 : int ret;
655 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
656 : struct test_ctx);
657 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
658 2 : uint8_t key_val[] = "TheKey";
659 2 : struct ldb_val key = {
660 : .data = key_val,
661 : .length = sizeof(key_val)
662 : };
663 :
664 2 : uint8_t value[] = "The record contents";
665 2 : struct ldb_val data = {
666 : .data = value,
667 : .length = sizeof(value)
668 : };
669 :
670 2 : struct ldb_val read;
671 :
672 2 : int flags = 0;
673 2 : TALLOC_CTX *tmp_ctx;
674 :
675 2 : tmp_ctx = talloc_new(test_ctx);
676 2 : assert_non_null(tmp_ctx);
677 :
678 : /*
679 : * Begin a transaction
680 : */
681 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
682 2 : assert_int_equal(ret, 0);
683 :
684 : /*
685 : * Write the record
686 : */
687 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
688 2 : assert_int_equal(ret, 0);
689 :
690 : /*
691 : * Commit the transaction
692 : */
693 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
694 2 : assert_int_equal(ret, 0);
695 :
696 : /*
697 : * And now read it back
698 : */
699 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
700 2 : assert_int_equal(ret, 0);
701 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
702 2 : assert_int_equal(ret, 0);
703 2 : assert_int_equal(sizeof(value), read.length);
704 2 : assert_memory_equal(value, read.data, sizeof(value));
705 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
706 2 : assert_int_equal(ret, 0);
707 :
708 : /*
709 : * Now attempt to delete a record
710 : */
711 2 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
712 2 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
713 :
714 : /*
715 : * And now read it back
716 : */
717 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
718 2 : assert_int_equal(ret, 0);
719 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &read);
720 2 : assert_int_equal(ret, 0);
721 2 : assert_int_equal(sizeof(value), read.length);
722 2 : assert_memory_equal(value, read.data, sizeof(value));
723 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
724 2 : assert_int_equal(ret, 0);
725 :
726 2 : talloc_free(tmp_ctx);
727 2 : }
728 :
729 3675 : 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 3675 : int *visits = ctx;
736 3675 : int i;
737 :
738 3675 : if (strncmp("key ", (char *) key.data, 4) == 0) {
739 3671 : i = strtol((char *) &key.data[4], NULL, 10);
740 3671 : visits[i]++;
741 : }
742 3675 : return LDB_SUCCESS;
743 : }
744 :
745 : /*
746 : * Test that iterate visits all the records.
747 : */
748 2 : static void test_iterate(void **state)
749 2 : {
750 2 : int ret;
751 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
752 : struct test_ctx);
753 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
754 2 : int i;
755 2 : int num_recs = 1024;
756 2 : int visits[num_recs];
757 :
758 2 : TALLOC_CTX *tmp_ctx;
759 :
760 2 : tmp_ctx = talloc_new(test_ctx);
761 2 : assert_non_null(tmp_ctx);
762 :
763 : /*
764 : * Begin a transaction
765 : */
766 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
767 2 : assert_int_equal(ret, 0);
768 :
769 : /*
770 : * Write the records
771 : */
772 2052 : for (i = 0; i < num_recs; i++) {
773 2048 : struct ldb_val key;
774 2048 : struct ldb_val rec;
775 2048 : int flags = 0;
776 :
777 2048 : visits[i] = 0;
778 2048 : key.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
779 2048 : key.length = strlen((char *)key.data) + 1;
780 :
781 2048 : rec.data = (uint8_t *) talloc_asprintf(tmp_ctx,
782 : "data for record (%04d)",
783 : i);
784 2048 : rec.length = strlen((char *)rec.data) + 1;
785 :
786 2048 : ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
787 2048 : assert_int_equal(ret, 0);
788 :
789 2048 : TALLOC_FREE(key.data);
790 2048 : TALLOC_FREE(rec.data);
791 : }
792 :
793 : /*
794 : * Commit the transaction
795 : */
796 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
797 2 : 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 2 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
804 2 : assert_int_equal(ret, 0);
805 2 : ret = ldb_kv->kv_ops->iterate(ldb_kv, traverse_fn, visits);
806 2052 : for (i = 0; i <num_recs; i++) {
807 2048 : assert_int_equal(1, visits[i]);
808 : }
809 2 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
810 2 : assert_int_equal(ret, 0);
811 :
812 2 : TALLOC_FREE(tmp_ctx);
813 2 : }
814 :
815 12 : static void do_iterate_range_test(void **state, int range_start,
816 : int range_end, bool fail)
817 12 : {
818 12 : int ret;
819 12 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
820 : struct test_ctx);
821 12 : struct ldb_kv_private *ldb_kv = NULL;
822 12 : int i;
823 12 : int num_recs = 1024;
824 12 : int skip_recs = 10;
825 12 : int visits[num_recs];
826 12 : struct ldb_val sk, ek;
827 :
828 12 : TALLOC_CTX *tmp_ctx;
829 :
830 12 : ldb_kv = get_ldb_kv(test_ctx->ldb);
831 12 : assert_non_null(ldb_kv);
832 :
833 6162 : for (i = 0; i < num_recs; i++){
834 6144 : visits[i] = 0;
835 : }
836 :
837 : /*
838 : * No iterate_range on tdb
839 : */
840 12 : if (strcmp(TEST_BE, "tdb") == 0) {
841 7 : return;
842 : }
843 :
844 6 : tmp_ctx = talloc_new(test_ctx);
845 6 : assert_non_null(tmp_ctx);
846 :
847 : /*
848 : * Begin a transaction
849 : */
850 6 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
851 6 : assert_int_equal(ret, 0);
852 :
853 : /*
854 : * Write the records
855 : */
856 6042 : for (i = skip_recs; i <= num_recs - skip_recs; i++) {
857 6030 : struct ldb_val key;
858 6030 : struct ldb_val rec;
859 6030 : int flags = 0;
860 :
861 6030 : key.data = (uint8_t *)talloc_asprintf(tmp_ctx,
862 : "key %04d",
863 : i);
864 6030 : key.length = strlen((char *)key.data);
865 :
866 6030 : rec.data = (uint8_t *)talloc_asprintf(tmp_ctx,
867 : "data for record (%04d)",
868 : i);
869 6030 : rec.length = strlen((char *)rec.data) + 1;
870 :
871 6030 : ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
872 6030 : assert_int_equal(ret, 0);
873 :
874 6030 : TALLOC_FREE(key.data);
875 6030 : TALLOC_FREE(rec.data);
876 : }
877 :
878 : /*
879 : * Commit the transaction
880 : */
881 6 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
882 6 : assert_int_equal(ret, 0);
883 :
884 6 : sk.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", range_start);
885 6 : sk.length = strlen((char *)sk.data);
886 :
887 6 : ek.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", range_end);
888 6 : ek.length = strlen((char *)ek.data) + 1;
889 :
890 6 : ret = ldb_kv->kv_ops->lock_read(test_ctx->ldb->modules);
891 6 : assert_int_equal(ret, 0);
892 6 : ret = ldb_kv->kv_ops->iterate_range(ldb_kv, sk, ek,
893 : traverse_fn, visits);
894 6 : if (fail){
895 1 : assert_int_equal(ret, LDB_ERR_PROTOCOL_ERROR);
896 1 : TALLOC_FREE(tmp_ctx);
897 1 : return;
898 : } else{
899 5 : assert_int_equal(ret, 0);
900 : }
901 5130 : for (i = 0; i < num_recs; i++) {
902 5120 : if (i >= skip_recs && i <= num_recs - skip_recs &&
903 5025 : i >= range_start && i <= range_end){
904 1623 : assert_int_equal(1, visits[i]);
905 : } else {
906 3497 : assert_int_equal(0, visits[i]);
907 : }
908 : }
909 :
910 5 : ret = ldb_kv->kv_ops->unlock_read(test_ctx->ldb->modules);
911 5 : assert_int_equal(ret, 0);
912 :
913 5 : TALLOC_FREE(tmp_ctx);
914 : }
915 :
916 : /*
917 : * Test that iterate_range visits all the records between two keys.
918 : */
919 2 : static void test_iterate_range(void **state)
920 : {
921 2 : do_iterate_range_test(state, 300, 900, false);
922 :
923 : /*
924 : * test start_key = end_key
925 : */
926 2 : do_iterate_range_test(state, 20, 20, false);
927 :
928 : /*
929 : * test reverse range fails
930 : */
931 2 : 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 2 : do_iterate_range_test(state, 0, 20, false);
937 2 : do_iterate_range_test(state, 1010, 1030, false);
938 2 : do_iterate_range_test(state, 0, 1030, false);
939 2 : }
940 :
941 : struct update_context {
942 : struct ldb_context* ldb;
943 : int visits[NUM_RECS];
944 : };
945 :
946 2855 : 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 2855 : struct ldb_val new_key;
953 2855 : struct ldb_module *module = NULL;
954 2855 : struct update_context *context =NULL;
955 2855 : int ret = LDB_SUCCESS;
956 2855 : TALLOC_CTX *tmp_ctx;
957 :
958 2855 : tmp_ctx = talloc_new(ldb_kv);
959 2855 : assert_non_null(tmp_ctx);
960 :
961 2855 : context = talloc_get_type_abort(ctx, struct update_context);
962 :
963 2855 : module = talloc_zero(tmp_ctx, struct ldb_module);
964 2855 : module->ldb = context->ldb;
965 :
966 2855 : if (strncmp("key ", (char *) key.data, 4) == 0) {
967 2048 : int i = strtol((char *) &key.data[4], NULL, 10);
968 2048 : context->visits[i]++;
969 2048 : new_key.data = talloc_memdup(tmp_ctx, key.data, key.length);
970 2048 : new_key.length = key.length;
971 2048 : new_key.data[0] = 'K';
972 :
973 2048 : ret = ldb_kv->kv_ops->update_in_iterate(
974 : ldb_kv, key, new_key, data, &module);
975 : }
976 2855 : TALLOC_FREE(tmp_ctx);
977 2855 : return ret;
978 : }
979 :
980 : /*
981 : * Test that update_in_iterate behaves as expected.
982 : */
983 2 : static void test_update_in_iterate(void **state)
984 : {
985 2 : int ret;
986 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
987 : struct test_ctx);
988 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
989 2 : int i;
990 2 : struct update_context *context = NULL;
991 :
992 :
993 2 : TALLOC_CTX *tmp_ctx;
994 :
995 2 : tmp_ctx = talloc_new(test_ctx);
996 2 : assert_non_null(tmp_ctx);
997 :
998 2 : context = talloc_zero(tmp_ctx, struct update_context);
999 2 : assert_non_null(context);
1000 2 : context->ldb = test_ctx->ldb;
1001 : /*
1002 : * Begin a transaction
1003 : */
1004 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1005 2 : assert_int_equal(ret, 0);
1006 :
1007 : /*
1008 : * Write the records
1009 : */
1010 2052 : for (i = 0; i < NUM_RECS; i++) {
1011 2048 : struct ldb_val key;
1012 2048 : struct ldb_val rec;
1013 2048 : int flags = 0;
1014 :
1015 2048 : key.data = (uint8_t *)talloc_asprintf(tmp_ctx, "key %04d", i);
1016 2048 : key.length = strlen((char *)key.data) + 1;
1017 :
1018 2048 : rec.data = (uint8_t *) talloc_asprintf(tmp_ctx,
1019 : "data for record (%04d)",
1020 : i);
1021 2048 : rec.length = strlen((char *)rec.data) + 1;
1022 :
1023 2048 : ret = ldb_kv->kv_ops->store(ldb_kv, key, rec, flags);
1024 2048 : assert_int_equal(ret, 0);
1025 :
1026 2048 : TALLOC_FREE(key.data);
1027 2048 : TALLOC_FREE(rec.data);
1028 : }
1029 :
1030 : /*
1031 : * Commit the transaction
1032 : */
1033 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1034 2 : 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 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1045 2 : assert_int_equal(ret, 0);
1046 :
1047 2 : ret = ldb_kv->kv_ops->iterate(ldb_kv, update_fn, context);
1048 2052 : for (i = 0; i < NUM_RECS; i++) {
1049 2048 : assert_int_equal(1, context->visits[i]);
1050 : }
1051 :
1052 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1053 2 : assert_int_equal(ret, 0);
1054 :
1055 2 : TALLOC_FREE(tmp_ctx);
1056 2 : }
1057 :
1058 : /*
1059 : * Ensure that writes are not visible until the transaction has been
1060 : * committed.
1061 : */
1062 2 : static void test_write_transaction_isolation(void **state)
1063 : {
1064 2 : int ret;
1065 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
1066 : struct test_ctx);
1067 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
1068 2 : struct ldb_val key;
1069 2 : struct ldb_val val;
1070 :
1071 2 : const char *KEY1 = "KEY01";
1072 2 : const char *VAL1 = "VALUE01";
1073 :
1074 2 : const char *KEY2 = "KEY02";
1075 2 : const char *VAL2 = "VALUE02";
1076 :
1077 : /*
1078 : * Pipes etc to coordinate the processes
1079 : */
1080 2 : int to_child[2];
1081 2 : int to_parent[2];
1082 2 : char buf[2];
1083 2 : pid_t pid, w_pid;
1084 2 : int wstatus;
1085 :
1086 2 : TALLOC_CTX *tmp_ctx;
1087 2 : tmp_ctx = talloc_new(test_ctx);
1088 2 : assert_non_null(tmp_ctx);
1089 :
1090 :
1091 : /*
1092 : * Add a record to the database
1093 : */
1094 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1095 2 : assert_int_equal(ret, 0);
1096 :
1097 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1098 2 : key.length = strlen(KEY1) + 1;
1099 :
1100 2 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL1);
1101 2 : val.length = strlen(VAL1) + 1;
1102 :
1103 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1104 2 : assert_int_equal(ret, 0);
1105 :
1106 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1107 2 : assert_int_equal(ret, 0);
1108 :
1109 :
1110 2 : ret = pipe(to_child);
1111 2 : assert_int_equal(ret, 0);
1112 2 : ret = pipe(to_parent);
1113 2 : assert_int_equal(ret, 0);
1114 : /*
1115 : * Now fork a new process
1116 : */
1117 :
1118 2 : pid = fork();
1119 4 : if (pid == 0) {
1120 :
1121 2 : struct ldb_context *ldb = NULL;
1122 2 : close(to_child[1]);
1123 2 : close(to_parent[0]);
1124 :
1125 : /*
1126 : * Wait for the transaction to start
1127 : */
1128 2 : ret = read(to_child[0], buf, 2);
1129 2 : if (ret != 2) {
1130 0 : print_error(__location__": read returned (%d)\n",
1131 : ret);
1132 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1133 : }
1134 2 : ldb = ldb_init(test_ctx, test_ctx->ev);
1135 2 : ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
1136 2 : if (ret != LDB_SUCCESS) {
1137 0 : print_error(__location__": ldb_connect returned (%d)\n",
1138 : ret);
1139 0 : exit(ret);
1140 : }
1141 :
1142 2 : ldb_kv = get_ldb_kv(ldb);
1143 :
1144 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1145 2 : 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 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1155 2 : key.length = strlen(KEY1) + 1;
1156 :
1157 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1158 2 : 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 2 : if ((strlen(VAL1) + 1) != val.length) {
1166 0 : print_error(__location__": KEY1 value lengths different"
1167 : ", expected (%d) actual(%d)\n",
1168 : (int)(strlen(VAL1) + 1), (int)val.length);
1169 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1170 : }
1171 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1180 2 : 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 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1190 2 : key.length = strlen(KEY2 + 1);
1191 :
1192 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1193 2 : if (ret != LDB_SUCCESS) {
1194 0 : print_error(__location__": lock_read returned (%d)\n",
1195 : ret);
1196 0 : exit(ret);
1197 : }
1198 :
1199 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1200 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1208 2 : 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 2 : ret = write(to_parent[1], "GO", 2);
1218 2 : 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 2 : ret = read(to_child[0], buf, 2);
1228 2 : 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 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1238 2 : if (ret != LDB_SUCCESS) {
1239 0 : print_error(__location__": unlock_read returned (%d)\n",
1240 : ret);
1241 0 : exit(ret);
1242 : }
1243 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1244 2 : key.length = strlen(KEY1) + 1;
1245 :
1246 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1247 2 : 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 2 : if ((strlen(VAL1) + 1) != val.length) {
1255 0 : print_error(__location__": KEY1 value lengths different"
1256 : ", expected (%d) actual(%d)\n",
1257 : (int)(strlen(VAL1) + 1), (int)val.length);
1258 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1259 : }
1260 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1269 2 : 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 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1280 2 : if (ret != LDB_SUCCESS) {
1281 0 : print_error(__location__": unlock_read returned (%d)\n",
1282 : ret);
1283 0 : exit(ret);
1284 : }
1285 :
1286 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1287 2 : key.length = strlen(KEY2) + 1;
1288 :
1289 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1290 2 : 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 2 : if ((strlen(VAL2) + 1) != val.length) {
1298 0 : print_error(__location__": KEY2 value lengths different"
1299 : ", expected (%d) actual(%d)\n",
1300 : (int)(strlen(VAL2) + 1), (int)val.length);
1301 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1302 : }
1303 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1312 2 : if (ret != LDB_SUCCESS) {
1313 0 : print_error(__location__": unlock_read returned (%d)\n",
1314 : ret);
1315 0 : exit(ret);
1316 : }
1317 :
1318 2 : exit(0);
1319 : }
1320 2 : close(to_child[0]);
1321 2 : 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 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1328 2 : assert_int_equal(ret, 0);
1329 :
1330 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1331 2 : key.length = strlen(KEY2) + 1;
1332 :
1333 2 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL2);
1334 2 : val.length = strlen(VAL2) + 1;
1335 :
1336 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1337 2 : assert_int_equal(ret, 0);
1338 :
1339 : /*
1340 : * Signal the child process
1341 : */
1342 2 : ret = write(to_child[1], "GO", 2);
1343 2 : 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 2 : ret = read(to_parent[0], buf, 2);
1350 2 : assert_int_equal(2, ret);
1351 :
1352 : /*
1353 : * commit the transaction
1354 : */
1355 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1356 2 : assert_int_equal(0, ret);
1357 :
1358 : /*
1359 : * Signal the child process
1360 : */
1361 2 : ret = write(to_child[1], "GO", 2);
1362 2 : assert_int_equal(2, ret);
1363 :
1364 2 : w_pid = waitpid(pid, &wstatus, 0);
1365 2 : assert_int_equal(pid, w_pid);
1366 :
1367 2 : assert_true(WIFEXITED(wstatus));
1368 :
1369 2 : assert_int_equal(WEXITSTATUS(wstatus), 0);
1370 :
1371 :
1372 2 : TALLOC_FREE(tmp_ctx);
1373 2 : }
1374 :
1375 : /*
1376 : * Ensure that deletes are not visible until the transaction has been
1377 : * committed.
1378 : */
1379 2 : static void test_delete_transaction_isolation(void **state)
1380 : {
1381 2 : int ret;
1382 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
1383 : struct test_ctx);
1384 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
1385 2 : struct ldb_val key;
1386 2 : struct ldb_val val;
1387 :
1388 2 : const char *KEY1 = "KEY01";
1389 2 : const char *VAL1 = "VALUE01";
1390 :
1391 2 : const char *KEY2 = "KEY02";
1392 2 : const char *VAL2 = "VALUE02";
1393 :
1394 : /*
1395 : * Pipes etc to coordinate the processes
1396 : */
1397 2 : int to_child[2];
1398 2 : int to_parent[2];
1399 2 : char buf[2];
1400 2 : pid_t pid, w_pid;
1401 2 : int wstatus;
1402 :
1403 2 : TALLOC_CTX *tmp_ctx;
1404 2 : tmp_ctx = talloc_new(test_ctx);
1405 2 : assert_non_null(tmp_ctx);
1406 :
1407 :
1408 : /*
1409 : * Add records to the database
1410 : */
1411 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1412 2 : assert_int_equal(ret, 0);
1413 :
1414 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1415 2 : key.length = strlen(KEY1) + 1;
1416 :
1417 2 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL1);
1418 2 : val.length = strlen(VAL1) + 1;
1419 :
1420 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1421 2 : assert_int_equal(ret, 0);
1422 :
1423 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1424 2 : key.length = strlen(KEY2) + 1;
1425 :
1426 2 : val.data = (uint8_t *)talloc_strdup(tmp_ctx, VAL2);
1427 2 : val.length = strlen(VAL2) + 1;
1428 :
1429 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, val, 0);
1430 2 : assert_int_equal(ret, 0);
1431 :
1432 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1433 2 : assert_int_equal(ret, 0);
1434 :
1435 :
1436 2 : ret = pipe(to_child);
1437 2 : assert_int_equal(ret, 0);
1438 2 : ret = pipe(to_parent);
1439 2 : assert_int_equal(ret, 0);
1440 : /*
1441 : * Now fork a new process
1442 : */
1443 :
1444 2 : pid = fork();
1445 4 : if (pid == 0) {
1446 :
1447 2 : struct ldb_context *ldb = NULL;
1448 2 : close(to_child[1]);
1449 2 : close(to_parent[0]);
1450 :
1451 : /*
1452 : * Wait for the transaction to be started
1453 : */
1454 2 : ret = read(to_child[0], buf, 2);
1455 2 : if (ret != 2) {
1456 0 : print_error(__location__": read returned (%d)\n",
1457 : ret);
1458 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1459 : }
1460 :
1461 2 : ldb = ldb_init(test_ctx, test_ctx->ev);
1462 2 : ret = ldb_connect(ldb, test_ctx->dbpath, 0, NULL);
1463 2 : if (ret != LDB_SUCCESS) {
1464 0 : print_error(__location__": ldb_connect returned (%d)\n",
1465 : ret);
1466 0 : exit(ret);
1467 : }
1468 :
1469 2 : ldb_kv = get_ldb_kv(ldb);
1470 :
1471 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1472 2 : 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 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1482 2 : key.length = strlen(KEY1) + 1;
1483 :
1484 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1485 2 : 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 2 : if ((strlen(VAL1) + 1) != val.length) {
1493 0 : print_error(__location__": KEY1 value lengths different"
1494 : ", expected (%d) actual(%d)\n",
1495 : (int)(strlen(VAL1) + 1), (int)val.length);
1496 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1497 : }
1498 2 : 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 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1511 2 : key.length = strlen(KEY2) + 1;
1512 :
1513 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1514 2 : 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 2 : if ((strlen(VAL2) + 1) != val.length) {
1522 0 : print_error(__location__": KEY2 value lengths different"
1523 : ", expected (%d) actual(%d)\n",
1524 : (int)(strlen(VAL2) + 1), (int)val.length);
1525 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1526 : }
1527 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1536 2 : 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 2 : ret = write(to_parent[1], "GO", 2);
1546 2 : 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 2 : ret = read(to_child[0], buf, 2);
1556 2 : 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 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1566 2 : if (ret != LDB_SUCCESS) {
1567 0 : print_error(__location__": unlock_read returned (%d)\n",
1568 : ret);
1569 0 : exit(ret);
1570 : }
1571 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY1);
1572 2 : key.length = strlen(KEY1) + 1;
1573 :
1574 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1575 2 : 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 2 : if ((strlen(VAL1) + 1) != val.length) {
1583 0 : print_error(__location__": KEY1 value lengths different"
1584 : ", expected (%d) actual(%d)\n",
1585 : (int)(strlen(VAL1) + 1), (int)val.length);
1586 0 : exit(LDB_ERR_OPERATIONS_ERROR);
1587 : }
1588 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1596 2 : 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 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1606 2 : key.length = strlen(KEY2 + 1);
1607 :
1608 2 : ret = ldb_kv->kv_ops->lock_read(ldb->modules);
1609 2 : if (ret != LDB_SUCCESS) {
1610 0 : print_error(__location__": lock_read returned (%d)\n",
1611 : ret);
1612 0 : exit(ret);
1613 : }
1614 :
1615 2 : ret = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key, parse, &val);
1616 2 : 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 2 : ret = ldb_kv->kv_ops->unlock_read(ldb->modules);
1624 2 : if (ret != LDB_SUCCESS) {
1625 0 : print_error(__location__": unlock_read returned (%d)\n",
1626 : ret);
1627 0 : exit(ret);
1628 : }
1629 2 : TALLOC_FREE(tmp_ctx);
1630 2 : exit(0);
1631 : }
1632 2 : close(to_child[0]);
1633 2 : 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 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1640 2 : assert_int_equal(ret, 0);
1641 :
1642 2 : key.data = (uint8_t *)talloc_strdup(tmp_ctx, KEY2);
1643 2 : key.length = strlen(KEY2) + 1;
1644 :
1645 2 : ret = ldb_kv->kv_ops->delete (ldb_kv, key);
1646 2 : assert_int_equal(ret, 0);
1647 : /*
1648 : * Signal the child process
1649 : */
1650 2 : ret = write(to_child[1], "GO", 2);
1651 2 : 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 2 : ret = read(to_parent[0], buf, 2);
1658 2 : assert_int_equal(2, ret);
1659 :
1660 : /*
1661 : * commit the transaction
1662 : */
1663 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1664 2 : assert_int_equal(0, ret);
1665 :
1666 : /*
1667 : * Signal the child process
1668 : */
1669 2 : ret = write(to_child[1], "GO", 2);
1670 2 : assert_int_equal(2, ret);
1671 :
1672 2 : w_pid = waitpid(pid, &wstatus, 0);
1673 2 : assert_int_equal(pid, w_pid);
1674 :
1675 2 : assert_true(WIFEXITED(wstatus));
1676 :
1677 2 : assert_int_equal(WEXITSTATUS(wstatus), 0);
1678 :
1679 :
1680 2 : TALLOC_FREE(tmp_ctx);
1681 2 : }
1682 :
1683 :
1684 : /*
1685 : * Test that get_size returns a sensible estimate of the number of records
1686 : * in the database.
1687 : */
1688 2 : static void test_get_size(void **state)
1689 : {
1690 2 : int ret;
1691 2 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
1692 : struct test_ctx);
1693 2 : struct ldb_kv_private *ldb_kv = get_ldb_kv(test_ctx->ldb);
1694 2 : uint8_t key_val[] = "TheKey";
1695 2 : struct ldb_val key = {
1696 : .data = key_val,
1697 : .length = sizeof(key_val)
1698 : };
1699 :
1700 2 : uint8_t value[] = "The record contents";
1701 2 : struct ldb_val data = {
1702 : .data = value,
1703 : .length = sizeof(value)
1704 : };
1705 2 : size_t size = 0;
1706 :
1707 2 : int flags = 0;
1708 2 : TALLOC_CTX *tmp_ctx;
1709 :
1710 2 : tmp_ctx = talloc_new(test_ctx);
1711 2 : assert_non_null(tmp_ctx);
1712 :
1713 2 : size = ldb_kv->kv_ops->get_size(ldb_kv);
1714 : #if defined(TEST_LMDB)
1715 1 : 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 2 : ret = ldb_kv->kv_ops->begin_write(ldb_kv);
1731 2 : assert_int_equal(ret, 0);
1732 :
1733 : /*
1734 : * Write the record
1735 : */
1736 2 : ret = ldb_kv->kv_ops->store(ldb_kv, key, data, flags);
1737 2 : assert_int_equal(ret, 0);
1738 :
1739 : /*
1740 : * Commit the transaction
1741 : */
1742 2 : ret = ldb_kv->kv_ops->finish_write(ldb_kv);
1743 2 : assert_int_equal(ret, 0);
1744 :
1745 2 : size = ldb_kv->kv_ops->get_size(ldb_kv);
1746 : #ifdef TEST_LMDB
1747 1 : 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 2 : talloc_free(tmp_ctx);
1759 2 : }
1760 :
1761 2 : int main(int argc, const char **argv)
1762 : {
1763 2 : 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 2 : cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
1819 :
1820 2 : return cmocka_run_group_tests(tests, NULL, NULL);
1821 : }
|