test_challenger_db.c (23769B)
1 /* 2 This file is part of Challenger 3 (C) 2023 Taler Systems SA 4 5 Challenger 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 Challenger 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 Challenger; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file challengerdb/test_challenger_db.c 18 * @brief testcase for challenger postgres db plugin 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include <gnunet/gnunet_util_lib.h> 23 #include <gnunet/gnunet_pq_lib.h> 24 #include <taler/taler_util.h> 25 #include "challenger_database_lib.h" 26 #include "challenger-database/drop_tables.h" 27 #include "challenger-database/create_tables.h" 28 #include "challenger-database/preflight.h" 29 #include "challenger-database/gc.h" 30 #include "challenger-database/insert_client.h" 31 #include "challenger-database/do_insert_validation.h" 32 #include "challenger-database/do_challenge_address.h" 33 #include "challenger-database/do_solve_challenge.h" 34 #include "challenger-database/do_insert_token.h" 35 #include "challenger-database/get_token.h" 36 #include "challenger-database/get_validation_pkce.h" 37 #include "challenger_util.h" 38 #include "pg_helper.h" 39 #include "challenger-database/delete_client.h" 40 #include "challenger-database/do_insert_validation.h" 41 42 43 #define FAILIF(cond) \ 44 do { \ 45 if (! (cond)) { break;} \ 46 GNUNET_break (0); \ 47 goto drop; \ 48 } while (0) 49 50 /** 51 * Secret of the client the tests register and act as. 52 */ 53 #define CLIENT_SECRET "secret-token:test-secret" 54 55 /** 56 * Redirect URI of the client the tests register. 57 */ 58 #define CLIENT_URI "http://client.example.com/" 59 60 /** 61 * Global return value for the test. Initially -1, set to 0 upon 62 * completion. Other values indicate some kind of error. 63 */ 64 static int result; 65 66 /** 67 * Handle to the database we are testing. 68 */ 69 static struct CHALLENGERDB_PostgresContext *pg; 70 71 /** 72 * Serial ID of the client registered by #setup_client(). 73 */ 74 static uint64_t client_id; 75 76 77 /** 78 * Register the OAuth client all tests act as. 79 * 80 * @return #GNUNET_OK on success 81 */ 82 static enum GNUNET_GenericReturnValue 83 setup_client (void) 84 { 85 bool uri_taken = false; 86 87 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 88 CHALLENGERDB_insert_client (pg, 89 CLIENT_URI, 90 CLIENT_SECRET, 91 &client_id, 92 &uri_taken)) 93 { 94 GNUNET_break (0); 95 return GNUNET_SYSERR; 96 } 97 return GNUNET_OK; 98 } 99 100 101 /** 102 * Create a fresh validation for #client_id and have a TAN transmitted 103 * for it, leaving the validation in the state a user reaches by posting 104 * an address to ``/challenge`` and then walking away. 105 * 106 * @param[out] nonce set to the nonce identifying the new validation 107 * @param[out] pin set to the TAN that was "transmitted" 108 * @return #GNUNET_OK on success 109 */ 110 static enum GNUNET_GenericReturnValue 111 challenge_validation (struct CHALLENGER_ValidationNonceP *nonce, 112 uint32_t *pin) 113 { 114 struct GNUNET_TIME_Absolute expiration 115 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); 116 json_t *address; 117 char *state = NULL; 118 char *redirect_uri = NULL; 119 struct GNUNET_TIME_Absolute last_tx_time; 120 uint32_t auth_attempts_left; 121 uint32_t pin_transmissions_left; 122 bool pin_transmit; 123 bool address_refused; 124 bool solved; 125 enum GNUNET_DB_QueryStatus qs; 126 127 GNUNET_CRYPTO_random_block (nonce, 128 sizeof (*nonce)); 129 qs = CHALLENGERDB_do_insert_validation (pg, 130 client_id, 131 CLIENT_SECRET, 132 nonce, 133 expiration, 134 NULL); 135 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) 136 { 137 GNUNET_break (0); 138 return GNUNET_SYSERR; 139 } 140 address = json_pack ("{s:s}", 141 "filename", 142 "test-challenger-db.txt"); 143 GNUNET_assert (NULL != address); 144 *pin = 424242; 145 qs = CHALLENGERDB_do_challenge_address (pg, 146 nonce, 147 address, 148 GNUNET_TIME_UNIT_ZERO, 149 pin, 150 &state, 151 &last_tx_time, 152 &auth_attempts_left, 153 &pin_transmissions_left, 154 &pin_transmit, 155 &redirect_uri, 156 &address_refused, 157 &solved); 158 json_decref (address); 159 /* The TAN is only pending until its transmission is confirmed; this 160 stands in for a successful AUTH_COMMAND run. */ 161 qs = CHALLENGERDB_do_challenge_address_confirm_pin (pg, 162 nonce, 163 &auth_attempts_left); 164 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) 165 { 166 GNUNET_break (0); 167 return GNUNET_SYSERR; 168 } 169 GNUNET_free (state); 170 GNUNET_free (redirect_uri); 171 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) || 172 (! pin_transmit) || 173 address_refused || 174 solved) 175 { 176 GNUNET_break (0); 177 return GNUNET_SYSERR; 178 } 179 return GNUNET_OK; 180 } 181 182 183 /** 184 * Enter @a pin for the validation under @a nonce and check it was accepted. 185 * 186 * @param nonce validation to solve 187 * @param pin TAN to enter 188 * @return #GNUNET_OK on success 189 */ 190 static enum GNUNET_GenericReturnValue 191 solve_validation (const struct CHALLENGER_ValidationNonceP *nonce, 192 uint32_t pin) 193 { 194 char *state = NULL; 195 char *redirect_uri = NULL; 196 uint32_t addr_left; 197 uint32_t auth_attempts_left; 198 uint32_t pin_transmissions_left; 199 bool solved; 200 bool exhausted; 201 bool no_challenge; 202 enum GNUNET_DB_QueryStatus qs; 203 204 qs = CHALLENGERDB_do_solve_challenge (pg, 205 nonce, 206 pin, 207 &solved, 208 &exhausted, 209 &no_challenge, 210 &state, 211 &addr_left, 212 &auth_attempts_left, 213 &pin_transmissions_left, 214 &redirect_uri); 215 GNUNET_free (state); 216 GNUNET_free (redirect_uri); 217 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) || 218 (! solved) || 219 exhausted || 220 no_challenge) 221 { 222 GNUNET_break (0); 223 return GNUNET_SYSERR; 224 } 225 return GNUNET_OK; 226 } 227 228 229 /** 230 * Mint an access token for the validation under @a nonce. 231 * 232 * @param client client redeeming the authorization code 233 * @param nonce validation to redeem 234 * @param[out] token set to the (random) access token we tried to store 235 * @return transaction status of CHALLENGERDB_do_insert_token() 236 */ 237 static enum GNUNET_DB_QueryStatus 238 insert_token (uint64_t client, 239 const struct CHALLENGER_ValidationNonceP *nonce, 240 struct CHALLENGER_AccessTokenP *token) 241 { 242 GNUNET_CRYPTO_random_block (token, 243 sizeof (*token)); 244 return CHALLENGERDB_do_insert_token (pg, 245 nonce, 246 client, 247 token, 248 GNUNET_TIME_UNIT_HOURS, 249 GNUNET_TIME_UNIT_DAYS); 250 } 251 252 253 /** 254 * Test that a validation for which the user never entered the correct 255 * TAN cannot be redeemed for an access token, and is not even visible to 256 * the ``/token`` lookup. Without the ``auth_attempts_left < 0`` guard 257 * anyone able to compute the authorization code could mint an 258 * attestation for an address nobody ever proved control over. 259 * 260 * @return #GNUNET_OK on success 261 */ 262 static enum GNUNET_GenericReturnValue 263 test_unsolved_not_redeemable (void) 264 { 265 struct CHALLENGER_ValidationNonceP nonce; 266 struct CHALLENGER_AccessTokenP token; 267 uint32_t pin; 268 269 if (GNUNET_OK != 270 challenge_validation (&nonce, 271 &pin)) 272 return GNUNET_SYSERR; 273 { 274 char *client_secret; 275 json_t *address; 276 char *client_scope; 277 char *client_state; 278 char *client_redirect_uri; 279 char *code_challenge; 280 uint32_t code_challenge_method; 281 282 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 283 CHALLENGERDB_get_validation_pkce (pg, 284 &nonce, 285 client_id, 286 &client_secret, 287 &address, 288 &client_scope, 289 &client_state, 290 &client_redirect_uri, 291 &code_challenge, 292 &code_challenge_method)) 293 { 294 GNUNET_break (0); 295 return GNUNET_SYSERR; 296 } 297 } 298 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 299 insert_token (client_id, 300 &nonce, 301 &token)) 302 { 303 GNUNET_break (0); 304 return GNUNET_SYSERR; 305 } 306 return GNUNET_OK; 307 } 308 309 310 /** 311 * Test that a solved validation is redeemable, and redeemable exactly 312 * once (the authorization code must not be replayable). 313 * 314 * @return #GNUNET_OK on success 315 */ 316 static enum GNUNET_GenericReturnValue 317 test_solved_redeemable (void) 318 { 319 struct CHALLENGER_ValidationNonceP nonce; 320 struct CHALLENGER_AccessTokenP token; 321 uint32_t pin; 322 323 if ( (GNUNET_OK != 324 challenge_validation (&nonce, 325 &pin)) || 326 (GNUNET_OK != 327 solve_validation (&nonce, 328 pin)) ) 329 return GNUNET_SYSERR; 330 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 331 insert_token (client_id, 332 &nonce, 333 &token)) 334 { 335 GNUNET_break (0); 336 return GNUNET_SYSERR; 337 } 338 /* replay: the validation was consumed, so this must not mint a token */ 339 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 340 insert_token (client_id, 341 &nonce, 342 &token)) 343 { 344 GNUNET_break (0); 345 return GNUNET_SYSERR; 346 } 347 return GNUNET_OK; 348 } 349 350 351 /** 352 * Test that the address expiration stored with a freshly minted token is 353 * in the future, and in particular that it does *not* depend on the 354 * validation's ``last_tx_time``. The regression this guards against 355 * computed the expiration as ``address_expiration + last_tx_time``, which 356 * lands in 1970 whenever that column was never written. We force the 357 * column back to 0 to pin the property down without relying on any 358 * particular code path leaving it there. 359 * 360 * @return #GNUNET_OK on success 361 */ 362 static enum GNUNET_GenericReturnValue 363 test_address_expiry_is_in_the_future (void) 364 { 365 struct GNUNET_PQ_ExecuteStatement es[] = { 366 GNUNET_PQ_make_execute ("UPDATE validations SET last_tx_time=0;"), 367 GNUNET_PQ_EXECUTE_STATEMENT_END 368 }; 369 struct CHALLENGER_ValidationNonceP nonce; 370 struct CHALLENGER_AccessTokenP token; 371 struct GNUNET_TIME_Timestamp address_expiration; 372 struct GNUNET_TIME_Absolute now; 373 json_t *address = NULL; 374 uint64_t rowid; 375 uint32_t pin; 376 enum GNUNET_GenericReturnValue ret; 377 378 if ( (GNUNET_OK != 379 challenge_validation (&nonce, 380 &pin)) || 381 (GNUNET_OK != 382 solve_validation (&nonce, 383 pin)) ) 384 return GNUNET_SYSERR; 385 if (GNUNET_OK != 386 GNUNET_PQ_exec_statements (pg->conn, 387 es)) 388 { 389 GNUNET_break (0); 390 return GNUNET_SYSERR; 391 } 392 now = GNUNET_TIME_absolute_get (); 393 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 394 insert_token (client_id, 395 &nonce, 396 &token)) 397 { 398 GNUNET_break (0); 399 return GNUNET_SYSERR; 400 } 401 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 402 CHALLENGERDB_get_token (pg, 403 &token, 404 &rowid, 405 &address, 406 &address_expiration)) 407 { 408 GNUNET_break (0); 409 return GNUNET_SYSERR; 410 } 411 ret = GNUNET_OK; 412 if (address_expiration.abs_time.abs_value_us <= now.abs_value_us) 413 { 414 GNUNET_break (0); 415 ret = GNUNET_SYSERR; 416 } 417 json_decref (address); 418 return ret; 419 } 420 421 422 /** 423 * Test that an expired validation is not consumable, even though the 424 * caller (``/token``) checked the expiration in an earlier, separate 425 * transaction. Everything get_validation_pkce() filters on has to be 426 * repeated by do_insert_token(), or the gap between the two statements is 427 * an unguarded TOCTOU window. 428 * 429 * @return #GNUNET_OK on success 430 */ 431 static enum GNUNET_GenericReturnValue 432 test_expired_not_redeemable (void) 433 { 434 struct GNUNET_PQ_ExecuteStatement es[] = { 435 GNUNET_PQ_make_execute ("UPDATE validations SET expiration_time=1;"), 436 GNUNET_PQ_EXECUTE_STATEMENT_END 437 }; 438 struct CHALLENGER_ValidationNonceP nonce; 439 struct CHALLENGER_AccessTokenP token; 440 uint32_t pin; 441 442 if ( (GNUNET_OK != 443 challenge_validation (&nonce, 444 &pin)) || 445 (GNUNET_OK != 446 solve_validation (&nonce, 447 pin)) ) 448 return GNUNET_SYSERR; 449 if (GNUNET_OK != 450 GNUNET_PQ_exec_statements (pg->conn, 451 es)) 452 { 453 GNUNET_break (0); 454 return GNUNET_SYSERR; 455 } 456 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 457 insert_token (client_id, 458 &nonce, 459 &token)) 460 { 461 GNUNET_break (0); 462 return GNUNET_SYSERR; 463 } 464 return GNUNET_OK; 465 } 466 467 468 /** 469 * Test that a validation cannot be consumed by a client it does not 470 * belong to. 471 * 472 * @return #GNUNET_OK on success 473 */ 474 static enum GNUNET_GenericReturnValue 475 test_foreign_client_not_redeemable (void) 476 { 477 struct CHALLENGER_ValidationNonceP nonce; 478 struct CHALLENGER_AccessTokenP token; 479 uint32_t pin; 480 481 if ( (GNUNET_OK != 482 challenge_validation (&nonce, 483 &pin)) || 484 (GNUNET_OK != 485 solve_validation (&nonce, 486 pin)) ) 487 return GNUNET_SYSERR; 488 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 489 insert_token (client_id + 1, 490 &nonce, 491 &token)) 492 { 493 GNUNET_break (0); 494 return GNUNET_SYSERR; 495 } 496 /* ... and the rightful client still can */ 497 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 498 insert_token (client_id, 499 &nonce, 500 &token)) 501 { 502 GNUNET_break (0); 503 return GNUNET_SYSERR; 504 } 505 return GNUNET_OK; 506 } 507 508 509 /** 510 * Run @a sql directly on the database, bypassing the CHALLENGERDB API. 511 * Used to create states (and to make assertions about the schema) that 512 * the API deliberately cannot produce. 513 * 514 * @param sql SQL statement to execute 515 * @return #GNUNET_OK on success 516 */ 517 static enum GNUNET_GenericReturnValue 518 exec_sql (const char *sql) 519 { 520 struct GNUNET_PQ_ExecuteStatement es[] = { 521 GNUNET_PQ_make_execute (sql), 522 GNUNET_PQ_EXECUTE_STATEMENT_END 523 }; 524 525 return GNUNET_PQ_exec_statements (pg->conn, 526 es); 527 } 528 529 530 /** 531 * Test that a client cannot be inserted silently: a URI that is already 532 * registered must be reported as such, and any *other* unique violation 533 * (notably one on the primary key, which happens once the identity sequence 534 * of 'clients' lags behind max(client_serial_id)) must not be misreported as 535 * a duplicate URI. 536 * 537 * @return #GNUNET_OK on success 538 */ 539 static enum GNUNET_GenericReturnValue 540 test_insert_client (void) 541 { 542 uint64_t nclient_id; 543 bool uri_taken; 544 545 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 546 CHALLENGERDB_insert_client (pg, 547 "https://example.com/a", 548 "secret-token:a", 549 &nclient_id, 550 &uri_taken)) 551 { 552 GNUNET_break (0); 553 return GNUNET_SYSERR; 554 } 555 if (uri_taken) 556 { 557 GNUNET_break (0); 558 return GNUNET_SYSERR; 559 } 560 /* Same URI again: this one really is a duplicate. */ 561 if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 562 CHALLENGERDB_insert_client (pg, 563 "https://example.com/a", 564 "secret-token:b", 565 &nclient_id, 566 &uri_taken)) || 567 (! uri_taken) ) 568 { 569 GNUNET_break (0); 570 return GNUNET_SYSERR; 571 } 572 /* Rewind the identity sequence, as a restore that did not restore the 573 sequences leaves it: the next INSERT then collides on the primary key, 574 not on the URI. */ 575 if (GNUNET_OK != 576 exec_sql ("DO $$ BEGIN" 577 " PERFORM setval(" 578 " pg_get_serial_sequence('challenger.clients'," 579 " 'client_serial_id')," 580 " (SELECT MIN(client_serial_id) FROM challenger.clients)," 581 " false);" 582 "END $$;")) 583 { 584 GNUNET_break (0); 585 return GNUNET_SYSERR; 586 } 587 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 588 CHALLENGERDB_insert_client (pg, 589 "https://example.com/b", 590 "secret-token:b", 591 &nclient_id, 592 &uri_taken)) 593 { 594 /* The PK collision must not go unnoticed. */ 595 GNUNET_break (0); 596 return GNUNET_SYSERR; 597 } 598 if (uri_taken) 599 { 600 /* This is the regression: the failure has nothing to do with the URI, 601 and the operator must not be told that the URI already exists. */ 602 GNUNET_break (0); 603 return GNUNET_SYSERR; 604 } 605 /* Repair the sequence, then the very same insert must work. */ 606 if (GNUNET_OK != 607 exec_sql ("DO $$ BEGIN" 608 " PERFORM setval(" 609 " pg_get_serial_sequence('challenger.clients'," 610 " 'client_serial_id')," 611 " (SELECT MAX(client_serial_id) FROM challenger.clients)," 612 " true);" 613 "END $$;")) 614 { 615 GNUNET_break (0); 616 return GNUNET_SYSERR; 617 } 618 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 619 CHALLENGERDB_insert_client (pg, 620 "https://example.com/b", 621 "secret-token:b", 622 &nclient_id, 623 &uri_taken)) || 624 (uri_taken) ) 625 { 626 GNUNET_break (0); 627 return GNUNET_SYSERR; 628 } 629 return GNUNET_OK; 630 } 631 632 633 /** 634 * Test that deleting a client reports how many validations it took with it: 635 * validations_client_serial_id_fkey cascades, so an operator would otherwise 636 * abort in-flight KYC processes without being told. 637 * 638 * @return #GNUNET_OK on success 639 */ 640 static enum GNUNET_GenericReturnValue 641 test_delete_client (void) 642 { 643 const char *uri = "https://example.com/del"; 644 const char *secret = "secret-token:del"; 645 struct GNUNET_TIME_Absolute expiration 646 = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS); 647 uint64_t nclient_id; 648 uint64_t validations_deleted; 649 bool uri_taken; 650 651 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 652 CHALLENGERDB_insert_client (pg, 653 uri, 654 secret, 655 &nclient_id, 656 &uri_taken)) 657 { 658 GNUNET_break (0); 659 return GNUNET_SYSERR; 660 } 661 for (unsigned int i = 0; i < 2; i++) 662 { 663 struct CHALLENGER_ValidationNonceP nonce; 664 665 GNUNET_CRYPTO_random_block (&nonce, 666 sizeof (nonce)); 667 if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 668 CHALLENGERDB_do_insert_validation (pg, 669 nclient_id, 670 secret, 671 &nonce, 672 expiration, 673 NULL)) 674 { 675 GNUNET_break (0); 676 return GNUNET_SYSERR; 677 } 678 } 679 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 680 CHALLENGERDB_delete_client (pg, 681 uri, 682 &validations_deleted)) || 683 (2 != validations_deleted) ) 684 { 685 GNUNET_break (0); 686 return GNUNET_SYSERR; 687 } 688 /* Deleting it again finds nothing and discards nothing. */ 689 if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 690 CHALLENGERDB_delete_client (pg, 691 uri, 692 &validations_deleted)) || 693 (0 != validations_deleted) ) 694 { 695 GNUNET_break (0); 696 return GNUNET_SYSERR; 697 } 698 return GNUNET_OK; 699 } 700 701 702 /** 703 * Main function that will be run by the scheduler. 704 * 705 * @param cls closure with config 706 */ 707 static void 708 run (void *cls) 709 { 710 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 711 712 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 713 "Connecting\n"); 714 if (NULL == (pg = CHALLENGERDB_connect_admin (cfg))) 715 { 716 result = 77; 717 return; 718 } 719 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 720 "Connected\n"); 721 if (GNUNET_OK != 722 CHALLENGERDB_drop_tables (pg)) 723 { 724 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 725 "Dropping tables failed\n"); 726 } 727 if (GNUNET_OK != 728 CHALLENGERDB_create_tables (pg)) 729 { 730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 731 "Creating tables failed\n"); 732 goto drop; 733 } 734 GNUNET_assert (GNUNET_OK == 735 CHALLENGERDB_preflight (pg)); 736 { 737 struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get (); 738 739 FAILIF (0 > 740 CHALLENGERDB_gc (pg, 741 ts)); 742 } 743 FAILIF (GNUNET_OK != 744 setup_client ()); 745 FAILIF (GNUNET_OK != 746 test_unsolved_not_redeemable ()); 747 FAILIF (GNUNET_OK != 748 test_solved_redeemable ()); 749 FAILIF (GNUNET_OK != 750 test_address_expiry_is_in_the_future ()); 751 FAILIF (GNUNET_OK != 752 test_expired_not_redeemable ()); 753 FAILIF (GNUNET_OK != 754 test_foreign_client_not_redeemable ()); 755 FAILIF (GNUNET_OK != 756 test_insert_client ()); 757 FAILIF (GNUNET_OK != 758 test_delete_client ()); 759 result = 0; 760 drop: 761 GNUNET_break (GNUNET_OK == 762 CHALLENGERDB_drop_tables (pg)); 763 CHALLENGERDB_disconnect (pg); 764 pg = NULL; 765 } 766 767 768 int 769 main (int argc, 770 char *const argv[]) 771 { 772 struct GNUNET_CONFIGURATION_Handle *cfg; 773 774 (void) argc; 775 result = EXIT_FAILURE; 776 GNUNET_log_setup (argv[0], 777 "DEBUG", 778 NULL); 779 cfg = GNUNET_CONFIGURATION_create (CHALLENGER_project_data ()); 780 if (GNUNET_OK != 781 GNUNET_CONFIGURATION_parse (cfg, 782 "test_challenger_db_postgres.conf")) 783 { 784 GNUNET_break (0); 785 return EXIT_NOTCONFIGURED; 786 } 787 GNUNET_SCHEDULER_run (&run, cfg); 788 GNUNET_CONFIGURATION_destroy (cfg); 789 return result; 790 } 791 792 793 /* end of test_challenger_db.c */