test_auditordb.c (21088B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2016--2022 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 auditordb/test_auditordb.c 18 * @brief test cases for DB interaction functions 19 * @author Gabor X Toth 20 * @author Christian Grothoff 21 */ 22 #include <gnunet/gnunet_db_lib.h> 23 #include "auditordb_lib.h" 24 #include "auditor-database/create_tables.h" 25 #include "auditor-database/delete_reserve_info.h" 26 #include "auditor-database/delete_auditor_closure_lag.h" 27 #include "auditor-database/drop_tables.h" 28 #include "auditor-database/gc.h" 29 #include "auditor-database/get_denomination_balance.h" 30 #include "auditor-database/get_exists_historic_denom_revenue.h" 31 #include "auditor-database/get_reserve_info.h" 32 #include "auditor-database/insert_auditor_closure_lags.h" 33 #include "auditor-database/insert_denomination_balance.h" 34 #include "auditor-database/insert_historic_denom_revenue.h" 35 #include "auditor-database/insert_historic_reserve_revenue.h" 36 #include "auditor-database/insert_reserve_info.h" 37 #include "auditor-database/preflight.h" 38 #include "auditor-database/iterate_historic_denom_revenue.h" 39 #include "auditor-database/iterate_historic_reserve_revenue.h" 40 #include "auditor-database/start.h" 41 #include "auditor-database/update_denomination_balance.h" 42 #include "auditor-database/update_reserve_info.h" 43 44 /** 45 * Currency we use, must match CURRENCY in "test-auditor-db-postgres.conf". 46 */ 47 #define CURRENCY "EUR" 48 49 /** 50 * Report line of error if @a cond is true, and jump to label "drop". 51 */ 52 #define FAILIF(cond) \ 53 do { \ 54 if (! (cond)) { break;} \ 55 GNUNET_break (0); \ 56 goto drop; \ 57 } while (0) 58 59 /** 60 * Initializes @a ptr with random data. 61 */ 62 #define RND_BLK(ptr) \ 63 GNUNET_CRYPTO_random_block (ptr, sizeof (* \ 64 ptr)) 65 66 /** 67 * Initializes @a ptr with zeros. 68 */ 69 #define ZR_BLK(ptr) \ 70 memset (ptr, 0, sizeof (*ptr)) 71 72 73 /** 74 * Global result from the testcase. 75 */ 76 static int result = -1; 77 78 /** 79 * Hash of denomination public key. 80 */ 81 static struct TALER_DenominationHashP denom_pub_hash; 82 83 /** 84 * Another hash of a denomination public key. 85 */ 86 static struct TALER_DenominationHashP rnd_hash; 87 88 /** 89 * Current time. 90 */ 91 static struct GNUNET_TIME_Timestamp now; 92 93 /** 94 * Timestamp in the past. 95 */ 96 static struct GNUNET_TIME_Timestamp past; 97 98 /** 99 * Timestamp in the future. 100 */ 101 static struct GNUNET_TIME_Timestamp future; 102 103 /** 104 * Database under test. 105 */ 106 static struct TALER_AUDITORDB_PostgresContext *pg; 107 108 /** 109 * Historic denomination revenue value. 110 */ 111 static struct TALER_Amount rbalance; 112 113 /** 114 * Historic denomination loss value. 115 */ 116 static struct TALER_Amount rloss; 117 118 /** 119 * Reserve profit value we are using. 120 */ 121 static struct TALER_Amount reserve_profits; 122 123 124 static enum GNUNET_GenericReturnValue 125 select_historic_denom_revenue_result ( 126 void *cls, 127 uint64_t rowid, 128 const struct TALER_DenominationHashP *denom_pub_hash2, 129 struct GNUNET_TIME_Timestamp revenue_timestamp2, 130 const struct TALER_Amount *revenue_balance2, 131 const struct TALER_Amount *loss2) 132 { 133 static int n = 0; 134 135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 136 "select_historic_denom_revenue_result: row %u\n", n); 137 138 if ( (3 <= n++) 139 || (cls != NULL) 140 || ((0 != GNUNET_memcmp (&revenue_timestamp2, 141 &past)) 142 && (0 != GNUNET_memcmp (&revenue_timestamp2, 143 &now))) 144 || ((0 != GNUNET_memcmp (denom_pub_hash2, 145 &denom_pub_hash)) 146 && (0 != GNUNET_memcmp (denom_pub_hash2, 147 &rnd_hash))) 148 || (0 != TALER_amount_cmp (revenue_balance2, 149 &rbalance)) 150 || (0 != TALER_amount_cmp (loss2, 151 &rloss))) 152 { 153 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 154 "select_historic_denom_revenue_result: result does not match\n") 155 ; 156 GNUNET_break (0); 157 return GNUNET_SYSERR; 158 } 159 return GNUNET_OK; 160 } 161 162 163 static enum GNUNET_GenericReturnValue 164 select_historic_reserve_revenue_result ( 165 void *cls, 166 uint64_t rowid, 167 struct GNUNET_TIME_Timestamp start_time2, 168 struct GNUNET_TIME_Timestamp end_time2, 169 const struct TALER_Amount *reserve_profits2) 170 { 171 static int n = 0; 172 173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 174 "select_historic_reserve_revenue_result: row %u\n", n); 175 176 if ((2 <= n++) 177 || (cls != NULL) 178 || ((0 != GNUNET_memcmp (&start_time2, 179 &past)) 180 && (0 != GNUNET_memcmp (&start_time2, 181 &now))) 182 || (0 != GNUNET_memcmp (&end_time2, 183 &future)) 184 || (0 != TALER_amount_cmp (reserve_profits2, 185 &reserve_profits))) 186 { 187 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 188 "select_historic_reserve_revenue_result: result does not match\n"); 189 GNUNET_break (0); 190 return GNUNET_SYSERR; 191 } 192 return GNUNET_OK; 193 } 194 195 196 /** 197 * Main function that will be run by the scheduler. 198 * 199 * @param cls closure with config 200 */ 201 static void 202 run (void *cls) 203 { 204 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 205 uint64_t rowid; 206 struct TALER_Amount value; 207 struct TALER_Amount fee_withdraw; 208 struct TALER_Amount fee_deposit; 209 struct TALER_Amount fee_refresh; 210 struct TALER_Amount fee_refund; 211 struct TALER_ReservePublicKeyP reserve_pub; 212 struct TALER_DenominationPrivateKey denom_priv; 213 struct TALER_DenominationPublicKey denom_pub; 214 struct GNUNET_TIME_Timestamp date; 215 216 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 217 "connecting to database\n"); 218 219 if (NULL == 220 (pg = TALER_AUDITORDB_connect (cfg))) 221 { 222 result = 77; 223 return; 224 } 225 GNUNET_assert (GNUNET_OK == 226 TALER_AUDITORDB_preflight (pg)); 227 (void) TALER_AUDITORDB_drop_tables (pg, 228 GNUNET_YES); 229 if (GNUNET_OK != 230 TALER_AUDITORDB_create_tables (pg, 231 false, 232 0)) 233 { 234 result = 77; 235 goto unload; 236 } 237 if (GNUNET_SYSERR == 238 TALER_AUDITORDB_preflight (pg)) 239 { 240 result = 77; 241 goto drop; 242 } 243 244 FAILIF (GNUNET_OK != 245 TALER_AUDITORDB_start (pg, 246 "test-auditordb")); 247 248 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 249 "initializing\n"); 250 251 GNUNET_assert (GNUNET_OK == 252 TALER_string_to_amount (CURRENCY ":1.000010", 253 &value)); 254 GNUNET_assert (GNUNET_OK == 255 TALER_string_to_amount (CURRENCY ":0.000011", 256 &fee_withdraw)); 257 GNUNET_assert (GNUNET_OK == 258 TALER_string_to_amount (CURRENCY ":0.000012", 259 &fee_deposit)); 260 GNUNET_assert (GNUNET_OK == 261 TALER_string_to_amount (CURRENCY ":0.000013", 262 &fee_refresh)); 263 GNUNET_assert (GNUNET_OK == 264 TALER_string_to_amount (CURRENCY ":0.000014", 265 &fee_refund)); 266 RND_BLK (&reserve_pub); 267 RND_BLK (&rnd_hash); 268 GNUNET_assert (GNUNET_OK == 269 TALER_denom_priv_create (&denom_priv, 270 &denom_pub, 271 GNUNET_CRYPTO_BSA_RSA, 272 1024)); 273 TALER_denom_pub_hash (&denom_pub, 274 &denom_pub_hash); 275 TALER_denom_priv_free (&denom_priv); 276 TALER_denom_pub_free (&denom_pub); 277 278 now = GNUNET_TIME_timestamp_get (); 279 past = GNUNET_TIME_absolute_to_timestamp ( 280 GNUNET_TIME_absolute_subtract (now.abs_time, 281 GNUNET_TIME_relative_multiply ( 282 GNUNET_TIME_UNIT_HOURS, 283 4))); 284 future = GNUNET_TIME_absolute_to_timestamp ( 285 GNUNET_TIME_absolute_add (now.abs_time, 286 GNUNET_TIME_relative_multiply ( 287 GNUNET_TIME_UNIT_HOURS, 288 4))); 289 290 { 291 struct TALER_AUDITORDB_ReserveFeeBalance rfb; 292 struct TALER_AUDITORDB_ReserveFeeBalance rfb2; 293 294 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 295 "Test: insert_reserve_info\n"); 296 GNUNET_assert (GNUNET_OK == 297 TALER_string_to_amount (CURRENCY ":12.345678", 298 &rfb.reserve_balance)); 299 GNUNET_assert (GNUNET_OK == 300 TALER_string_to_amount (CURRENCY ":11.245678", 301 &rfb.reserve_loss)); 302 GNUNET_assert (GNUNET_OK == 303 TALER_string_to_amount (CURRENCY ":23.456789", 304 &rfb.withdraw_fee_balance)); 305 GNUNET_assert (GNUNET_OK == 306 TALER_string_to_amount (CURRENCY ":23.456719", 307 &rfb.close_fee_balance)); 308 GNUNET_assert (GNUNET_OK == 309 TALER_string_to_amount (CURRENCY ":33.456789", 310 &rfb.purse_fee_balance)); 311 GNUNET_assert (GNUNET_OK == 312 TALER_string_to_amount (CURRENCY ":43.456789", 313 &rfb.open_fee_balance)); 314 GNUNET_assert (GNUNET_OK == 315 TALER_string_to_amount (CURRENCY ":53.456789", 316 &rfb.history_fee_balance)); 317 { 318 struct TALER_FullPayto pt = { 319 .full_payto = (char *) "payto://bla/blub?receiver-name=blub" 320 }; 321 322 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 323 TALER_AUDITORDB_insert_reserve_info (pg, 324 &reserve_pub, 325 &rfb, 326 past, 327 pt)); 328 } 329 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 330 "Test: update_reserve_info\n"); 331 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 332 TALER_AUDITORDB_update_reserve_info (pg, 333 &reserve_pub, 334 &rfb, 335 future)); 336 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 337 "Test: get_reserve_info\n"); 338 { 339 struct TALER_FullPayto payto; 340 341 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 342 TALER_AUDITORDB_get_reserve_info (pg, 343 &reserve_pub, 344 &rowid, 345 &rfb2, 346 &date, 347 &payto)); 348 FAILIF (0 != strcmp (payto.full_payto, 349 "payto://bla/blub?receiver-name=blub")); 350 GNUNET_free (payto.full_payto); 351 } 352 FAILIF ( (0 != GNUNET_memcmp (&date, 353 &future)) 354 || (0 != TALER_amount_cmp (&rfb2.reserve_balance, 355 &rfb.reserve_balance)) 356 || (0 != TALER_amount_cmp (&rfb2.withdraw_fee_balance, 357 &rfb.withdraw_fee_balance)) 358 || (0 != TALER_amount_cmp (&rfb2.close_fee_balance, 359 &rfb.close_fee_balance)) 360 || (0 != TALER_amount_cmp (&rfb2.purse_fee_balance, 361 &rfb.purse_fee_balance)) 362 || (0 != TALER_amount_cmp (&rfb2.open_fee_balance, 363 &rfb.open_fee_balance)) 364 || (0 != TALER_amount_cmp (&rfb2.history_fee_balance, 365 &rfb.history_fee_balance)) 366 ); 367 } 368 369 { 370 struct TALER_AUDITORDB_ClosureLags cl = { 371 .problem_row_id = 42 372 }; 373 374 GNUNET_assert (GNUNET_OK == 375 TALER_string_to_amount (CURRENCY ":12.345678", 376 &cl.amount)); 377 cl.account.full_payto 378 = (char *) "payto://unspec/foo?receiver-name=bar"; 379 memset (&cl.wtid, 380 42, 381 sizeof (cl.wtid)); 382 cl.deadline = GNUNET_TIME_absolute_get (); 383 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 384 TALER_AUDITORDB_delete_auditor_closure_lag (pg, 385 &cl.amount, 386 &cl.wtid, 387 cl.account)); 388 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 389 TALER_AUDITORDB_insert_auditor_closure_lags (pg, 390 &cl)); 391 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 392 TALER_AUDITORDB_delete_auditor_closure_lag (pg, 393 &cl.amount, 394 &cl.wtid, 395 cl.account)); 396 } 397 398 { 399 struct TALER_AUDITORDB_DenominationCirculationData dcd; 400 struct TALER_AUDITORDB_DenominationCirculationData dcd2; 401 402 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 403 "Test: insert_denomination_balance\n"); 404 GNUNET_assert (GNUNET_OK == 405 TALER_string_to_amount (CURRENCY ":12.345678", 406 &dcd.denom_balance)); 407 GNUNET_assert (GNUNET_OK == 408 TALER_string_to_amount (CURRENCY ":0.1", 409 &dcd.denom_loss)); 410 GNUNET_assert (GNUNET_OK == 411 TALER_string_to_amount (CURRENCY ":13.57986", 412 &dcd.denom_risk)); 413 GNUNET_assert (GNUNET_OK == 414 TALER_string_to_amount (CURRENCY ":12.57986", 415 &dcd.recoup_loss)); 416 dcd.num_issued = 62; 417 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 418 TALER_AUDITORDB_insert_denomination_balance (pg, 419 &denom_pub_hash, 420 &dcd)); 421 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 422 "Test: update_denomination_balance\n"); 423 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 424 TALER_AUDITORDB_update_denomination_balance (pg, 425 &denom_pub_hash, 426 &dcd)); 427 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 428 "Test: get_denomination_balance\n"); 429 430 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 431 TALER_AUDITORDB_get_denomination_balance (pg, 432 &denom_pub_hash, 433 &dcd2)); 434 FAILIF (0 != TALER_amount_cmp (&dcd2.denom_balance, 435 &dcd.denom_balance)); 436 FAILIF (0 != TALER_amount_cmp (&dcd2.denom_loss, 437 &dcd.denom_loss)); 438 FAILIF (0 != TALER_amount_cmp (&dcd2.denom_risk, 439 &dcd.denom_risk)); 440 FAILIF (0 != TALER_amount_cmp (&dcd2.recoup_loss, 441 &dcd.recoup_loss)); 442 FAILIF (dcd2.num_issued != dcd.num_issued); 443 } 444 445 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 446 "Test: insert_historic_denom_revenue\n"); 447 GNUNET_assert (GNUNET_OK == 448 TALER_string_to_amount (CURRENCY ":12.345678", 449 &rbalance)); 450 GNUNET_assert (GNUNET_OK == 451 TALER_string_to_amount (CURRENCY ":23.456789", 452 &rloss)); 453 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 454 TALER_AUDITORDB_insert_historic_denom_revenue (pg, 455 &denom_pub_hash, 456 past, 457 &rbalance, 458 &rloss)); 459 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 460 TALER_AUDITORDB_insert_historic_denom_revenue (pg, 461 &rnd_hash, 462 now, 463 &rbalance, 464 &rloss)); 465 /* The table is append-only: a denomination that is credited after it was 466 booked as finished gets another row instead of an update. */ 467 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 468 TALER_AUDITORDB_insert_historic_denom_revenue (pg, 469 &denom_pub_hash, 470 now, 471 &rbalance, 472 &rloss)); 473 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 474 "Test: get_exists_historic_denom_revenue\n"); 475 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 476 TALER_AUDITORDB_get_exists_historic_denom_revenue (pg, 477 &denom_pub_hash)); 478 { 479 struct TALER_DenominationHashP unknown_hash; 480 481 RND_BLK (&unknown_hash); 482 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 483 TALER_AUDITORDB_get_exists_historic_denom_revenue ( 484 pg, 485 &unknown_hash)); 486 } 487 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 488 "Test: select_historic_denom_revenue\n"); 489 FAILIF (0 >= 490 TALER_AUDITORDB_iterate_historic_denom_revenue ( 491 pg, 492 1024, /* limit */ 493 0, /* offset */ 494 &select_historic_denom_revenue_result, 495 NULL)); 496 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 497 "Test: insert_historic_reserve_revenue\n"); 498 GNUNET_assert (GNUNET_OK == 499 TALER_string_to_amount (CURRENCY ":56.789012", 500 &reserve_profits)); 501 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 502 TALER_AUDITORDB_insert_historic_reserve_revenue (pg, 503 past, 504 future, 505 &reserve_profits)); 506 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 507 TALER_AUDITORDB_insert_historic_reserve_revenue (pg, 508 now, 509 future, 510 &reserve_profits)); 511 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 512 "Test: select_historic_reserve_revenue\n"); 513 FAILIF (0 >= 514 TALER_AUDITORDB_iterate_historic_reserve_revenue ( 515 pg, 516 1024, /* limit */ 517 0, /* offset */ 518 &select_historic_reserve_revenue_result, 519 NULL)); 520 521 FAILIF (0 > 522 TALER_AUDITORDB_commit (pg)); 523 524 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 525 TALER_AUDITORDB_delete_reserve_info (pg, 526 &reserve_pub)); 527 528 #if GC_IMPLEMENTED 529 FAILIF (GNUNET_OK != 530 TALER_AUDITORDB_gc (pg)); 531 #endif 532 533 result = 0; 534 535 drop: 536 TALER_AUDITORDB_rollback (pg); 537 GNUNET_break (GNUNET_OK == 538 TALER_AUDITORDB_drop_tables (pg, 539 GNUNET_YES)); 540 unload: 541 TALER_AUDITORDB_disconnect (pg); 542 pg = NULL; 543 } 544 545 546 int 547 main (int argc, 548 char *const argv[]) 549 { 550 struct GNUNET_CONFIGURATION_Handle *cfg; 551 552 (void) argc; 553 result = -1; 554 GNUNET_log_setup (argv[0], 555 "WARNING", 556 NULL); 557 cfg = GNUNET_CONFIGURATION_create (TALER_AUDITOR_project_data ()); 558 if (GNUNET_OK != 559 GNUNET_CONFIGURATION_parse (cfg, 560 "test-auditor-db-postgres.conf")) 561 { 562 GNUNET_break (0); 563 return 2; 564 } 565 GNUNET_SCHEDULER_run (&run, 566 cfg); 567 GNUNET_CONFIGURATION_destroy (cfg); 568 return result; 569 }