test_donaudb.c (48668B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU 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 src/donaudb/test_donaudb.c 18 * @brief test cases for DB interaction functions 19 * @author Johannes Casaburi 20 */ 21 #include "donau_config.h" 22 #include <taler/taler_json_lib.h> 23 #include "donaudb_lib.h" 24 #include "donau_util.h" 25 #include "helper.h" 26 #include "donaudb_lib.h" 27 #include "donau-database/commit.h" 28 #include "donau-database/create_tables.h" 29 #include "donau-database/delete_charity.h" 30 #include "donau-database/drop_tables.h" 31 #include "donau-database/event_listen_cancel.h" 32 #include "donau-database/event_listen.h" 33 #include "donau-database/event_notify.h" 34 #include "donau-database/iterate_charities.h" 35 #include "donau-database/iterate_history_entries.h" 36 #include "donau-database/insert_charity.h" 37 #include "donau-database/insert_donation_unit.h" 38 #include "donau-database/insert_history_entry.h" 39 #include "donau-database/do_insert_receipt_issued.h" 40 #include "donau-database/insert_signkey.h" 41 #include "donau-database/insert_receipts_submitted.h" 42 #include "donau-database/iterate_active_signkeys.h" 43 #include "donau-database/iterate_donation_units.h" 44 #include "donau-database/get_receipts_submitted_total.h" 45 #include "donau-database/get_charity.h" 46 #include "donau-database/get_donation_unit_amount.h" 47 #include "donau-database/get_receipt_issued.h" 48 #include "donau-database/get_signkey.h" 49 #include "donau-database/preflight.h" 50 #include "donau-database/rollback.h" 51 #include "donau-database/start.h" 52 #include "donau-database/start_read_committed.h" 53 #include "donau-database/start_read_only.h" 54 #include "donau-database/update_charity.h" 55 56 /** 57 * Global result from the testcase. 58 */ 59 static int result; 60 61 /** 62 * Report line of error if @a cond is true, and jump to label "drop". 63 */ 64 #define FAILIF(cond) \ 65 do { \ 66 if (! (cond)) { break;} \ 67 GNUNET_break (0); \ 68 goto drop; \ 69 } while (0) 70 71 72 /** 73 * Initializes @a ptr with random data. 74 */ 75 #define RND_BLK(ptr) \ 76 GNUNET_CRYPTO_random_block (ptr, sizeof (* \ 77 ptr)) 78 79 /** 80 * Initializes @a ptr with zeros. 81 */ 82 #define ZR_BLK(ptr) \ 83 memset (ptr, 0, sizeof (*ptr)) 84 85 /** 86 * How big do we make the RSA keys? 87 */ 88 #define RSA_KEY_SIZE 1024 89 90 /** 91 * Currency we use. Must match test-donau-db-*.conf. 92 */ 93 #define CURRENCY "EUR" 94 95 /** 96 * Database plugin under test. 97 */ 98 static struct DONAUDB_PostgresContext *ctx; 99 100 /** 101 * Denomination key pair used to manufacture blinded donation unit 102 * signatures for the regression tests below. Created on demand. 103 */ 104 static struct TALER_DenominationPrivateKey test_denom_priv; 105 106 /** 107 * Public key matching #test_denom_priv. 108 */ 109 static struct TALER_DenominationPublicKey test_denom_pub; 110 111 112 /** 113 * Create a blinded donation unit signature usable as filler data 114 * for `receipts_issued.blinded_sig'. 115 * 116 * @return freshly allocated blinded signature 117 */ 118 static struct GNUNET_CRYPTO_BlindedSignature * 119 make_blinded_sig (void) 120 { 121 struct GNUNET_CRYPTO_BlindedMessage *rp; 122 struct GNUNET_CRYPTO_BlindedSignature *bs; 123 124 if (NULL == test_denom_priv.bsign_priv_key) 125 GNUNET_assert (GNUNET_OK == 126 TALER_denom_priv_create (&test_denom_priv, 127 &test_denom_pub, 128 GNUNET_CRYPTO_BSA_RSA, 129 RSA_KEY_SIZE)); 130 rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); 131 rp->cipher = GNUNET_CRYPTO_BSA_RSA; 132 rp->rc = 1; 133 rp->details.rsa_blinded_message.blinded_msg_size = 32; 134 rp->details.rsa_blinded_message.blinded_msg = GNUNET_malloc (32); 135 GNUNET_CRYPTO_random_block (rp->details.rsa_blinded_message.blinded_msg, 136 32); 137 bs = GNUNET_CRYPTO_blind_sign (test_denom_priv.bsign_priv_key, 138 "rw", 139 rp); 140 GNUNET_assert (NULL != bs); 141 GNUNET_CRYPTO_blinded_message_decref (rp); 142 return bs; 143 } 144 145 146 /** 147 * Register a fresh charity with a random public key. 148 * 149 * @param max_per_year annual donation limit to use 150 * @param[out] charity_id set to the ID of the new charity 151 * @return #GNUNET_OK on success 152 */ 153 static enum GNUNET_GenericReturnValue 154 make_charity (const char *max_per_year, 155 uint64_t *charity_id) 156 { 157 struct DONAU_CharityPublicKeyP charity_pub; 158 struct TALER_Amount max; 159 160 RND_BLK (&charity_pub); 161 GNUNET_assert (GNUNET_OK == 162 TALER_string_to_amount (max_per_year, 163 &max)); 164 return (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 165 DONAUDB_insert_charity (ctx, 166 &charity_pub, 167 "test charity", 168 "https://charity.example.com/", 169 &max, 170 charity_id)) 171 ? GNUNET_OK 172 : GNUNET_SYSERR; 173 } 174 175 176 /** 177 * Issue one (fresh, never seen before) receipt for @a charity_id. 178 * 179 * @param charity_id charity to issue for 180 * @param year year to attribute the receipt to 181 * @param amount amount of the receipt 182 * @param[out] under_limit set to true if the charity stayed below its limit 183 * @return database status of the operation 184 */ 185 static enum GNUNET_DB_QueryStatus 186 issue_receipt (uint64_t charity_id, 187 uint32_t year, 188 const char *amount, 189 bool *under_limit) 190 { 191 struct DONAU_BlindedDonationUnitSignature du_sigs[1]; 192 struct DONAU_DonationReceiptHashP h_receipt; 193 struct TALER_Amount amt; 194 bool charity_unknown; 195 enum GNUNET_DB_QueryStatus qs; 196 197 RND_BLK (&h_receipt); 198 GNUNET_assert (GNUNET_OK == 199 TALER_string_to_amount (amount, 200 &amt)); 201 du_sigs[0].blinded_sig = make_blinded_sig (); 202 qs = DONAUDB_do_insert_receipt_issued (ctx, 203 year, 204 1, 205 du_sigs, 206 charity_id, 207 &h_receipt, 208 &amt, 209 under_limit, 210 &charity_unknown); 211 GNUNET_CRYPTO_blinded_sig_decref (du_sigs[0].blinded_sig); 212 return qs; 213 } 214 215 216 /** 217 * Return charities information. 218 * 219 * @param cls closure 220 */ 221 static enum GNUNET_GenericReturnValue 222 charities_cb ( 223 void *cls, 224 uint64_t charity_id, 225 const struct DONAU_CharityPublicKeyP *charity_pub, 226 const char *charity_name, 227 const struct TALER_Amount *max_per_year, 228 uint32_t current_year, 229 const struct TALER_Amount *receipts_to_date) 230 { 231 (void) cls; 232 (void) charity_id; 233 (void) charity_name; 234 (void) max_per_year; 235 (void) current_year; 236 (void) receipts_to_date; 237 return GNUNET_OK; 238 } 239 240 241 /** 242 * Function called with information about the donau's donation_unit keys. 243 * 244 * @param cls NULL 245 * @param donation_unit_pub public key of the donation_unit 246 * @param h_donation_unit_pub hash of @a donation_unit_pub 247 * @param validity_year of the donation unit 248 * @param value of the donation unit 249 */ 250 static enum GNUNET_GenericReturnValue 251 donation_unit_info_cb ( 252 void *cls, 253 const struct DONAU_DonationUnitHashP *h_donation_unit_pub, 254 const struct DONAU_DonationUnitPublicKey *donation_unit_pub, 255 uint64_t validity_year, 256 struct TALER_Amount *value) 257 { 258 (void) cls; 259 (void) h_donation_unit_pub; 260 (void) donation_unit_pub; 261 (void) validity_year; 262 (void) value; 263 return GNUNET_OK; 264 } 265 266 267 /** 268 * Create an unblinded donation unit signature. The database layer only 269 * serializes it, so any well-formed signature will do. 270 * 271 * @return freshly allocated unblinded signature 272 */ 273 static struct GNUNET_CRYPTO_UnblindedSignature * 274 make_unblinded_sig (void) 275 { 276 struct GNUNET_CRYPTO_UnblindedSignature *us; 277 struct GNUNET_HashCode msg; 278 279 if (NULL == test_denom_priv.bsign_priv_key) 280 GNUNET_assert (GNUNET_OK == 281 TALER_denom_priv_create (&test_denom_priv, 282 &test_denom_pub, 283 GNUNET_CRYPTO_BSA_RSA, 284 RSA_KEY_SIZE)); 285 RND_BLK (&msg); 286 us = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature); 287 us->cipher = GNUNET_CRYPTO_BSA_RSA; 288 us->rc = 1; 289 us->details.rsa_signature 290 = GNUNET_CRYPTO_rsa_sign_fdh ( 291 test_denom_priv.bsign_priv_key->details.rsa_private_key, 292 &msg, 293 sizeof (msg)); 294 GNUNET_assert (NULL != us->details.rsa_signature); 295 return us; 296 } 297 298 299 /** 300 * Register a donation unit with a random key hash. 301 * 302 * @param[out] h_donation_unit_pub set to the hash identifying the unit 303 * @param year validity year of the unit 304 * @param value value of the unit 305 * @return database status of the operation 306 */ 307 static enum GNUNET_DB_QueryStatus 308 make_donation_unit (struct DONAU_DonationUnitHashP *h_donation_unit_pub, 309 uint64_t year, 310 const char *value) 311 { 312 struct TALER_DenominationPrivateKey dpriv; 313 struct TALER_DenominationPublicKey dpub; 314 struct DONAU_DonationUnitPublicKey du_pub; 315 struct TALER_Amount val; 316 enum GNUNET_DB_QueryStatus qs; 317 318 RND_BLK (h_donation_unit_pub); 319 GNUNET_assert (GNUNET_OK == 320 TALER_denom_priv_create (&dpriv, 321 &dpub, 322 GNUNET_CRYPTO_BSA_RSA, 323 RSA_KEY_SIZE)); 324 du_pub.bsign_pub_key = dpub.bsign_pub_key; 325 GNUNET_assert (GNUNET_OK == 326 TALER_string_to_amount (value, 327 &val)); 328 qs = DONAUDB_insert_donation_unit (ctx, 329 h_donation_unit_pub, 330 &du_pub, 331 year, 332 &val); 333 TALER_denom_priv_free (&dpriv); 334 TALER_denom_pub_free (&dpub); 335 return qs; 336 } 337 338 339 /** 340 * Function called with information about the donau's online signing keys. 341 * 342 * @param cls NULL 343 * @param donau_pub the public key 344 * @param meta meta data information about the denomination type (expirations) 345 */ 346 static void 347 iterate_active_signkeys_cb ( 348 void *cls, 349 const struct DONAU_DonauPublicKeyP *donau_pub, 350 struct DONAUDB_SignkeyMetaData *meta) 351 { 352 (void) cls; 353 (void) donau_pub; 354 (void) meta; 355 } 356 357 358 /** 359 * Closure for #check_charity_cb(). 360 */ 361 struct CharityCheck 362 { 363 /** 364 * Charity we are interested in. 365 */ 366 uint64_t charity_id; 367 368 /** 369 * Value #DONAUDB_iterate_charities() reported for it. 370 */ 371 struct TALER_Amount receipts_to_date; 372 373 /** 374 * Set to true if the charity was seen. 375 */ 376 bool found; 377 }; 378 379 380 /** 381 * Capture what #DONAUDB_iterate_charities() reports for one charity. 382 * 383 * @param cls a `struct CharityCheck *` 384 * @param charity_id charity of this row 385 * @param charity_pub public key of the charity 386 * @param charity_name name of the charity 387 * @param max_per_year annual limit 388 * @param current_year year `receipts_to_date' belongs to 389 * @param receipts_to_date total booked so far 390 * @return #GNUNET_OK to continue 391 */ 392 static enum GNUNET_GenericReturnValue 393 check_charity_cb (void *cls, 394 uint64_t charity_id, 395 const struct DONAU_CharityPublicKeyP *charity_pub, 396 const char *charity_name, 397 const struct TALER_Amount *max_per_year, 398 uint32_t current_year, 399 const struct TALER_Amount *receipts_to_date) 400 { 401 struct CharityCheck *cc = cls; 402 403 (void) charity_pub; 404 (void) charity_name; 405 (void) max_per_year; 406 (void) current_year; 407 if (charity_id != cc->charity_id) 408 return GNUNET_OK; 409 cc->receipts_to_date = *receipts_to_date; 410 cc->found = true; 411 return GNUNET_OK; 412 } 413 414 415 /** 416 * Closure for #collect_history_cb(). 417 */ 418 struct HistoryCheck 419 { 420 /** 421 * Charity we are interested in. 422 */ 423 unsigned long long charity_id; 424 425 /** 426 * Year we expect a history entry for. 427 */ 428 uint64_t donation_year; 429 430 /** 431 * Amount we expect that entry to carry. 432 */ 433 struct TALER_Amount expected; 434 435 /** 436 * Set to true if the expected entry was found. 437 */ 438 bool found; 439 }; 440 441 442 /** 443 * Look for the history entry described by @a cls. 444 * 445 * @param cls a `struct HistoryCheck *` 446 * @param charity_id charity of this entry 447 * @param final_amount closing total of that year 448 * @param donation_year year of this entry 449 * @return #GNUNET_OK to continue 450 */ 451 static enum GNUNET_GenericReturnValue 452 collect_history_cb (void *cls, 453 unsigned long long charity_id, 454 struct TALER_Amount final_amount, 455 uint64_t donation_year) 456 { 457 struct HistoryCheck *hc = cls; 458 459 if ( (charity_id == hc->charity_id) && 460 (donation_year == hc->donation_year) && 461 (0 == TALER_amount_cmp (&final_amount, 462 &hc->expected)) ) 463 hc->found = true; 464 return GNUNET_OK; 465 } 466 467 468 /** 469 * Main function that will be run by the scheduler. 470 * 471 * @param cls closure with config 472 */ 473 static void 474 run (void *cls) 475 { 476 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 477 unsigned int year; 478 479 // Charity information 480 json_t *charities; 481 struct DONAU_CharityPublicKeyP charity_pub; 482 struct DONAUDB_CharityMetaData charity_meta; 483 const char *charity_name; 484 const char *charity_url; 485 struct TALER_Amount max_per_year; 486 struct TALER_Amount receipts_to_date; 487 uint64_t charity_id; 488 489 // Donation unit information 490 struct DONAU_DonationUnitHashP h_donation_unit_pub; 491 uint64_t validity_year; 492 struct TALER_Amount du_value; 493 494 // Signing key information 495 struct DONAU_DonauPublicKeyP donau_pub; 496 struct DONAUDB_SignkeyMetaData sk_meta; 497 498 // Issued receipts information 499 size_t num_b_sigs = 1; 500 struct DONAU_BlindedDonationUnitSignature du_sigs[num_b_sigs]; 501 struct DONAU_DonationReceiptHashP h_receipt; 502 struct TALER_Amount amount_receipts; 503 bool smaller_than_max_per_year; 504 bool charity_unknown; 505 bool charity_in_use; 506 struct TALER_DenominationPrivateKey denom_priv; 507 struct TALER_DenominationPublicKey denom_pub; 508 struct DONAU_DonationUnitPublicKey du_pub; 509 struct GNUNET_CRYPTO_BlindedMessage *rp; 510 struct GNUNET_CRYPTO_RsaBlindedMessage *rsa; 511 512 if (NULL == 513 (ctx = DONAUDB_connect_admin (cfg))) 514 { 515 fprintf (stderr, 516 "Failed to connect to database\n"); 517 result = 77; 518 return; 519 } 520 (void) DONAUDB_drop_tables (ctx); 521 if (GNUNET_OK != 522 DONAUDB_create_tables (ctx)) 523 { 524 fprintf (stderr, 525 "Failed to create DB tables\n"); 526 result = 77; 527 goto cleanup; 528 } 529 DONAUDB_preflight (ctx); 530 FAILIF (GNUNET_OK != 531 DONAUDB_start (ctx, 532 "test-1")); 533 534 fprintf (stderr, 535 "Running DB tests\n"); 536 537 /* test DB is empty */ 538 charity_id = 1; 539 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 540 DONAUDB_get_charity (ctx, 541 charity_id, 542 &charity_meta)); 543 544 /* test insert charity */ 545 charity_name = "charity_name"; 546 charity_url = "charity_url"; 547 charities = json_array (); 548 RND_BLK (&charity_pub); 549 GNUNET_assert (GNUNET_OK == 550 TALER_string_to_amount (CURRENCY ":1.000010", 551 &max_per_year)); 552 GNUNET_assert (GNUNET_OK == 553 TALER_string_to_amount (CURRENCY ":0.000010", 554 &receipts_to_date)); 555 556 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 557 DONAUDB_insert_charity (ctx, 558 &charity_pub, 559 charity_name, 560 charity_url, 561 &max_per_year, 562 &charity_id)); 563 564 /* test get charities */ 565 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 566 DONAUDB_iterate_charities (ctx, 567 &charities_cb, 568 charities)); 569 570 { 571 /* Update the charity and verify the new key and metadata persist. */ 572 const char *updated_charity_name = "charity_name_updated"; 573 const char *updated_charity_url = "charity_url_updated"; 574 struct TALER_Amount updated_max; 575 struct DONAU_CharityPrivateKeyP updated_charity_priv; 576 struct DONAU_CharityPublicKeyP updated_charity_pub; 577 bool conflict = true; 578 579 GNUNET_CRYPTO_eddsa_key_create (&updated_charity_priv.eddsa_priv); 580 GNUNET_CRYPTO_eddsa_key_get_public (&updated_charity_priv.eddsa_priv, 581 &updated_charity_pub.eddsa_pub); 582 583 GNUNET_assert (GNUNET_OK == 584 TALER_string_to_amount (CURRENCY ":2.000000", 585 &updated_max)); 586 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 587 DONAUDB_update_charity (ctx, 588 charity_id, 589 &updated_charity_pub, 590 updated_charity_name, 591 updated_charity_url, 592 &updated_max, 593 &conflict)); 594 FAILIF (conflict); 595 596 ZR_BLK (&charity_meta); 597 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 598 DONAUDB_get_charity (ctx, 599 charity_id, 600 &charity_meta)); 601 GNUNET_assert (0 == GNUNET_memcmp (&charity_meta.charity_pub, 602 &updated_charity_pub)); 603 GNUNET_assert (0 == strcmp (charity_meta.charity_name, 604 updated_charity_name)); 605 GNUNET_assert (0 == strcmp (charity_meta.charity_url, 606 updated_charity_url)); 607 GNUNET_assert (0 == TALER_amount_cmp (&charity_meta.max_per_year, 608 &updated_max)); 609 GNUNET_free (charity_meta.charity_name); 610 GNUNET_free (charity_meta.charity_url); 611 612 charity_name = updated_charity_name; 613 charity_url = updated_charity_url; 614 max_per_year = updated_max; 615 charity_pub = updated_charity_pub; 616 } 617 618 /* test delete charity */ 619 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 620 DONAUDB_delete_charity (ctx, 621 charity_id, 622 &charity_in_use)); 623 624 /* test insert donation unit */ 625 RND_BLK (&h_donation_unit_pub); 626 GNUNET_assert (GNUNET_OK == 627 TALER_denom_priv_create (&denom_priv, 628 &denom_pub, 629 GNUNET_CRYPTO_BSA_RSA, 630 RSA_KEY_SIZE)); 631 du_pub.bsign_pub_key = denom_pub.bsign_pub_key; 632 validity_year = 2024; 633 GNUNET_assert (GNUNET_OK == 634 TALER_string_to_amount (CURRENCY ":1.000010", 635 &du_value)); 636 637 /* test iterate donation units */ 638 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 639 DONAUDB_iterate_donation_units (ctx, 640 &donation_unit_info_cb, 641 NULL)); 642 643 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 644 DONAUDB_insert_donation_unit (ctx, 645 &h_donation_unit_pub, 646 &du_pub, 647 validity_year, 648 &du_value)); 649 650 /* test iterate donation units */ 651 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 652 DONAUDB_iterate_donation_units (ctx, 653 &donation_unit_info_cb, 654 NULL)); 655 656 /* D-9: the security module re-announces every donation unit on each 657 restart, and h_donation_unit_pub covers the key material only. A 658 donation_units row is a historical fact -- receipts already issued under 659 this key are summed from its value -- so a re-announce with a different 660 year and value must leave the stored row untouched. */ 661 { 662 struct TALER_Amount other_value; 663 struct TALER_Amount stored_value; 664 665 GNUNET_assert (GNUNET_OK == 666 TALER_string_to_amount (CURRENCY ":2.000020", 667 &other_value)); 668 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 669 DONAUDB_insert_donation_unit (ctx, 670 &h_donation_unit_pub, 671 &du_pub, 672 validity_year + 1, 673 &other_value)); 674 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 675 DONAUDB_get_donation_unit_amount (ctx, 676 &h_donation_unit_pub, 677 &stored_value)); 678 FAILIF (0 != TALER_amount_cmp (&stored_value, 679 &du_value)); 680 } 681 682 /* D-9: a key the operator retires is replaced by a *new* key, which may 683 well carry the same year and value. Both must be storable side by side, 684 so that the signatures already made with the old one stay accountable. */ 685 { 686 struct TALER_DenominationPrivateKey second_priv; 687 struct TALER_DenominationPublicKey second_pub; 688 struct DONAU_DonationUnitPublicKey second_du_pub; 689 struct DONAU_DonationUnitHashP second_h_du_pub; 690 691 RND_BLK (&second_h_du_pub); 692 GNUNET_assert (GNUNET_OK == 693 TALER_denom_priv_create (&second_priv, 694 &second_pub, 695 GNUNET_CRYPTO_BSA_RSA, 696 RSA_KEY_SIZE)); 697 second_du_pub.bsign_pub_key = second_pub.bsign_pub_key; 698 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 699 DONAUDB_insert_donation_unit (ctx, 700 &second_h_du_pub, 701 &second_du_pub, 702 validity_year, 703 &du_value)); 704 TALER_denom_priv_free (&second_priv); 705 TALER_denom_pub_free (&second_pub); 706 } 707 708 TALER_denom_pub_free (&denom_pub); 709 710 /* test insert signing key */ 711 RND_BLK (&donau_pub); 712 year = GNUNET_TIME_get_current_year (); 713 sk_meta.expire_legal = GNUNET_TIME_absolute_to_timestamp ( 714 GNUNET_TIME_year_to_time (year + 5)); 715 sk_meta.expire_sign = GNUNET_TIME_absolute_to_timestamp ( 716 GNUNET_TIME_year_to_time (year + 1)); 717 sk_meta.valid_from = GNUNET_TIME_absolute_to_timestamp ( 718 GNUNET_TIME_year_to_time (year)); 719 720 721 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 722 DONAUDB_insert_signkey (ctx, 723 &donau_pub, 724 &sk_meta)); 725 726 /* test iterate signing key */ 727 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 728 DONAUDB_iterate_active_signkeys (ctx, 729 &iterate_active_signkeys_cb, 730 NULL)); 731 732 /* test insert issued receipt */ 733 rp = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage); 734 rp->cipher = GNUNET_CRYPTO_BSA_RSA; 735 rp->rc = 1; 736 rsa = &rp->details.rsa_blinded_message; 737 rsa->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 ( 738 (RSA_KEY_SIZE / 8) - 1); 739 rsa->blinded_msg = GNUNET_malloc (rsa->blinded_msg_size); 740 GNUNET_CRYPTO_random_block (rsa->blinded_msg, 741 rsa->blinded_msg_size); 742 smaller_than_max_per_year = false; 743 GNUNET_assert (GNUNET_OK == 744 TALER_string_to_amount (CURRENCY ":1.000010", 745 &amount_receipts)); 746 747 du_sigs[0].blinded_sig = 748 GNUNET_CRYPTO_blind_sign (denom_priv.bsign_priv_key, 749 "rw", 750 rp); 751 752 GNUNET_assert (NULL != du_sigs[0].blinded_sig); 753 TALER_denom_priv_free (&denom_priv); 754 755 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 756 DONAUDB_do_insert_receipt_issued (ctx, 757 GNUNET_TIME_get_current_year (), 758 num_b_sigs, 759 du_sigs, 760 charity_id, 761 &h_receipt, 762 &amount_receipts, 763 &smaller_than_max_per_year, 764 &charity_unknown)); 765 766 // FIXME 767 // FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 768 // DONAUDB_get_receipt_issued (ctx, 769 // &h_receipt, 770 // &ir_meta)); 771 772 /* test insert submitted receipts */ 773 // RND_BLK (&h_donor_tax_id); 774 // RND_BLK (&donation_receipts[0].h_donation_unit_pub); 775 // RND_BLK (&donation_receipts[0].nonce); 776 // RND_BLK (&donation_receipts[0].donation_unit_sig); 777 // FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 778 // DONAUDB_insert_receipts_submitted (ctx, 779 // &h_donor_tax_id, 780 // num_dr, 781 // donation_receipts, 782 // current_year)); 783 784 DONAUDB_preflight (ctx); 785 786 /* A transaction PostgreSQL has already aborted must never be reported as 787 committed -- and a clean transaction must still return exactly 788 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS, which is what every caller that 789 compares against 0 relies on. */ 790 { 791 struct GNUNET_PQ_ExecuteStatement mk[] = { 792 GNUNET_PQ_make_execute ("CREATE TABLE test_commit_rollback (x INT)"), 793 GNUNET_PQ_EXECUTE_STATEMENT_END 794 }; 795 struct GNUNET_PQ_ExecuteStatement bad[] = { 796 GNUNET_PQ_make_execute ("SELECT 1/0"), 797 GNUNET_PQ_EXECUTE_STATEMENT_END 798 }; 799 struct GNUNET_PQ_ExecuteStatement chk[] = { 800 GNUNET_PQ_make_execute ( 801 "DO $$ BEGIN" 802 " IF EXISTS (SELECT FROM pg_class" 803 " WHERE relname='test_commit_rollback')" 804 " THEN RAISE EXCEPTION 'table survived a rollback';" 805 " END IF; END $$"), 806 GNUNET_PQ_EXECUTE_STATEMENT_END 807 }; 808 809 FAILIF (GNUNET_OK != 810 DONAUDB_start (ctx, 811 "test-commit-aborted")); 812 FAILIF (GNUNET_OK != 813 GNUNET_PQ_exec_statements (ctx->conn, 814 mk)); 815 /* provoke an error; from here on the transaction is doomed */ 816 FAILIF (GNUNET_OK == 817 GNUNET_PQ_exec_statements (ctx->conn, 818 bad)); 819 /* before the fix this returned GNUNET_DB_STATUS_SUCCESS_NO_RESULTS (0) */ 820 FAILIF (0 <= 821 DONAUDB_commit (ctx)); 822 /* ...and the table is indeed gone, so 'success' would have been a lie */ 823 FAILIF (GNUNET_OK != 824 GNUNET_PQ_exec_statements (ctx->conn, 825 chk)); 826 827 FAILIF (GNUNET_OK != 828 DONAUDB_start (ctx, 829 "test-commit-clean")); 830 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 831 DONAUDB_commit (ctx)); 832 } 833 834 /* D-5: `history' is documented as holding the *yearly* total per 835 charity, so it must be able to hold more than one year per charity, 836 and a repeated write for the same year must be distinguishable from 837 a successful one. */ 838 { 839 uint64_t hist_charity_id; 840 struct TALER_Amount y1; 841 struct TALER_Amount y2; 842 843 FAILIF (GNUNET_OK != 844 make_charity (CURRENCY ":1000", 845 &hist_charity_id)); 846 GNUNET_assert (GNUNET_OK == 847 TALER_string_to_amount (CURRENCY ":90", 848 &y1)); 849 GNUNET_assert (GNUNET_OK == 850 TALER_string_to_amount (CURRENCY ":75", 851 &y2)); 852 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 853 DONAUDB_insert_history_entry (ctx, 854 hist_charity_id, 855 &y1, 856 2026)); 857 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 858 DONAUDB_insert_history_entry (ctx, 859 hist_charity_id, 860 &y2, 861 2027)); 862 /* Re-recording the same year must report "nothing written". */ 863 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 864 DONAUDB_insert_history_entry (ctx, 865 hist_charity_id, 866 &y2, 867 2027)); 868 } 869 870 /* D-4: the first request of a new year resets receipts_to_date; the 871 closing total of the year being left must be preserved in `history' 872 rather than discarded. */ 873 { 874 uint64_t rollover_charity_id; 875 struct DONAUDB_CharityMetaData rollover_meta; 876 struct HistoryCheck hc; 877 struct TALER_Amount zero; 878 bool under_limit = false; 879 uint32_t this_year = GNUNET_TIME_get_current_year (); 880 881 FAILIF (GNUNET_OK != 882 make_charity (CURRENCY ":1000", 883 &rollover_charity_id)); 884 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 885 issue_receipt (rollover_charity_id, 886 this_year, 887 CURRENCY ":90", 888 &under_limit)); 889 FAILIF (! under_limit); 890 /* Pretend those 90 were booked last year: that is the state every 891 charity is in on the 1st of January, before its first request. */ 892 { 893 struct GNUNET_PQ_QueryParam uparams[] = { 894 GNUNET_PQ_query_param_uint64 (&rollover_charity_id), 895 GNUNET_PQ_query_param_end 896 }; 897 898 FAILIF (GNUNET_OK != 899 GNUNET_PQ_prepare_anon (ctx->conn, 900 "UPDATE charities" 901 " SET current_year=current_year-1" 902 " WHERE charity_id=$1;")); 903 FAILIF (0 >= 904 GNUNET_PQ_eval_prepared_non_select (ctx->conn, 905 "", 906 uparams)); 907 } 908 /* First request of the new year. */ 909 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 910 issue_receipt (rollover_charity_id, 911 this_year, 912 CURRENCY ":5", 913 &under_limit)); 914 FAILIF (! under_limit); 915 916 memset (&hc, 917 0, 918 sizeof (hc)); 919 hc.charity_id = (unsigned long long) rollover_charity_id; 920 hc.donation_year = this_year - 1; 921 GNUNET_assert (GNUNET_OK == 922 TALER_string_to_amount (CURRENCY ":90", 923 &hc.expected)); 924 FAILIF (0 > 925 DONAUDB_iterate_history_entries (ctx, 926 &collect_history_cb, 927 &hc)); 928 FAILIF (! hc.found); 929 930 /* ... and the new year did start from zero. */ 931 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 932 DONAUDB_get_charity (ctx, 933 rollover_charity_id, 934 &rollover_meta)); 935 GNUNET_assert (GNUNET_OK == 936 TALER_string_to_amount (CURRENCY ":5", 937 &zero)); 938 FAILIF (0 != TALER_amount_cmp (&rollover_meta.receipts_to_date, 939 &zero)); 940 GNUNET_free (rollover_meta.charity_name); 941 GNUNET_free (rollover_meta.charity_url); 942 } 943 944 /* D-6: updating a charity to a charity_pub that another charity 945 already owns must be reported as a conflict, not as "no such 946 charity" -- and it must not abort the caller's transaction. */ 947 { 948 uint64_t first_id; 949 uint64_t second_id; 950 struct DONAUDB_CharityMetaData first_meta; 951 struct DONAUDB_CharityMetaData second_meta; 952 struct TALER_Amount some_max; 953 bool conflict = false; 954 955 FAILIF (GNUNET_OK != 956 make_charity (CURRENCY ":100", 957 &first_id)); 958 FAILIF (GNUNET_OK != 959 make_charity (CURRENCY ":100", 960 &second_id)); 961 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 962 DONAUDB_get_charity (ctx, 963 first_id, 964 &first_meta)); 965 GNUNET_assert (GNUNET_OK == 966 TALER_string_to_amount (CURRENCY ":100", 967 &some_max)); 968 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 969 DONAUDB_update_charity (ctx, 970 second_id, 971 &first_meta.charity_pub, 972 "stolen", 973 "https://stolen.example.com/", 974 &some_max, 975 &conflict)); 976 FAILIF (! conflict); 977 /* The second charity must be untouched ... */ 978 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 979 DONAUDB_get_charity (ctx, 980 second_id, 981 &second_meta)); 982 FAILIF (0 == GNUNET_memcmp (&second_meta.charity_pub, 983 &first_meta.charity_pub)); 984 /* ... and an unknown charity_id must still be "no results". */ 985 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 986 DONAUDB_update_charity (ctx, 987 second_id + 424242, 988 &second_meta.charity_pub, 989 "ghost", 990 "https://ghost.example.com/", 991 &some_max, 992 &conflict)); 993 FAILIF (conflict); 994 GNUNET_free (first_meta.charity_name); 995 GNUNET_free (first_meta.charity_url); 996 GNUNET_free (second_meta.charity_name); 997 GNUNET_free (second_meta.charity_url); 998 } 999 1000 /* D-7: `receipts_submitted.nonce' is globally unique, so a donor who 1001 reuses one UDI nonce for a *different* donation unit in a second 1002 request has that receipt silently dropped. The DB layer must tell 1003 the caller which index was refused, so /batch-submit can answer 409 1004 instead of 201. */ 1005 { 1006 struct DONAU_HashDonorTaxId donor; 1007 struct DONAU_DonationUnitHashP du_a; 1008 struct DONAU_DonationUnitHashP du_b; 1009 struct DONAU_DonationReceipt dr; 1010 struct DONAU_UniqueDonorIdentifierNonce nonce; 1011 struct TALER_Amount total; 1012 struct TALER_Amount expected; 1013 size_t conflict_index = 42; 1014 size_t unknown_index = 42; 1015 uint64_t this_year = GNUNET_TIME_get_current_year (); 1016 1017 RND_BLK (&donor); 1018 RND_BLK (&nonce); 1019 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1020 make_donation_unit (&du_a, 1021 this_year, 1022 CURRENCY ":10")); 1023 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1024 make_donation_unit (&du_b, 1025 this_year, 1026 CURRENCY ":25")); 1027 1028 dr.h_donation_unit_pub = du_a; 1029 dr.nonce = nonce; 1030 dr.donation_unit_sig.unblinded_sig = make_unblinded_sig (); 1031 FAILIF (0 > 1032 DONAUDB_insert_receipts_submitted (ctx, 1033 &donor, 1034 1, 1035 &dr, 1036 this_year, 1037 &conflict_index, 1038 &unknown_index)); 1039 FAILIF (1 != conflict_index); /* == num_dr, i.e. no conflict */ 1040 GNUNET_CRYPTO_unblinded_sig_decref (dr.donation_unit_sig.unblinded_sig); 1041 1042 /* Same donor, same nonce, different donation unit: refused. */ 1043 dr.h_donation_unit_pub = du_b; 1044 dr.nonce = nonce; 1045 dr.donation_unit_sig.unblinded_sig = make_unblinded_sig (); 1046 FAILIF (0 > 1047 DONAUDB_insert_receipts_submitted (ctx, 1048 &donor, 1049 1, 1050 &dr, 1051 this_year, 1052 &conflict_index, 1053 &unknown_index)); 1054 FAILIF (0 != conflict_index); 1055 GNUNET_CRYPTO_unblinded_sig_decref (dr.donation_unit_sig.unblinded_sig); 1056 1057 /* Only the first receipt is deductible; the second one was dropped. */ 1058 FAILIF (0 > 1059 DONAUDB_get_receipts_submitted_total (ctx, 1060 this_year, 1061 &donor, 1062 &total)); 1063 GNUNET_assert (GNUNET_OK == 1064 TALER_string_to_amount (CURRENCY ":10", 1065 &expected)); 1066 FAILIF (0 != TALER_amount_cmp (&total, 1067 &expected)); 1068 } 1069 1070 /* D-10: h_donation_unit_pub is client-supplied and is a foreign key. 1071 ON CONFLICT DO NOTHING does not absorb foreign key violations, so an 1072 unknown unit used to escape as a hard error (HTTP 500). It must be 1073 reported as "unknown donation unit at index i", and nothing at all 1074 may be written for that batch. */ 1075 { 1076 struct DONAU_HashDonorTaxId donor; 1077 struct DONAU_DonationUnitHashP known_du; 1078 struct DONAU_DonationReceipt drs[2]; 1079 struct TALER_Amount total; 1080 struct TALER_Amount zero; 1081 size_t conflict_index = 42; 1082 size_t unknown_index = 42; 1083 uint64_t this_year = GNUNET_TIME_get_current_year (); 1084 1085 RND_BLK (&donor); 1086 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1087 make_donation_unit (&known_du, 1088 this_year, 1089 CURRENCY ":10")); 1090 drs[0].h_donation_unit_pub = known_du; 1091 RND_BLK (&drs[0].nonce); 1092 drs[0].donation_unit_sig.unblinded_sig = make_unblinded_sig (); 1093 /* Second receipt names a donation unit that was never registered. */ 1094 RND_BLK (&drs[1].h_donation_unit_pub); 1095 RND_BLK (&drs[1].nonce); 1096 drs[1].donation_unit_sig.unblinded_sig = make_unblinded_sig (); 1097 1098 FAILIF (0 > 1099 DONAUDB_insert_receipts_submitted (ctx, 1100 &donor, 1101 2, 1102 drs, 1103 this_year, 1104 &conflict_index, 1105 &unknown_index)); 1106 FAILIF (1 != unknown_index); 1107 GNUNET_CRYPTO_unblinded_sig_decref (drs[0].donation_unit_sig.unblinded_sig); 1108 GNUNET_CRYPTO_unblinded_sig_decref (drs[1].donation_unit_sig.unblinded_sig); 1109 1110 /* The valid receipt in the same batch must NOT have been stored. */ 1111 FAILIF (0 > 1112 DONAUDB_get_receipts_submitted_total (ctx, 1113 this_year, 1114 &donor, 1115 &total)); 1116 GNUNET_assert (GNUNET_OK == 1117 TALER_amount_set_zero (CURRENCY, 1118 &zero)); 1119 FAILIF (0 != TALER_amount_cmp (&total, 1120 &zero)); 1121 } 1122 1123 /* Everything below runs in autocommit, which is what donau-httpd does. */ 1124 1125 /* D-1: amount_add()'s overflow guard must trigger at 2^52, not at 1126 2^20. A charity with a realistic annual limit must be able to 1127 book receipts well beyond 1048576 units of currency. */ 1128 { 1129 uint64_t big_charity_id; 1130 bool under_limit = false; 1131 1132 FAILIF (GNUNET_OK != 1133 make_charity (CURRENCY ":4000000000", 1134 &big_charity_id)); 1135 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1136 issue_receipt (big_charity_id, 1137 GNUNET_TIME_get_current_year (), 1138 CURRENCY ":2000000", 1139 &under_limit)); 1140 FAILIF (! under_limit); 1141 } 1142 1143 /* D-8: receipts_issued.receipt_id must not be settable from outside. 1144 If it is, an operator bulk load or a partial restore can leave the 1145 identity sequence behind the largest stored value, after which every 1146 insert fails on receipts_issued_receipt_id_key -- which donau-httpd 1147 used to answer with an assertion failure, i.e. abort(). */ 1148 { 1149 struct GNUNET_PQ_QueryParam params[] = { 1150 GNUNET_PQ_query_param_end 1151 }; 1152 1153 /* Control: the very same insert without receipt_id is accepted. */ 1154 FAILIF (GNUNET_OK != 1155 GNUNET_PQ_prepare_anon ( 1156 ctx->conn, 1157 "INSERT INTO receipts_issued" 1158 " (blinded_sig,charity_id,receipt_hash,amount)" 1159 " SELECT r.blinded_sig, r.charity_id," 1160 " sha512(r.receipt_hash), r.amount" 1161 " FROM receipts_issued r" 1162 " LIMIT 1;")); 1163 /* Supplying receipt_id explicitly must be refused. With GENERATED 1164 ALWAYS PostgreSQL already rejects it at PREPARE time; if a server 1165 accepts the statement, executing it must fail. */ 1166 if (GNUNET_OK == 1167 GNUNET_PQ_prepare_anon ( 1168 ctx->conn, 1169 "INSERT INTO receipts_issued" 1170 " (receipt_id,blinded_sig,charity_id,receipt_hash,amount)" 1171 " SELECT 424242, r.blinded_sig, r.charity_id," 1172 " sha512(r.receipt_hash), r.amount" 1173 " FROM receipts_issued r" 1174 " LIMIT 1;")) 1175 FAILIF (0 <= 1176 GNUNET_PQ_eval_prepared_non_select (ctx->conn, 1177 "", 1178 params)); 1179 } 1180 1181 /* D-12: between the 1st of January and a charity's first request of the 1182 year, `receipts_to_date' still holds last year's total. 1183 DONAUDB_iterate_charities() compensates for that; DONAUDB_get_charity() 1184 must do the same, otherwise GET /charity/$ID and GET /charities 1185 disagree and PATCH refuses to lower max_per_year below *last* year's 1186 total. */ 1187 { 1188 uint64_t stale_charity_id; 1189 struct DONAUDB_CharityMetaData stale_meta; 1190 struct CharityCheck cc; 1191 struct TALER_Amount zero; 1192 bool under_limit = false; 1193 1194 FAILIF (GNUNET_OK != 1195 make_charity (CURRENCY ":1000", 1196 &stale_charity_id)); 1197 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1198 issue_receipt (stale_charity_id, 1199 GNUNET_TIME_get_current_year (), 1200 CURRENCY ":90", 1201 &under_limit)); 1202 FAILIF (! under_limit); 1203 { 1204 struct GNUNET_PQ_QueryParam uparams[] = { 1205 GNUNET_PQ_query_param_uint64 (&stale_charity_id), 1206 GNUNET_PQ_query_param_end 1207 }; 1208 1209 FAILIF (GNUNET_OK != 1210 GNUNET_PQ_prepare_anon (ctx->conn, 1211 "UPDATE charities" 1212 " SET current_year=current_year-1" 1213 " WHERE charity_id=$1;")); 1214 FAILIF (0 >= 1215 GNUNET_PQ_eval_prepared_non_select (ctx->conn, 1216 "", 1217 uparams)); 1218 } 1219 GNUNET_assert (GNUNET_OK == 1220 TALER_amount_set_zero (CURRENCY, 1221 &zero)); 1222 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1223 DONAUDB_get_charity (ctx, 1224 stale_charity_id, 1225 &stale_meta)); 1226 FAILIF (0 != TALER_amount_cmp (&stale_meta.receipts_to_date, 1227 &zero)); 1228 GNUNET_free (stale_meta.charity_name); 1229 GNUNET_free (stale_meta.charity_url); 1230 1231 /* ... and the two views agree. */ 1232 memset (&cc, 1233 0, 1234 sizeof (cc)); 1235 cc.charity_id = stale_charity_id; 1236 FAILIF (0 > 1237 DONAUDB_iterate_charities (ctx, 1238 &check_charity_cb, 1239 &cc)); 1240 FAILIF (! cc.found); 1241 FAILIF (0 != TALER_amount_cmp (&cc.receipts_to_date, 1242 &zero)); 1243 } 1244 1245 /* D-13: receipts_issued.receipt_hash is the idempotence key of 1246 POST /batch-issue. Deleting a charity used to cascade those rows 1247 away, so re-registering the charity re-enabled replay of every 1248 request it had ever made. The delete must now be refused, and 1249 reported as such rather than as a hard error. */ 1250 { 1251 uint64_t busy_charity_id; 1252 struct DONAUDB_CharityMetaData survivor; 1253 bool under_limit = false; 1254 bool in_use = false; 1255 1256 FAILIF (GNUNET_OK != 1257 make_charity (CURRENCY ":1000", 1258 &busy_charity_id)); 1259 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1260 issue_receipt (busy_charity_id, 1261 GNUNET_TIME_get_current_year (), 1262 CURRENCY ":7", 1263 &under_limit)); 1264 FAILIF (! under_limit); 1265 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1266 DONAUDB_delete_charity (ctx, 1267 busy_charity_id, 1268 &in_use)); 1269 FAILIF (! in_use); 1270 /* The charity -- and with it the issued-receipt record -- survives. */ 1271 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1272 DONAUDB_get_charity (ctx, 1273 busy_charity_id, 1274 &survivor)); 1275 GNUNET_free (survivor.charity_name); 1276 GNUNET_free (survivor.charity_url); 1277 /* A charity without issued receipts is still deletable. */ 1278 { 1279 uint64_t idle_charity_id; 1280 1281 FAILIF (GNUNET_OK != 1282 make_charity (CURRENCY ":1000", 1283 &idle_charity_id)); 1284 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 1285 DONAUDB_delete_charity (ctx, 1286 idle_charity_id, 1287 &in_use)); 1288 FAILIF (in_use); 1289 } 1290 } 1291 1292 result = 0; 1293 1294 drop: 1295 if (0 != result) 1296 DONAUDB_rollback (ctx); 1297 GNUNET_break (GNUNET_OK == 1298 DONAUDB_drop_tables (ctx)); 1299 cleanup: 1300 if (NULL != test_denom_priv.bsign_priv_key) 1301 { 1302 TALER_denom_priv_free (&test_denom_priv); 1303 TALER_denom_pub_free (&test_denom_pub); 1304 } 1305 DONAUDB_disconnect (ctx); 1306 ctx = NULL; 1307 } 1308 1309 1310 int 1311 main (int argc, 1312 char *const argv[]) 1313 { 1314 const char *plugin_name; 1315 char *config_filename; 1316 char *testname; 1317 struct GNUNET_CONFIGURATION_Handle *cfg; 1318 1319 (void) argc; 1320 result = -1; 1321 if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) 1322 { 1323 GNUNET_break (0); 1324 return -1; 1325 } 1326 GNUNET_log_setup (argv[0], 1327 "INFO", 1328 NULL); 1329 plugin_name++; 1330 (void) GNUNET_asprintf (&testname, 1331 "test-donau-db-%s", 1332 plugin_name); 1333 (void) GNUNET_asprintf (&config_filename, 1334 "%s.conf", 1335 testname); 1336 cfg = GNUNET_CONFIGURATION_create (DONAU_project_data ()); 1337 if (GNUNET_OK != 1338 GNUNET_CONFIGURATION_parse (cfg, 1339 config_filename)) 1340 { 1341 GNUNET_break (0); 1342 GNUNET_free (config_filename); 1343 GNUNET_free (testname); 1344 return 2; 1345 } 1346 GNUNET_SCHEDULER_run (&run, 1347 cfg); 1348 GNUNET_CONFIGURATION_destroy (cfg); 1349 GNUNET_free (config_filename); 1350 GNUNET_free (testname); 1351 return result; 1352 } 1353 1354 1355 /* end of test_donaudb.c */