test_exchange_p2p.c (18241B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014--2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 3, or 8 (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, see 17 <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file testing/test_exchange_p2p.c 21 * @brief testcase to test exchange's P2P payments 22 * @author Christian Grothoff 23 */ 24 #include "taler/taler_util.h" 25 #include "taler/taler_json_lib.h" 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_testing_lib.h> 28 #include <microhttpd.h> 29 #include "taler/taler_bank_service.h" 30 #include "taler/taler_testing_lib.h" 31 #include "taler/taler_extensions.h" 32 33 /** 34 * Configuration file we use. One (big) configuration is used 35 * for the various components for this test. 36 */ 37 static char *config_file; 38 39 /** 40 * Our credentials. 41 */ 42 struct TALER_TESTING_Credentials cred; 43 44 /** 45 * Some tests behave differently when using CS as we cannot 46 * reuse the coin private key for different denominations 47 * due to the derivation of it with the /csr values. Hence 48 * some tests behave differently in CS mode, hence this 49 * flag. 50 */ 51 static bool uses_cs; 52 53 /** 54 * Execute the taler-exchange-wirewatch command with 55 * our configuration file. 56 * 57 * @param label label to use for the command. 58 */ 59 #define CMD_EXEC_WIREWATCH(label) \ 60 TALER_TESTING_cmd_exec_wirewatch2 (label, config_file, \ 61 "exchange-account-2") 62 63 /** 64 * Execute the taler-exchange-aggregator, closer and transfer commands with 65 * our configuration file. 66 * 67 * @param label label to use for the command. 68 */ 69 #define CMD_EXEC_AGGREGATOR(label) \ 70 TALER_TESTING_cmd_sleep ("sleep-before-aggregator", 2), \ 71 TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \ 72 TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file) 73 74 75 /** 76 * Run wire transfer of funds from some user's account to the 77 * exchange. 78 * 79 * @param label label to use for the command. 80 * @param amount amount to transfer, i.e. "EUR:1" 81 */ 82 #define CMD_TRANSFER_TO_EXCHANGE(label,amount) \ 83 TALER_TESTING_cmd_admin_add_incoming (label, amount, \ 84 &cred.ba, \ 85 cred.user42_payto) 86 87 /** 88 * Main function that will tell the interpreter what commands to 89 * run. 90 * 91 * @param cls closure 92 * @param is interpreter we use to run commands 93 */ 94 static void 95 run (void *cls, 96 struct TALER_TESTING_Interpreter *is) 97 { 98 /** 99 * Test withdrawal plus spending. 100 */ 101 struct TALER_TESTING_Command withdraw[] = { 102 /** 103 * Move money to the exchange's bank account. 104 */ 105 CMD_TRANSFER_TO_EXCHANGE ( 106 "create-reserve-1", 107 "EUR:5.04"), 108 CMD_TRANSFER_TO_EXCHANGE ( 109 "create-reserve-2", 110 "EUR:5.01"), 111 TALER_TESTING_cmd_reserve_poll ( 112 "poll-reserve-1", 113 "create-reserve-1", 114 "EUR:5.04", 115 GNUNET_TIME_UNIT_MINUTES, 116 MHD_HTTP_OK), 117 TALER_TESTING_cmd_check_bank_admin_transfer ( 118 "check-create-reserve-1", 119 "EUR:5.04", 120 cred.user42_payto, 121 cred.exchange_payto, 122 "create-reserve-1"), 123 TALER_TESTING_cmd_check_bank_admin_transfer ( 124 "check-create-reserve-2", 125 "EUR:5.01", 126 cred.user42_payto, 127 cred.exchange_payto, 128 "create-reserve-2"), 129 /** 130 * Make a reserve exist, according to the previous 131 * transfer. 132 */ 133 CMD_EXEC_WIREWATCH ("wirewatch-1"), 134 TALER_TESTING_cmd_reserve_poll_finish ( 135 "finish-poll-reserve-1", 136 GNUNET_TIME_UNIT_SECONDS, 137 "poll-reserve-1"), 138 /** 139 * Withdraw EUR:5. 140 */ 141 TALER_TESTING_cmd_withdraw_amount ( 142 "withdraw-coin-1", 143 "create-reserve-1", 144 "EUR:5", 145 0, /* age restriction off */ 146 MHD_HTTP_OK), 147 /** 148 * Check the reserve is depleted. 149 */ 150 TALER_TESTING_cmd_status ( 151 "status-1", 152 "create-reserve-1", 153 "EUR:0.03", 154 MHD_HTTP_OK), 155 TALER_TESTING_cmd_end () 156 }; 157 struct TALER_TESTING_Command push[] = { 158 TALER_TESTING_cmd_purse_create_with_deposit ( 159 "purse-with-deposit-for-delete", 160 MHD_HTTP_OK, 161 "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", 162 true, /* upload contract */ 163 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 164 "withdraw-coin-1", 165 "EUR:1.01", 166 NULL), 167 TALER_TESTING_cmd_purse_delete ( 168 "purse-with-deposit-delete", 169 MHD_HTTP_NO_CONTENT, 170 "purse-with-deposit-for-delete"), 171 TALER_TESTING_cmd_purse_create_with_deposit ( 172 "purse-with-deposit", 173 MHD_HTTP_OK, 174 "{\"amount\":\"EUR:0.99\",\"summary\":\"ice cream\"}", 175 true, /* upload contract */ 176 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 177 "withdraw-coin-1", 178 "EUR:1.00", 179 NULL), 180 TALER_TESTING_cmd_purse_poll ( 181 "push-poll-purse-before-merge", 182 MHD_HTTP_OK, 183 "purse-with-deposit", 184 "EUR:0.99", 185 true, 186 GNUNET_TIME_UNIT_MINUTES), 187 TALER_TESTING_cmd_contract_get ( 188 "push-get-contract", 189 MHD_HTTP_OK, 190 true, /* for merge */ 191 "purse-with-deposit"), 192 TALER_TESTING_cmd_purse_merge ( 193 "purse-merge-into-reserve", 194 MHD_HTTP_OK, 195 "push-get-contract", 196 "create-reserve-1"), 197 TALER_TESTING_cmd_purse_poll_finish ( 198 "push-merge-purse-poll-finish", 199 GNUNET_TIME_relative_multiply ( 200 GNUNET_TIME_UNIT_SECONDS, 201 5), 202 "push-poll-purse-before-merge"), 203 TALER_TESTING_cmd_status ( 204 "push-check-post-merge-reserve-balance-get", 205 "create-reserve-1", 206 "EUR:1.02", 207 MHD_HTTP_OK), 208 /* POST history doesn't yet support P2P transfers */ 209 TALER_TESTING_cmd_reserve_history ( 210 "push-check-post-merge-reserve-balance-post", 211 "create-reserve-1", 212 "EUR:1.02", 213 MHD_HTTP_OK), 214 /* Test conflicting merge */ 215 TALER_TESTING_cmd_purse_merge ( 216 "purse-merge-into-reserve", 217 MHD_HTTP_CONFLICT, 218 "push-get-contract", 219 "create-reserve-2"), 220 221 TALER_TESTING_cmd_end () 222 }; 223 struct TALER_TESTING_Command pull[] = { 224 TALER_TESTING_cmd_purse_create_with_reserve ( 225 "purse-create-with-reserve", 226 MHD_HTTP_OK, 227 "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", 228 true /* upload contract */, 229 true /* pay purse fee */, 230 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 231 "create-reserve-1"), 232 TALER_TESTING_cmd_contract_get ( 233 "pull-get-contract", 234 MHD_HTTP_OK, 235 false, /* for deposit */ 236 "purse-create-with-reserve"), 237 TALER_TESTING_cmd_purse_poll ( 238 "pull-poll-purse-before-deposit", 239 MHD_HTTP_OK, 240 "purse-create-with-reserve", 241 "EUR:1", 242 false, 243 GNUNET_TIME_UNIT_MINUTES), 244 TALER_TESTING_cmd_purse_deposit_coins ( 245 "purse-deposit-coins", 246 MHD_HTTP_OK, 247 0 /* min age */, 248 "purse-create-with-reserve", 249 "withdraw-coin-1", 250 "EUR:1.01", 251 NULL), 252 TALER_TESTING_cmd_purse_poll_finish ( 253 "pull-deposit-purse-poll-finish", 254 GNUNET_TIME_relative_multiply ( 255 GNUNET_TIME_UNIT_SECONDS, 256 5), 257 "pull-poll-purse-before-deposit"), 258 TALER_TESTING_cmd_status ( 259 "pull-check-post-merge-reserve-balance-get", 260 "create-reserve-1", 261 "EUR:2.02", 262 MHD_HTTP_OK), 263 TALER_TESTING_cmd_reserve_history ( 264 "push-check-post-merge-reserve-balance-post", 265 "create-reserve-1", 266 "EUR:2.02", 267 MHD_HTTP_OK), 268 TALER_TESTING_cmd_purse_deposit_coins ( 269 "purse-deposit-coins-idempotent", 270 MHD_HTTP_OK, 271 0 /* min age */, 272 "purse-create-with-reserve", 273 "withdraw-coin-1", 274 "EUR:1.01", 275 NULL), 276 /* create 2nd purse for a deposit conflict */ 277 TALER_TESTING_cmd_purse_create_with_reserve ( 278 "purse-create-with-reserve-2", 279 MHD_HTTP_OK, 280 "{\"amount\":\"EUR:4\",\"summary\":\"beer\"}", 281 true /* upload contract */, 282 true /* pay purse fee */, 283 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 284 "create-reserve-1"), 285 TALER_TESTING_cmd_purse_deposit_coins ( 286 "purse-deposit-coins-conflict", 287 MHD_HTTP_CONFLICT, 288 0 /* min age */, 289 "purse-create-with-reserve-2", 290 "withdraw-coin-1", 291 "EUR:4.01", 292 NULL), 293 TALER_TESTING_cmd_end () 294 }; 295 296 struct TALER_TESTING_Command expire[] = { 297 TALER_TESTING_cmd_purse_create_with_reserve ( 298 "purse-create-with-reserve-expire", 299 MHD_HTTP_OK, 300 "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}", 301 true /* upload contract */, 302 true /* pay purse fee */, 303 GNUNET_TIME_relative_multiply ( 304 GNUNET_TIME_UNIT_SECONDS, 305 1), /* expiration */ 306 "create-reserve-1"), 307 TALER_TESTING_cmd_purse_poll ( 308 "pull-poll-purse-before-expire", 309 MHD_HTTP_GONE, 310 "purse-create-with-reserve-expire", 311 "EUR:1", 312 false, 313 GNUNET_TIME_UNIT_MINUTES), 314 TALER_TESTING_cmd_purse_create_with_deposit ( 315 "purse-with-deposit-expire", 316 MHD_HTTP_OK, 317 "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", 318 true, /* upload contract */ 319 GNUNET_TIME_relative_multiply ( 320 GNUNET_TIME_UNIT_SECONDS, 321 1), /* expiration */ 322 "withdraw-coin-1", 323 "EUR:1.02", 324 NULL), 325 TALER_TESTING_cmd_purse_poll ( 326 "push-poll-purse-before-expire", 327 MHD_HTTP_GONE, 328 "purse-with-deposit-expire", 329 "EUR:1", 330 true, /* wait for merge */ 331 GNUNET_TIME_UNIT_MINUTES), 332 /* This should fail, as too much of the coin 333 is already spend / in a purse */ 334 TALER_TESTING_cmd_purse_create_with_deposit ( 335 "purse-with-deposit-overspending", 336 MHD_HTTP_CONFLICT, 337 "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}", 338 true, /* upload contract */ 339 GNUNET_TIME_relative_multiply ( 340 GNUNET_TIME_UNIT_SECONDS, 341 1), /* expiration */ 342 "withdraw-coin-1", 343 "EUR:2.01", 344 NULL), 345 TALER_TESTING_cmd_sleep ( 346 "sleep", 347 2 /* seconds */), 348 TALER_TESTING_cmd_exec_expire ( 349 "exec-expire", 350 config_file), 351 TALER_TESTING_cmd_purse_poll_finish ( 352 "push-merge-purse-poll-finish-expire", 353 GNUNET_TIME_relative_multiply ( 354 GNUNET_TIME_UNIT_SECONDS, 355 15), 356 "push-poll-purse-before-expire"), 357 TALER_TESTING_cmd_purse_poll_finish ( 358 "pull-deposit-purse-poll-expire-finish", 359 GNUNET_TIME_relative_multiply ( 360 GNUNET_TIME_UNIT_SECONDS, 361 15), 362 "pull-poll-purse-before-expire"), 363 /* coin was refunded, so now this should be OK */ 364 /* This should fail, as too much of the coin 365 is already spend / in a purse */ 366 TALER_TESTING_cmd_purse_create_with_deposit ( 367 "purse-with-deposit-refunded", 368 MHD_HTTP_OK, 369 "{\"amount\":\"EUR:2\",\"summary\":\"ice cream\"}", 370 true, /* upload contract */ 371 GNUNET_TIME_relative_multiply ( 372 GNUNET_TIME_UNIT_SECONDS, 373 1), /* expiration */ 374 "withdraw-coin-1", 375 "EUR:2.01", 376 NULL), 377 TALER_TESTING_cmd_end () 378 }; 379 struct TALER_TESTING_Command reserves[] = { 380 CMD_TRANSFER_TO_EXCHANGE ( 381 "create-reserve-100", 382 "EUR:1.04"), 383 TALER_TESTING_cmd_check_bank_admin_transfer ( 384 "check-create-reserve-100", 385 "EUR:1.04", 386 cred.user42_payto, 387 cred.exchange_payto, 388 "create-reserve-100"), 389 CMD_TRANSFER_TO_EXCHANGE ( 390 "create-reserve-101", 391 "EUR:1.04"), 392 TALER_TESTING_cmd_check_bank_admin_transfer ( 393 "check-create-reserve-101", 394 "EUR:1.04", 395 cred.user42_payto, 396 cred.exchange_payto, 397 "create-reserve-101"), 398 CMD_EXEC_WIREWATCH ("wirewatch-100"), 399 TALER_TESTING_cmd_withdraw_amount ( 400 "withdraw-coin-100", 401 "create-reserve-100", 402 "EUR:1", 403 0, /* age restriction off */ 404 MHD_HTTP_OK), 405 TALER_TESTING_cmd_reserve_open ( 406 "reserve-open-101-fail", 407 "create-reserve-101", 408 "EUR:0", 409 GNUNET_TIME_UNIT_YEARS, 410 5, /* min purses */ 411 MHD_HTTP_PAYMENT_REQUIRED, 412 NULL, 413 NULL), 414 TALER_TESTING_cmd_reserve_open ( 415 "reserve-open-101-ok-a", 416 "create-reserve-101", 417 "EUR:0.01", 418 GNUNET_TIME_UNIT_MONTHS, 419 1, /* min purses */ 420 MHD_HTTP_OK, 421 NULL, 422 NULL), 423 TALER_TESTING_cmd_status ( 424 "status-101-open-paid", 425 "create-reserve-101", 426 "EUR:1.03", 427 MHD_HTTP_OK), 428 TALER_TESTING_cmd_reserve_open ( 429 "reserve-open-101-ok-b", 430 "create-reserve-101", 431 "EUR:0", 432 GNUNET_TIME_UNIT_MONTHS, 433 2, /* min purses */ 434 MHD_HTTP_OK, 435 "withdraw-coin-100", 436 "EUR:0.03", /* 0.02 for the reserve open, 0.01 for deposit fee */ 437 NULL, 438 NULL), 439 /* Use purse creation with purse quota here */ 440 TALER_TESTING_cmd_purse_create_with_reserve ( 441 "purse-create-with-reserve-101-a", 442 MHD_HTTP_OK, 443 "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", 444 true /* upload contract */, 445 false /* pay purse fee */, 446 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 447 "create-reserve-101"), 448 TALER_TESTING_cmd_purse_create_with_reserve ( 449 "purse-create-with-reserve-101-b", 450 MHD_HTTP_OK, 451 "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", 452 true /* upload contract */, 453 false /* pay purse fee */, 454 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 455 "create-reserve-101"), 456 TALER_TESTING_cmd_purse_create_with_reserve ( 457 "purse-create-with-reserve-101-fail", 458 MHD_HTTP_CONFLICT, 459 "{\"amount\":\"EUR:1\",\"summary\":\"ice cream\"}", 460 true /* upload contract */, 461 false /* pay purse fee */, 462 GNUNET_TIME_UNIT_MINUTES, /* expiration */ 463 "create-reserve-101"), 464 TALER_TESTING_cmd_reserve_get_attestable ( 465 "reserve-101-attestable", 466 "create-reserve-101", 467 MHD_HTTP_NOT_FOUND, 468 NULL), 469 TALER_TESTING_cmd_reserve_get_attestable ( 470 "reserve-101-attest", 471 "create-reserve-101", 472 MHD_HTTP_NOT_FOUND, 473 "nx-attribute-name", 474 NULL), 475 TALER_TESTING_cmd_oauth_with_birthdate ( 476 "start-oauth-service", 477 "2015-00-00", 478 6666), 479 TALER_TESTING_cmd_reserve_close ( 480 "reserve-101-close-kyc", 481 "create-reserve-101", 482 /* 44 => not to origin */ 483 cred.user44_payto, 484 MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS), 485 TALER_TESTING_cmd_admin_add_kycauth ( 486 "setup-account-key", 487 "EUR:0.01", 488 &cred.ba, 489 cred.user44_payto, 490 NULL /* create new key */), 491 CMD_EXEC_WIREWATCH ( 492 "import-kyc-account"), 493 TALER_TESTING_cmd_check_kyc_get ( 494 "check-kyc-close-pending", 495 "reserve-101-close-kyc", 496 "setup-account-key", 497 TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER, 498 MHD_HTTP_ACCEPTED), 499 TALER_TESTING_cmd_get_kyc_info ( 500 "get-kyc-info", 501 "check-kyc-close-pending", 502 MHD_HTTP_OK), 503 TALER_TESTING_cmd_post_kyc_start ( 504 "start-kyc-process", 505 "get-kyc-info", 506 0, 507 MHD_HTTP_OK), 508 TALER_TESTING_cmd_proof_kyc_oauth2 ( 509 "proof-close-kyc", 510 "reserve-101-close-kyc", 511 "test-oauth2", 512 "pass", 513 MHD_HTTP_SEE_OTHER), 514 TALER_TESTING_cmd_check_kyc_get ( 515 "check-kyc-close-ok", 516 "reserve-101-close-kyc", 517 "setup-account-key", 518 TALER_EXCHANGE_KLPT_KYC_OK, 519 MHD_HTTP_OK), 520 /* Now it should pass */ 521 TALER_TESTING_cmd_reserve_close ( 522 "reserve-101-close", 523 "create-reserve-101", 524 /* 44 => not to origin */ 525 cred.user44_payto, 526 MHD_HTTP_OK), 527 TALER_TESTING_cmd_exec_closer ( 528 "close-reserves-101", 529 config_file, 530 "EUR:1.02", 531 "EUR:0.01", 532 "create-reserve-101"), 533 TALER_TESTING_cmd_exec_transfer ( 534 "close-reserves-101-transfer", 535 config_file), 536 TALER_TESTING_cmd_status ( 537 "reserve-101-closed-status", 538 "create-reserve-101", 539 "EUR:0", 540 MHD_HTTP_OK), 541 TALER_TESTING_cmd_end () 542 }; 543 544 struct TALER_TESTING_Command commands[] = { 545 TALER_TESTING_cmd_run_fakebank ("run-fakebank", 546 cred.cfg, 547 "exchange-account-2"), 548 TALER_TESTING_cmd_system_start ("start-taler", 549 config_file, 550 "-e", 551 NULL), 552 TALER_TESTING_cmd_get_exchange ("get-exchange", 553 cred.cfg, 554 NULL, 555 true, 556 true), 557 TALER_TESTING_cmd_batch ("withdraw", 558 withdraw), 559 TALER_TESTING_cmd_batch ("push", 560 push), 561 TALER_TESTING_cmd_batch ("pull", 562 pull), 563 TALER_TESTING_cmd_batch ("expire", 564 expire), 565 TALER_TESTING_cmd_batch ("reserves", 566 reserves), 567 /* End the suite. */ 568 TALER_TESTING_cmd_end () 569 }; 570 571 (void) cls; 572 TALER_TESTING_run (is, 573 commands); 574 } 575 576 577 int 578 main (int argc, 579 char *const *argv) 580 { 581 (void) argc; 582 { 583 char *cipher; 584 585 cipher = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]); 586 GNUNET_assert (NULL != cipher); 587 uses_cs = (0 == strcmp (cipher, "cs")); 588 GNUNET_asprintf (&config_file, 589 "test_exchange_api-%s.conf", 590 cipher); 591 GNUNET_free (cipher); 592 } 593 return TALER_TESTING_main (argv, 594 "INFO", 595 config_file, 596 "exchange-account-2", 597 TALER_TESTING_BS_FAKEBANK, 598 &cred, 599 &run, 600 NULL); 601 } 602 603 604 /* end of test_exchange_p2p.c */