test_sync_db.c (36229B)
1 /* 2 This file is part of TALER 3 (C) 2019 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Lesser General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file syncdb/test_sync_db.c 18 * @brief testcase for sync postgres db 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include <gnunet/gnunet_util_lib.h> 23 #include <taler/taler_util.h> 24 #include "sync/sync_service.h" 25 #include "sync/sync_database_lib.h" 26 #include "sync/sync_util.h" 27 28 29 #define FAILIF(cond) \ 30 do { \ 31 if (! (cond)) { break;} \ 32 GNUNET_break (0); \ 33 goto drop; \ 34 } while (0) 35 36 #define RND_BLK(ptr) \ 37 GNUNET_CRYPTO_random_block (ptr, sizeof (*ptr)) 38 39 /** 40 * Global return value for the test. Initially #EXIT_FAILURE, set to 41 * 0 upon completion. Other values indicate some kind of error. 42 */ 43 static int result; 44 45 46 /** 47 * Function called on all pending payments for an account. 48 * 49 * @param cls closure 50 * @param timestamp for how long have we been waiting 51 * @param order_id order id in the backend 52 * @param token claim token, or NULL for none 53 * @param amount how much is the order for 54 */ 55 static void 56 payment_it (void *cls, 57 struct GNUNET_TIME_Timestamp timestamp, 58 const char *order_id, 59 const struct TALER_ClaimTokenP *token, 60 const struct TALER_Amount *amount) 61 { 62 (void) timestamp; 63 (void) token; 64 (void) amount; 65 GNUNET_assert (NULL == cls); 66 GNUNET_assert (0 == strcmp (order_id, 67 "fake-order-2")); 68 } 69 70 71 /** 72 * Iterator used by the #SYNCDB_lookup_block_range_TR() tests, 73 * simply counts the blocks it is called with. 74 * 75 * @param cls an `int *` counter to increment 76 * @param nonce block nonce 77 * @param block_hash hash of the block data 78 * @param prev_nonce previous block nonce (NULL if first) 79 * @param next_nonce next block nonce (NULL if last) 80 * @param data_size size of @a data 81 * @param data encrypted block contents 82 * @param upload_sig signature stored with the block 83 * @param old_hash hash of the replaced block data 84 * @param refs_hash hash over the object references 85 */ 86 static void 87 block_it (void *cls, 88 const struct SYNC_BlockNonce *nonce, 89 const struct GNUNET_HashCode *block_hash, 90 const struct SYNC_BlockNonce *prev_nonce, 91 const struct SYNC_BlockNonce *next_nonce, 92 size_t data_size, 93 const void *data, 94 const struct SYNC_AccountSignatureP *upload_sig, 95 const struct GNUNET_HashCode *old_hash, 96 const struct GNUNET_HashCode *refs_hash) 97 { 98 (void) upload_sig; 99 (void) old_hash; 100 (void) refs_hash; 101 int *cnt = cls; 102 103 (void) nonce; 104 (void) block_hash; 105 (void) prev_nonce; 106 (void) next_nonce; 107 (void) data_size; 108 (void) data; 109 (*cnt)++; 110 } 111 112 113 /** 114 * Iterator used by the #SYNCDB_lookup_block_hashes_TR() tests, 115 * collecting the block identities it is called with. 116 */ 117 struct HashCollector 118 { 119 /** 120 * Nonces collected so far. 121 */ 122 struct SYNC_BlockNonce nonces[8]; 123 124 /** 125 * Hashes collected so far. 126 */ 127 struct GNUNET_HashCode hashes[8]; 128 129 /** 130 * Number of entries collected. 131 */ 132 unsigned int count; 133 }; 134 135 136 /** 137 * Collect the block identities the iterator is called with. 138 * 139 * @param cls a `struct HashCollector *` 140 * @param nonce nonce identifying the block 141 * @param block_hash hash of the block data 142 */ 143 static void 144 hash_it (void *cls, 145 const struct SYNC_BlockNonce *nonce, 146 const struct GNUNET_HashCode *block_hash) 147 { 148 struct HashCollector *hc = cls; 149 150 GNUNET_assert (hc->count < 8); 151 hc->nonces[hc->count] = *nonce; 152 hc->hashes[hc->count] = *block_hash; 153 hc->count++; 154 } 155 156 157 /** 158 * Create a paid account, so that the SQL entry points do not reject 159 * it with #SYNC_DB_PAYMENT_REQUIRED. 160 * 161 * @param account_pub account to activate 162 * @param order_id (unique) order ID to use for the fake payment 163 * @return #GNUNET_OK on success 164 */ 165 static enum GNUNET_GenericReturnValue 166 activate_account (const struct SYNC_AccountPublicKeyP *account_pub, 167 const char *order_id) 168 { 169 struct TALER_Amount amount; 170 struct TALER_ClaimTokenP token; 171 172 memset (&token, 3, sizeof (token)); 173 if (GNUNET_OK != 174 TALER_string_to_amount ("EUR:1", 175 &amount)) 176 { 177 GNUNET_break (0); 178 return GNUNET_SYSERR; 179 } 180 if (SYNC_DB_ONE_RESULT != 181 SYNCDB_store_payment_TR (account_pub, 182 order_id, 183 &token, 184 &amount, 185 GNUNET_TIME_UNIT_MINUTES)) 186 { 187 GNUNET_break (0); 188 return GNUNET_SYSERR; 189 } 190 if (SYNC_DB_ONE_RESULT != 191 SYNCDB_increment_lifetime_TR (account_pub, 192 order_id, 193 GNUNET_TIME_UNIT_MINUTES)) 194 { 195 GNUNET_break (0); 196 return GNUNET_SYSERR; 197 } 198 return GNUNET_OK; 199 } 200 201 202 /** 203 * Count the blocks currently stored for @a account_pub. 204 * 205 * @param account_pub account to count blocks of 206 * @return number of blocks found 207 */ 208 static int 209 count_blocks (const struct SYNC_AccountPublicKeyP *account_pub) 210 { 211 int got = 0; 212 213 SYNCDB_lookup_block_range_TR (account_pub, 214 NULL, 215 100, 216 &block_it, 217 &got); 218 return got; 219 } 220 221 222 /** 223 * Main function that will be run by the scheduler. 224 * 225 * @param cls closure with config 226 */ 227 static void 228 run (void *cls) 229 { 230 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 231 struct TALER_Amount amount; 232 struct SYNC_AccountPublicKeyP account_pub; 233 struct GNUNET_HashCode h; 234 struct GNUNET_HashCode h2; 235 struct GNUNET_TIME_Absolute ts; 236 struct TALER_ClaimTokenP token; 237 /* P1: fake signature/refs for the DB-level tests (the procedures 238 store, they do not verify) */ 239 struct SYNC_AccountSignatureP fake_sig; 240 struct GNUNET_HashCode empty_refs; 241 242 memset (&fake_sig, 7, sizeof (fake_sig)); 243 GNUNET_CRYPTO_hash ("", 0, &empty_refs); 244 245 if (GNUNET_OK != 246 SYNCDB_init_admin (cfg)) 247 { 248 result = 77; 249 return; 250 } 251 if (GNUNET_OK != 252 SYNCDB_drop_tables ()) 253 { 254 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 255 "Dropping tables failed\n"); 256 } 257 if (GNUNET_OK != 258 SYNCDB_create_tables ()) 259 { 260 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 261 "Creating tables failed\n"); 262 } 263 GNUNET_assert (GNUNET_OK == 264 SYNCDB_preflight ()); 265 memset (&account_pub, 1, sizeof (account_pub)); 266 memset (&token, 3, sizeof (token)); 267 GNUNET_CRYPTO_hash ("data", 4, &h); 268 GNUNET_CRYPTO_hash ("DATA", 4, &h2); 269 GNUNET_assert (GNUNET_OK == 270 TALER_string_to_amount ("EUR:1", 271 &amount)); 272 FAILIF (SYNC_DB_ONE_RESULT != 273 SYNCDB_store_payment_TR ( 274 &account_pub, 275 "fake-order", 276 &token, 277 &amount, 278 GNUNET_TIME_UNIT_MINUTES)); 279 FAILIF (SYNC_DB_ONE_RESULT != 280 SYNCDB_increment_lifetime_TR ( 281 &account_pub, 282 "fake-order", 283 GNUNET_TIME_UNIT_MINUTES)); 284 285 FAILIF (0 != 286 SYNCDB_lookup_pending_payments_by_account_TR ( 287 &account_pub, 288 &payment_it, 289 NULL)); 290 memset (&account_pub, 2, sizeof (account_pub)); 291 FAILIF (SYNC_DB_ONE_RESULT != 292 SYNCDB_store_payment_TR ( 293 &account_pub, 294 "fake-order-2", 295 &token, 296 &amount, 297 GNUNET_TIME_UNIT_MINUTES)); 298 FAILIF (1 != 299 SYNCDB_lookup_pending_payments_by_account_TR ( 300 &account_pub, 301 &payment_it, 302 NULL)); 303 FAILIF (SYNC_DB_ONE_RESULT != 304 SYNCDB_increment_lifetime_TR ( 305 &account_pub, 306 "fake-order-2", 307 GNUNET_TIME_UNIT_MINUTES)); 308 /* --- DLL tests: append three blocks A->B->C and validate lookup --- */ 309 { 310 struct SYNC_BlockNonce nA; 311 struct SYNC_BlockNonce nB; 312 struct SYNC_BlockNonce nC; 313 struct GNUNET_HashCode hA; 314 struct GNUNET_HashCode hB; 315 struct GNUNET_HashCode hC; 316 char dataA[] = "A"; 317 char dataB[] = "B"; 318 char dataC[] = "C"; 319 int got; 320 321 RND_BLK (&nA); 322 RND_BLK (&nB); 323 RND_BLK (&nC); 324 GNUNET_CRYPTO_hash (dataA, sizeof dataA - 1, &hA); 325 GNUNET_CRYPTO_hash (dataB, sizeof dataB - 1, &hB); 326 GNUNET_CRYPTO_hash (dataC, sizeof dataC - 1, &hC); 327 328 /* Append A (prev NULL) */ 329 FAILIF (SYNC_DB_ONE_RESULT != 330 SYNCDB_append_block_TR ( 331 &account_pub, 332 &nA, 333 NULL, 334 &hA, 335 sizeof dataA - 1, 336 dataA, 337 0, 338 NULL, 339 NULL, 340 &fake_sig, 341 &empty_refs, 342 NULL, 343 NULL, 344 NULL)); 345 346 347 /* Append B (prev A) */ 348 FAILIF (SYNC_DB_ONE_RESULT != 349 SYNCDB_append_block_TR ( 350 &account_pub, 351 &nB, 352 &nA, 353 &hB, 354 sizeof dataB - 1, 355 dataB, 356 0, 357 NULL, 358 NULL, 359 &fake_sig, 360 &empty_refs, 361 &fake_sig, 362 &hA, 363 NULL)); 364 365 366 /* Append C (prev B) */ 367 FAILIF (SYNC_DB_ONE_RESULT != 368 SYNCDB_append_block_TR ( 369 &account_pub, 370 &nC, 371 &nB, 372 &hC, 373 sizeof dataC - 1, 374 dataC, 375 0, 376 NULL, 377 NULL, 378 &fake_sig, 379 &empty_refs, 380 &fake_sig, 381 &hB, 382 &nA)); 383 384 /* Verify lookup returns 3 blocks */ 385 got = 0; 386 FAILIF (3 != 387 SYNCDB_lookup_block_range_TR ( 388 &account_pub, 389 &nA, 390 10, 391 &block_it, 392 &got)); 393 FAILIF (got != 3); 394 395 /* The relink signature covers the neighbour's other link, so an 396 append whose view of it went stale must be refused rather than 397 stored (the caller reads the neighbour outside the transaction) */ 398 { 399 struct SYNC_BlockNonce nS; 400 struct GNUNET_HashCode hS; 401 char dataS[] = "S"; 402 403 RND_BLK (&nS); 404 GNUNET_CRYPTO_hash (dataS, sizeof dataS - 1, &hS); 405 FAILIF (SYNC_DB_OUTDATED_WRITE != 406 SYNCDB_append_block_TR ( 407 &account_pub, 408 &nS, 409 &nC, 410 &hS, 411 sizeof dataS - 1, 412 dataS, 413 0, 414 NULL, 415 NULL, 416 &fake_sig, 417 &empty_refs, 418 &fake_sig, 419 &hC, 420 /* C's predecessor is B, not A */ &nA)); 421 FAILIF (3 != count_blocks (&account_pub)); 422 } 423 424 /* Delete middle block B (use its prev and next) */ 425 FAILIF (SYNC_DB_ONE_RESULT != 426 SYNCDB_delete_block_TR ( 427 &account_pub, 428 &nB, 429 &nA, 430 &nC, 431 &hB, 432 0, 433 NULL, 434 NULL, 435 &fake_sig, 436 &hA, 437 NULL, 438 &fake_sig, 439 &hC, 440 NULL)); 441 442 /* Update block C (test update path) */ 443 { 444 struct GNUNET_HashCode newC; 445 char newDataC[] = "C-new"; 446 447 GNUNET_CRYPTO_hash (newDataC, sizeof newDataC - 1, &newC); 448 FAILIF (SYNC_DB_ONE_RESULT != 449 SYNCDB_update_block_TR ( 450 &account_pub, 451 &nC, 452 /* prev */ &nA, 453 /* next */ NULL, 454 &hC, 455 &newC, 456 sizeof newDataC - 1, 457 newDataC, 458 0, 459 NULL, 460 NULL, 461 &fake_sig, 462 &empty_refs)); 463 hC = newC; 464 } 465 466 /* --- Outdated-write tests --- */ 467 { 468 struct SYNC_BlockNonce nD; 469 struct GNUNET_HashCode hD; 470 char dataD[] = "D"; 471 struct GNUNET_HashCode bogus_old; 472 char newDataC2[] = "C-newer"; 473 struct GNUNET_HashCode newC2; 474 475 RND_BLK (&nD); 476 GNUNET_CRYPTO_hash (dataD, sizeof dataD - 1, &hD); 477 478 /* Appending with NULL prev when backup is non-empty should be outdated */ 479 FAILIF (SYNC_DB_OUTDATED_WRITE != 480 SYNCDB_append_block_TR ( 481 &account_pub, 482 &nD, 483 /* prev */ NULL, 484 &hD, 485 sizeof dataD - 1, 486 dataD, 487 0, 488 NULL, 489 NULL, 490 &fake_sig, 491 &empty_refs, 492 NULL, 493 NULL, 494 NULL)); 495 496 /* Updating C with wrong old-data-hash should be outdated */ 497 GNUNET_CRYPTO_hash ("bogus", 5, &bogus_old); 498 GNUNET_CRYPTO_hash (newDataC2, sizeof newDataC2 - 1, &newC2); 499 FAILIF (SYNC_DB_OUTDATED_WRITE != 500 SYNCDB_update_block_TR ( 501 &account_pub, 502 &nC, 503 /* prev */ &nA, 504 /* next */ NULL, 505 &bogus_old, 506 &newC2, 507 sizeof newDataC2 - 1, 508 newDataC2, 509 0, 510 NULL, 511 NULL, 512 &fake_sig, 513 &empty_refs)); 514 515 /* Deleting C with wrong prev nonce should be outdated */ 516 FAILIF (SYNC_DB_OUTDATED_WRITE != 517 SYNCDB_delete_block_TR ( 518 &account_pub, 519 &nC, 520 /* prev (wrong) */ &nB, 521 /* next */ NULL, 522 &hC, 523 0, 524 NULL, 525 NULL, 526 NULL, 527 NULL, 528 NULL, 529 NULL, 530 NULL, 531 NULL)); 532 } 533 534 /* --- Block hash lookup (reconcile) tests --- */ 535 { 536 struct SYNC_AccountPublicKeyP unknown; 537 struct SYNC_AccountPublicKeyP lone; 538 struct SYNC_BlockNonce lone_nonce; 539 struct GNUNET_HashCode lone_hash; 540 char lone_data[] = "lone-block"; 541 struct HashCollector hc; 542 543 /* An account nobody has heard of demands payment */ 544 memset (&unknown, 9, sizeof (unknown)); 545 FAILIF (SYNC_DB_PAYMENT_REQUIRED != 546 SYNCDB_lookup_block_hashes_TR (&unknown, 547 NULL, 548 NULL)); 549 550 /* A fresh, paid account with a single block delivers exactly 551 that block's hash */ 552 memset (&lone, 16, sizeof (lone)); 553 FAILIF (GNUNET_OK != 554 activate_account (&lone, 555 "fake-order-hashes-lone")); 556 RND_BLK (&lone_nonce); 557 GNUNET_CRYPTO_hash (lone_data, 558 sizeof lone_data - 1, 559 &lone_hash); 560 FAILIF (SYNC_DB_ONE_RESULT != 561 SYNCDB_append_block_TR (&lone, 562 &lone_nonce, 563 NULL, 564 &lone_hash, 565 sizeof lone_data - 1, 566 lone_data, 567 0, 568 NULL, 569 NULL, 570 &fake_sig, 571 &empty_refs, 572 NULL, 573 NULL, 574 NULL)); 575 memset (&hc, 0, sizeof (hc)); 576 FAILIF (1 != 577 SYNCDB_lookup_block_hashes_TR (&lone, 578 &hash_it, 579 &hc)); 580 FAILIF (1 != hc.count); 581 FAILIF (0 != GNUNET_memcmp (&hc.hashes[0], 582 &lone_hash)); 583 FAILIF (0 != GNUNET_memcmp (&hc.nonces[0], 584 &lone_nonce)); 585 586 /* Counting pass with a NULL iterator */ 587 FAILIF (1 != 588 SYNCDB_lookup_block_hashes_TR (&lone, 589 NULL, 590 NULL)); 591 592 /* The DLL account now holds blocks A and C (B was deleted, C 593 was updated), whose identities must both be delivered */ 594 memset (&hc, 0, sizeof (hc)); 595 FAILIF (2 != 596 SYNCDB_lookup_block_hashes_TR (&account_pub, 597 &hash_it, 598 &hc)); 599 FAILIF (2 != hc.count); 600 { 601 bool have_a = false; 602 bool have_c = false; 603 604 for (unsigned int i = 0; i < hc.count; i++) 605 { 606 if (0 == GNUNET_memcmp (&hc.hashes[i], 607 &hA)) 608 have_a = true; 609 if (0 == GNUNET_memcmp (&hc.hashes[i], 610 &hC)) 611 have_c = true; 612 } 613 FAILIF (! have_a); 614 FAILIF (! have_c); 615 } 616 } 617 } 618 619 /* --- Account status lookup --- */ 620 { 621 struct SYNC_AccountPublicKeyP acc; 622 struct SYNC_BlockNonce nonce; 623 struct GNUNET_HashCode bh; 624 char data[] = "account-status-block"; 625 struct GNUNET_TIME_Timestamp expiration; 626 uint64_t storage_used_bytes; 627 uint64_t block_count; 628 629 memset (&acc, 20, sizeof (acc)); 630 631 /* An account nobody has heard of is missing, not expired */ 632 FAILIF (SYNC_DB_TARGET_MISSING != 633 SYNCDB_lookup_account_TR (&acc, 634 &expiration, 635 &storage_used_bytes, 636 &block_count)); 637 638 FAILIF (GNUNET_OK != 639 activate_account (&acc, 640 "fake-order-account-status")); 641 642 /* A fresh account has an expiration and no storage in use */ 643 FAILIF (SYNC_DB_ONE_RESULT != 644 SYNCDB_lookup_account_TR (&acc, 645 &expiration, 646 &storage_used_bytes, 647 &block_count)); 648 FAILIF (GNUNET_TIME_absolute_is_zero (expiration.abs_time)); 649 FAILIF (0 != storage_used_bytes); 650 FAILIF (0 != block_count); 651 652 /* ... and the block it stores is reflected in both counters */ 653 RND_BLK (&nonce); 654 GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh); 655 FAILIF (SYNC_DB_ONE_RESULT != 656 SYNCDB_append_block_TR (&acc, 657 &nonce, 658 NULL, 659 &bh, 660 sizeof data - 1, 661 data, 662 0, 663 NULL, 664 NULL, 665 &fake_sig, 666 &empty_refs, 667 NULL, 668 NULL, 669 NULL)); 670 FAILIF (SYNC_DB_ONE_RESULT != 671 SYNCDB_lookup_account_TR (&acc, 672 &expiration, 673 &storage_used_bytes, 674 &block_count)); 675 FAILIF (sizeof data - 1 != storage_used_bytes); 676 FAILIF (1 != block_count); 677 678 /* The blocks of other accounts must not be counted here */ 679 FAILIF (SYNC_DB_ONE_RESULT != 680 SYNCDB_lookup_account_TR (&account_pub, 681 &expiration, 682 &storage_used_bytes, 683 &block_count)); 684 FAILIF (1 == block_count); 685 } 686 687 /* --- Object store/lookup tests --- */ 688 { 689 struct SYNC_ObjectUID obj_uid; 690 struct GNUNET_HashCode obj_hash; 691 char obj_data[] = "objdata"; 692 int64_t refcount = 0; 693 struct GNUNET_TIME_Timestamp exp; 694 size_t data_sz = 0; 695 696 RND_BLK (&obj_uid); 697 GNUNET_CRYPTO_hash (obj_data, sizeof obj_data - 1, &obj_hash); 698 FAILIF (SYNC_DB_ONE_RESULT != 699 SYNCDB_store_object_TR ( 700 &obj_uid, 701 &account_pub, 702 &obj_hash, 703 GNUNET_TIME_UNIT_DAYS, 704 sizeof obj_data - 1, 705 obj_data)); 706 707 FAILIF (SYNC_DB_ONE_RESULT != 708 SYNCDB_lookup_object ( 709 &account_pub, 710 &obj_hash, 711 &refcount, 712 &exp, 713 &data_sz, 714 NULL)); 715 FAILIF (refcount < 0); 716 717 /* A missing object is a normal outcome, not a failure */ 718 { 719 struct GNUNET_HashCode bogus_hash; 720 721 GNUNET_CRYPTO_hash ("no-such-object", 722 14, 723 &bogus_hash); 724 FAILIF (SYNC_DB_NO_RESULTS != 725 SYNCDB_lookup_object (&account_pub, 726 &bogus_hash, 727 &refcount, 728 &exp, 729 &data_sz, 730 NULL)); 731 } 732 } 733 734 /* --- Referencing an object that was never uploaded --- */ 735 { 736 struct SYNC_AccountPublicKeyP acc; 737 struct SYNC_BlockNonce nonce; 738 struct GNUNET_HashCode bh; 739 struct SYNC_ObjectUID unknown_uid; 740 const int16_t inc = 1; 741 char data[] = "orphan"; 742 743 memset (&acc, 10, sizeof (acc)); 744 FAILIF (GNUNET_OK != 745 activate_account (&acc, 746 "fake-order-refs-missing")); 747 RND_BLK (&nonce); 748 RND_BLK (&unknown_uid); 749 GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh); 750 FAILIF (SYNC_DB_INCONSISTENT_BACKUP != 751 SYNCDB_append_block_TR (&acc, 752 &nonce, 753 NULL, 754 &bh, 755 sizeof data - 1, 756 data, 757 1, 758 &unknown_uid, 759 &inc, 760 &fake_sig, 761 &empty_refs, 762 NULL, 763 NULL, 764 NULL)); 765 /* the rejected append must be a no-op */ 766 FAILIF (0 != count_blocks (&acc)); 767 } 768 769 /* --- A nonce that is already taken is a conflict --- */ 770 { 771 struct SYNC_AccountPublicKeyP acc_a; 772 struct SYNC_AccountPublicKeyP acc_b; 773 struct SYNC_BlockNonce nonce; 774 struct GNUNET_HashCode bh; 775 char data[] = "shared-nonce"; 776 777 memset (&acc_a, 11, sizeof (acc_a)); 778 memset (&acc_b, 12, sizeof (acc_b)); 779 FAILIF (GNUNET_OK != 780 activate_account (&acc_a, 781 "fake-order-nonce-a")); 782 FAILIF (GNUNET_OK != 783 activate_account (&acc_b, 784 "fake-order-nonce-b")); 785 RND_BLK (&nonce); 786 GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh); 787 FAILIF (SYNC_DB_ONE_RESULT != 788 SYNCDB_append_block_TR (&acc_a, 789 &nonce, 790 NULL, 791 &bh, 792 sizeof data - 1, 793 data, 794 0, 795 NULL, 796 NULL, 797 &fake_sig, 798 &empty_refs, 799 NULL, 800 NULL, 801 NULL)); 802 FAILIF (SYNC_DB_OUTDATED_WRITE != 803 SYNCDB_append_block_TR (&acc_b, 804 &nonce, 805 NULL, 806 &bh, 807 sizeof data - 1, 808 data, 809 0, 810 NULL, 811 NULL, 812 &fake_sig, 813 &empty_refs, 814 NULL, 815 NULL, 816 NULL)); 817 /* the rejected append must not have touched account B */ 818 FAILIF (0 != count_blocks (&acc_b)); 819 } 820 821 /* --- Refcount lifecycle --- */ 822 { 823 struct SYNC_AccountPublicKeyP acc; 824 struct SYNC_BlockNonce nonce; 825 struct GNUNET_HashCode bh; 826 struct SYNC_ObjectUID uid; 827 struct GNUNET_HashCode oh; 828 const int16_t inc = 1; 829 const int16_t dec = -1; 830 const int16_t dec2 = -2; 831 char data[] = "refcounted"; 832 char obj[] = "payload"; 833 int64_t refcount = 0; 834 struct GNUNET_TIME_Timestamp exp; 835 size_t data_sz = 0; 836 837 memset (&acc, 13, sizeof (acc)); 838 FAILIF (GNUNET_OK != 839 activate_account (&acc, 840 "fake-order-refcount")); 841 RND_BLK (&nonce); 842 RND_BLK (&uid); 843 GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh); 844 GNUNET_CRYPTO_hash (obj, sizeof obj - 1, &oh); 845 FAILIF (SYNC_DB_ONE_RESULT != 846 SYNCDB_store_object_TR (&uid, 847 &acc, 848 &oh, 849 GNUNET_TIME_UNIT_DAYS, 850 sizeof obj - 1, 851 obj)); 852 /* re-uploading the same UID is idempotent, not an error */ 853 FAILIF (SYNC_DB_ONE_RESULT != 854 SYNCDB_store_object_TR (&uid, 855 &acc, 856 &oh, 857 GNUNET_TIME_UNIT_DAYS, 858 sizeof obj - 1, 859 obj)); 860 FAILIF (SYNC_DB_ONE_RESULT != 861 SYNCDB_append_block_TR (&acc, 862 &nonce, 863 NULL, 864 &bh, 865 sizeof data - 1, 866 data, 867 1, 868 &uid, 869 &inc, 870 &fake_sig, 871 &empty_refs, 872 NULL, 873 NULL, 874 NULL)); 875 FAILIF (SYNC_DB_ONE_RESULT != 876 SYNCDB_lookup_object (&acc, 877 &oh, 878 &refcount, 879 &exp, 880 &data_sz, 881 NULL)); 882 FAILIF (1 != refcount); 883 884 /* decrementing below zero is refused, refcount untouched */ 885 FAILIF (SYNC_DB_INCONSISTENT_BACKUP != 886 SYNCDB_delete_block_TR (&acc, 887 &nonce, 888 NULL, 889 NULL, 890 &bh, 891 1, 892 &uid, 893 &dec2, 894 NULL, 895 NULL, 896 NULL, 897 NULL, 898 NULL, 899 NULL)); 900 FAILIF (SYNC_DB_ONE_RESULT != 901 SYNCDB_lookup_object (&acc, 902 &oh, 903 &refcount, 904 &exp, 905 &data_sz, 906 NULL)); 907 FAILIF (1 != refcount); 908 /* ... and the block must still be there */ 909 FAILIF (1 != count_blocks (&acc)); 910 911 /* the matching decrement drops it to 0, deleting the object */ 912 FAILIF (SYNC_DB_ONE_RESULT != 913 SYNCDB_delete_block_TR (&acc, 914 &nonce, 915 NULL, 916 NULL, 917 &bh, 918 1, 919 &uid, 920 &dec, 921 NULL, 922 NULL, 923 NULL, 924 NULL, 925 NULL, 926 NULL)); 927 FAILIF (SYNC_DB_NO_RESULTS != 928 SYNCDB_lookup_object (&acc, 929 &oh, 930 &refcount, 931 &exp, 932 &data_sz, 933 NULL)); 934 FAILIF (0 != count_blocks (&acc)); 935 } 936 937 /* --- Increments for the same UID are aggregated --- */ 938 { 939 struct SYNC_AccountPublicKeyP acc; 940 struct SYNC_BlockNonce nonce; 941 struct GNUNET_HashCode bh; 942 struct SYNC_ObjectUID uids[2]; 943 struct GNUNET_HashCode oh; 944 const int16_t incs[2] = { -1, 1 }; 945 char data[] = "net-zero"; 946 char obj[] = "aggregated"; 947 int64_t refcount = 0; 948 struct GNUNET_TIME_Timestamp exp; 949 size_t data_sz = 0; 950 951 memset (&acc, 14, sizeof (acc)); 952 FAILIF (GNUNET_OK != 953 activate_account (&acc, 954 "fake-order-aggregate")); 955 RND_BLK (&nonce); 956 RND_BLK (&uids[0]); 957 uids[1] = uids[0]; 958 GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh); 959 GNUNET_CRYPTO_hash (obj, sizeof obj - 1, &oh); 960 FAILIF (SYNC_DB_ONE_RESULT != 961 SYNCDB_store_object_TR (&uids[0], 962 &acc, 963 &oh, 964 GNUNET_TIME_UNIT_DAYS, 965 sizeof obj - 1, 966 obj)); 967 FAILIF (SYNC_DB_ONE_RESULT != 968 SYNCDB_append_block_TR (&acc, 969 &nonce, 970 NULL, 971 &bh, 972 sizeof data - 1, 973 data, 974 2, 975 uids, 976 incs, 977 &fake_sig, 978 &empty_refs, 979 NULL, 980 NULL, 981 NULL)); 982 /* refcount unchanged, and the object still exists */ 983 FAILIF (SYNC_DB_ONE_RESULT != 984 SYNCDB_lookup_object (&acc, 985 &oh, 986 &refcount, 987 &exp, 988 &data_sz, 989 NULL)); 990 FAILIF (0 != refcount); 991 } 992 993 /* --- GC must not remove still-referenced objects --- */ 994 { 995 struct SYNC_AccountPublicKeyP acc; 996 struct SYNC_BlockNonce nonce; 997 struct GNUNET_HashCode bh; 998 struct SYNC_ObjectUID kept_uid; 999 struct SYNC_ObjectUID swept_uid; 1000 struct GNUNET_HashCode kept_oh; 1001 struct GNUNET_HashCode swept_oh; 1002 const int16_t inc = 1; 1003 char data[] = "gc-block"; 1004 char kept[] = "still-referenced"; 1005 char swept[] = "unreferenced"; 1006 int64_t refcount = 0; 1007 struct GNUNET_TIME_Timestamp exp; 1008 size_t data_sz = 0; 1009 struct GNUNET_TIME_Absolute future; 1010 1011 memset (&acc, 15, sizeof (acc)); 1012 FAILIF (GNUNET_OK != 1013 activate_account (&acc, 1014 "fake-order-gc")); 1015 RND_BLK (&nonce); 1016 RND_BLK (&kept_uid); 1017 RND_BLK (&swept_uid); 1018 GNUNET_CRYPTO_hash (data, sizeof data - 1, &bh); 1019 GNUNET_CRYPTO_hash (kept, sizeof kept - 1, &kept_oh); 1020 GNUNET_CRYPTO_hash (swept, sizeof swept - 1, &swept_oh); 1021 FAILIF (SYNC_DB_ONE_RESULT != 1022 SYNCDB_store_object_TR (&kept_uid, 1023 &acc, 1024 &kept_oh, 1025 GNUNET_TIME_UNIT_DAYS, 1026 sizeof kept - 1, 1027 kept)); 1028 FAILIF (SYNC_DB_ONE_RESULT != 1029 SYNCDB_store_object_TR (&swept_uid, 1030 &acc, 1031 &swept_oh, 1032 GNUNET_TIME_UNIT_DAYS, 1033 sizeof swept - 1, 1034 swept)); 1035 FAILIF (SYNC_DB_ONE_RESULT != 1036 SYNCDB_append_block_TR (&acc, 1037 &nonce, 1038 NULL, 1039 &bh, 1040 sizeof data - 1, 1041 data, 1042 1, 1043 &kept_uid, 1044 &inc, 1045 &fake_sig, 1046 &empty_refs, 1047 NULL, 1048 NULL, 1049 NULL)); 1050 /* Leave accounts and payments alone, only sweep objects */ 1051 future = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS); 1052 FAILIF (GNUNET_OK != 1053 SYNCDB_gc (GNUNET_TIME_UNIT_ZERO_ABS, 1054 GNUNET_TIME_UNIT_ZERO_ABS, 1055 future)); 1056 /* the referenced object survives ... */ 1057 FAILIF (SYNC_DB_ONE_RESULT != 1058 SYNCDB_lookup_object (&acc, 1059 &kept_oh, 1060 &refcount, 1061 &exp, 1062 &data_sz, 1063 NULL)); 1064 FAILIF (1 != refcount); 1065 /* ... the unreferenced one is collected */ 1066 FAILIF (SYNC_DB_NO_RESULTS != 1067 SYNCDB_lookup_object (&acc, 1068 &swept_oh, 1069 &refcount, 1070 &exp, 1071 &data_sz, 1072 NULL)); 1073 } 1074 1075 ts = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS); 1076 FAILIF (GNUNET_OK != 1077 SYNCDB_gc (ts, 1078 ts, 1079 ts)); 1080 result = 0; 1081 drop: 1082 GNUNET_break (GNUNET_OK == 1083 SYNCDB_drop_tables ()); 1084 SYNCDB_fini (); 1085 } 1086 1087 1088 int 1089 main (int argc, 1090 char *const argv[]) 1091 { 1092 const char *plugin_name; 1093 char *config_filename; 1094 struct GNUNET_CONFIGURATION_Handle *cfg; 1095 1096 (void) argc; 1097 result = EXIT_FAILURE; 1098 /* the database backend is the suffix of our own binary name */ 1099 if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) 1100 { 1101 GNUNET_break (0); 1102 return EXIT_FAILURE; 1103 } 1104 plugin_name++; 1105 GNUNET_log_setup (argv[0], 1106 "DEBUG", 1107 NULL); 1108 GNUNET_asprintf (&config_filename, 1109 "test_sync_db_%s.conf", 1110 plugin_name); 1111 cfg = GNUNET_CONFIGURATION_create (SYNC_project_data ()); 1112 if (GNUNET_OK != 1113 GNUNET_CONFIGURATION_parse (cfg, 1114 config_filename)) 1115 { 1116 GNUNET_break (0); 1117 GNUNET_CONFIGURATION_destroy (cfg); 1118 GNUNET_free (config_filename); 1119 return EXIT_NOTCONFIGURED; 1120 } 1121 GNUNET_SCHEDULER_run (&run, cfg); 1122 GNUNET_CONFIGURATION_destroy (cfg); 1123 GNUNET_free (config_filename); 1124 return result; 1125 } 1126 1127 1128 /* end of test_sync_db.c */