testing_api_cmd_post_orders.c (32615B)
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 /** 21 * @file src/testing/testing_api_cmd_post_orders.c 22 * @brief command to run POST /orders 23 * @author Marcello Stanisci 24 */ 25 26 #include "platform.h" 27 struct OrdersState; 28 #define TALER_MERCHANT_POST_PRIVATE_ORDERS_RESULT_CLOSURE struct OrdersState 29 #define TALER_MERCHANT_POST_ORDERS_CLAIM_RESULT_CLOSURE struct OrdersState 30 #include <gnunet/gnunet_common.h> 31 #include <gnunet/gnunet_time_lib.h> 32 #include <jansson.h> 33 #include <stdint.h> 34 #include "taler/taler_merchant_util.h" 35 #include <stdlib.h> 36 #include <math.h> 37 #include <taler/taler_exchange_service.h> 38 #include <taler/taler_testing_lib.h> 39 #include "taler/taler_merchant_service.h" 40 #include "taler/taler_merchant_testing_lib.h" 41 #include <taler/merchant/post-private-orders.h> 42 #include <taler/merchant/post-orders-ORDER_ID-claim.h> 43 44 /** 45 * State for a "POST /orders" CMD. 46 */ 47 struct OrdersState 48 { 49 50 /** 51 * Expected status code. 52 */ 53 unsigned int http_status; 54 55 /** 56 * Order id. 57 */ 58 const char *order_id; 59 60 /** 61 * Our configuration. 62 */ 63 const struct GNUNET_CONFIGURATION_Handle *cfg; 64 65 /** 66 * The order id we expect the merchant to assign (if not NULL). 67 */ 68 const char *expected_order_id; 69 70 /** 71 * Contract terms obtained from the backend. 72 */ 73 json_t *contract_terms; 74 75 /** 76 * Order submitted to the backend. 77 */ 78 json_t *order_terms; 79 80 /** 81 * Contract terms hash code. 82 */ 83 struct TALER_PrivateContractHashP h_contract_terms; 84 85 /** 86 * The /orders operation handle. 87 */ 88 struct TALER_MERCHANT_PostPrivateOrdersHandle *po; 89 90 /** 91 * The (initial) POST /orders/$ID/claim operation handle. 92 * The logic is such that after an order creation, 93 * we immediately claim the order. 94 */ 95 struct TALER_MERCHANT_PostOrdersClaimHandle *och; 96 97 /** 98 * The nonce. 99 */ 100 struct GNUNET_CRYPTO_EddsaPublicKey nonce; 101 102 /** 103 * Whether to generate a claim token. 104 */ 105 bool make_claim_token; 106 107 /** 108 * The claim token 109 */ 110 struct TALER_ClaimTokenP claim_token; 111 112 /** 113 * URL of the merchant backend. 114 */ 115 const char *merchant_url; 116 117 /** 118 * The interpreter state. 119 */ 120 struct TALER_TESTING_Interpreter *is; 121 122 /** 123 * Merchant signature over the orders. 124 */ 125 struct TALER_MerchantSignatureP merchant_sig; 126 127 /** 128 * Merchant public key. 129 */ 130 struct TALER_MerchantPublicKeyP merchant_pub; 131 132 /** 133 * The payment target for the order 134 */ 135 const char *payment_target; 136 137 /** 138 * The products the order is purchasing. 139 */ 140 const char *products; 141 142 /** 143 * The locks that the order should release. 144 */ 145 const char *locks; 146 147 /** 148 * Should the command also CLAIM the order? 149 */ 150 bool with_claim; 151 152 /** 153 * If not NULL, the command should duplicate the request and verify the 154 * response is the same as in this command. 155 */ 156 const char *duplicate_of; 157 }; 158 159 160 /** 161 * Offer internal data to other commands. 162 * 163 * @param cls closure 164 * @param[out] ret result (could be anything) 165 * @param trait name of the trait 166 * @param index index number of the object to extract. 167 * @return #GNUNET_OK on success 168 */ 169 static enum GNUNET_GenericReturnValue 170 orders_traits (void *cls, 171 const void **ret, 172 const char *trait, 173 unsigned int index) 174 { 175 struct OrdersState *ps = cls; 176 struct TALER_TESTING_Trait traits[] = { 177 TALER_TESTING_make_trait_order_id (ps->order_id), 178 TALER_TESTING_make_trait_contract_terms (ps->contract_terms), 179 TALER_TESTING_make_trait_order_terms (ps->order_terms), 180 TALER_TESTING_make_trait_h_contract_terms (&ps->h_contract_terms), 181 TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig), 182 TALER_TESTING_make_trait_merchant_pub (&ps->merchant_pub), 183 TALER_TESTING_make_trait_claim_nonce (&ps->nonce), 184 TALER_TESTING_make_trait_claim_token (&ps->claim_token), 185 TALER_TESTING_trait_end () 186 }; 187 188 return TALER_TESTING_get_trait (traits, 189 ret, 190 trait, 191 index); 192 } 193 194 195 /** 196 * Used to fill the "orders" CMD state with backend-provided 197 * values. Also double-checks that the order was correctly 198 * created. 199 * 200 * @param cls closure 201 * @param ocr response we got 202 */ 203 static void 204 orders_claim_cb (struct OrdersState *ps, 205 const struct TALER_MERCHANT_PostOrdersClaimResponse *ocr) 206 { 207 const char *error_name; 208 unsigned int error_line; 209 struct GNUNET_JSON_Specification spec[] = { 210 GNUNET_JSON_spec_fixed_auto ("merchant_pub", 211 &ps->merchant_pub), 212 GNUNET_JSON_spec_end () 213 }; 214 215 ps->och = NULL; 216 if (ps->http_status != ocr->hr.http_status) 217 { 218 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 219 "Expected status %u, got %u\n", 220 ps->http_status, 221 ocr->hr.http_status); 222 TALER_TESTING_FAIL (ps->is); 223 } 224 if (MHD_HTTP_OK != ocr->hr.http_status) 225 { 226 TALER_TESTING_interpreter_next (ps->is); 227 return; 228 } 229 ps->contract_terms = json_deep_copy ( 230 (json_t *) ocr->details.ok.contract_terms); 231 GNUNET_assert (GNUNET_OK == 232 TALER_JSON_contract_hash (ps->contract_terms, 233 &ps->h_contract_terms)); 234 ps->merchant_sig = ocr->details.ok.merchant_sig; 235 if (GNUNET_OK != 236 GNUNET_JSON_parse (ps->contract_terms, 237 spec, 238 &error_name, 239 &error_line)) 240 { 241 char *log; 242 243 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 244 "Parser failed on %s:%u\n", 245 error_name, 246 error_line); 247 log = json_dumps (ps->contract_terms, 248 JSON_INDENT (1)); 249 fprintf (stderr, 250 "%s\n", 251 log); 252 free (log); 253 TALER_TESTING_FAIL (ps->is); 254 } 255 TALER_TESTING_interpreter_next (ps->is); 256 } 257 258 259 /** 260 * Callback that processes the response following a POST /orders. NOTE: no 261 * contract terms are included here; they need to be taken via the "orders 262 * lookup" method. 263 * 264 * @param cls closure. 265 * @param por details about the response 266 */ 267 static void 268 order_cb (struct OrdersState *ps, 269 const struct TALER_MERCHANT_PostPrivateOrdersResponse *por) 270 { 271 272 ps->po = NULL; 273 if (ps->http_status != por->hr.http_status) 274 { 275 TALER_TESTING_unexpected_status_with_body (ps->is, 276 por->hr.http_status, 277 ps->http_status, 278 por->hr.reply); 279 TALER_TESTING_interpreter_fail (ps->is); 280 return; 281 } 282 switch (por->hr.http_status) 283 { 284 case 0: 285 TALER_LOG_DEBUG ("/orders, expected 0 status code\n"); 286 TALER_TESTING_interpreter_next (ps->is); 287 return; 288 case MHD_HTTP_OK: 289 if (NULL != por->details.ok.token) 290 ps->claim_token = *por->details.ok.token; 291 ps->order_id = GNUNET_strdup (por->details.ok.order_id); 292 if ((NULL != ps->expected_order_id) && 293 (0 != strcmp (por->details.ok.order_id, 294 ps->expected_order_id))) 295 { 296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 297 "Order id assigned does not match\n"); 298 TALER_TESTING_interpreter_fail (ps->is); 299 return; 300 } 301 if (NULL != ps->duplicate_of) 302 { 303 const struct TALER_TESTING_Command *order_cmd; 304 const struct TALER_ClaimTokenP *prev_token; 305 struct TALER_ClaimTokenP zero_token = {0}; 306 const struct TALER_ClaimTokenP *resp_token; 307 308 order_cmd = TALER_TESTING_interpreter_lookup_command ( 309 ps->is, 310 ps->duplicate_of); 311 if (GNUNET_OK != 312 TALER_TESTING_get_trait_claim_token (order_cmd, 313 &prev_token)) 314 { 315 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 316 "Could not fetch previous order claim token\n"); 317 TALER_TESTING_interpreter_fail (ps->is); 318 return; 319 } 320 321 resp_token = (NULL != por->details.ok.token) 322 ? por->details.ok.token 323 : &zero_token; 324 if (0 != GNUNET_memcmp (prev_token, 325 resp_token)) 326 { 327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 328 "Claim tokens for identical requests do not match\n"); 329 TALER_TESTING_interpreter_fail (ps->is); 330 return; 331 } 332 } 333 break; 334 case MHD_HTTP_NOT_FOUND: 335 TALER_TESTING_interpreter_next (ps->is); 336 return; 337 case MHD_HTTP_GONE: 338 TALER_TESTING_interpreter_next (ps->is); 339 return; 340 case MHD_HTTP_CONFLICT: 341 TALER_TESTING_interpreter_next (ps->is); 342 return; 343 default: 344 { 345 char *s = json_dumps (por->hr.reply, 346 JSON_COMPACT); 347 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 348 "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n", 349 por->hr.http_status, 350 (int) por->hr.ec, 351 TALER_TESTING_interpreter_get_current_label (ps->is), 352 s); 353 free (s); 354 /** 355 * Not failing, as test cases are _supposed_ 356 * to create non 200 OK situations. 357 */ 358 TALER_TESTING_interpreter_next (ps->is); 359 } 360 return; 361 } 362 363 if (! ps->with_claim) 364 { 365 TALER_TESTING_interpreter_next (ps->is); 366 return; 367 } 368 ps->och = TALER_MERCHANT_post_orders_claim_create ( 369 TALER_TESTING_interpreter_get_context (ps->is), 370 ps->merchant_url, 371 ps->order_id, 372 &ps->nonce); 373 if (NULL == ps->och) 374 TALER_TESTING_FAIL (ps->is); 375 TALER_MERCHANT_post_orders_claim_set_options ( 376 ps->och, 377 TALER_MERCHANT_post_orders_claim_option_token ( 378 &ps->claim_token)); 379 { 380 enum TALER_ErrorCode ec; 381 382 ec = TALER_MERCHANT_post_orders_claim_start (ps->och, 383 &orders_claim_cb, 384 ps); 385 GNUNET_assert (TALER_EC_NONE == ec); 386 } 387 } 388 389 390 /** 391 * Run a "orders" CMD. 392 * 393 * @param cls closure. 394 * @param cmd command currently being run. 395 * @param is interpreter state. 396 */ 397 static void 398 orders_run (void *cls, 399 const struct TALER_TESTING_Command *cmd, 400 struct TALER_TESTING_Interpreter *is) 401 { 402 struct OrdersState *ps = cls; 403 404 ps->is = is; 405 if (NULL == json_object_get (ps->order_terms, 406 "order_id")) 407 { 408 struct GNUNET_TIME_Absolute now; 409 char *order_id; 410 411 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 412 order_id = GNUNET_STRINGS_data_to_string_alloc ( 413 &now, 414 sizeof (now)); 415 GNUNET_assert (0 == 416 json_object_set_new (ps->order_terms, 417 "order_id", 418 json_string (order_id))); 419 GNUNET_free (order_id); 420 } 421 GNUNET_CRYPTO_random_block (&ps->nonce, 422 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 423 ps->po = TALER_MERCHANT_post_private_orders_create ( 424 TALER_TESTING_interpreter_get_context (is), 425 ps->merchant_url, 426 ps->order_terms); 427 GNUNET_assert (NULL != ps->po); 428 { 429 enum TALER_ErrorCode ec; 430 431 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 432 &order_cb, 433 ps); 434 GNUNET_assert (TALER_EC_NONE == ec); 435 } 436 } 437 438 439 /** 440 * Run a "orders" CMD. 441 * 442 * @param cls closure. 443 * @param cmd command currently being run. 444 * @param is interpreter state. 445 */ 446 static void 447 orders_run2 (void *cls, 448 const struct TALER_TESTING_Command *cmd, 449 struct TALER_TESTING_Interpreter *is) 450 { 451 struct OrdersState *ps = cls; 452 const json_t *order; 453 char *products_string = GNUNET_strdup (ps->products); 454 char *locks_string = GNUNET_strdup (ps->locks); 455 char *token; 456 struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct *products = NULL; 457 unsigned int products_length = 0; 458 const char **locks = NULL; 459 unsigned int locks_length = 0; 460 461 ps->is = is; 462 if (NULL != ps->duplicate_of) 463 { 464 const struct TALER_TESTING_Command *order_cmd; 465 const json_t *ct; 466 467 order_cmd = TALER_TESTING_interpreter_lookup_command ( 468 is, 469 ps->duplicate_of); 470 if (GNUNET_OK != 471 TALER_TESTING_get_trait_order_terms (order_cmd, 472 &ct)) 473 { 474 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 475 "Could not fetch previous order string\n"); 476 TALER_TESTING_interpreter_fail (is); 477 return; 478 } 479 order = (json_t *) ct; 480 } 481 else 482 { 483 if (NULL == json_object_get (ps->order_terms, 484 "order_id")) 485 { 486 struct GNUNET_TIME_Absolute now; 487 char *order_id; 488 489 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 490 order_id = GNUNET_STRINGS_data_to_string_alloc ( 491 &now.abs_value_us, 492 sizeof (now.abs_value_us)); 493 GNUNET_assert (0 == 494 json_object_set_new (ps->order_terms, 495 "order_id", 496 json_string (order_id))); 497 GNUNET_free (order_id); 498 } 499 order = ps->order_terms; 500 } 501 if (NULL == order) 502 { 503 GNUNET_break (0); 504 TALER_TESTING_interpreter_fail (is); 505 return; 506 } 507 508 GNUNET_CRYPTO_random_block (&ps->nonce, 509 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 510 for (token = strtok (products_string, ";"); 511 NULL != token; 512 token = strtok (NULL, ";")) 513 { 514 char *ctok; 515 struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct pd; 516 double quantity_double = 0.0; 517 518 /* Token syntax is "[product_id]/[quantity]" */ 519 ctok = strchr (token, '/'); 520 if (NULL != ctok) 521 { 522 *ctok = '\0'; 523 ctok++; 524 { 525 char *endptr; 526 527 quantity_double = strtod (ctok, 528 &endptr); 529 if ( (endptr == ctok) || ('\0' != *endptr) || 530 (! isfinite (quantity_double)) || (quantity_double < 0.0)) 531 { 532 GNUNET_break (0); 533 break; 534 } 535 } 536 } 537 else 538 { 539 quantity_double = 1.0; 540 } 541 if (quantity_double <= 0.0) 542 { 543 GNUNET_break (0); 544 break; 545 } 546 547 { 548 double quantity_floor; 549 double frac; 550 uint64_t quantity_int; 551 uint32_t quantity_frac_local = 0; 552 long long scaled; 553 554 quantity_floor = floor (quantity_double); 555 frac = quantity_double - quantity_floor; 556 quantity_int = (uint64_t) quantity_floor; 557 if (frac < 0.0) 558 { 559 GNUNET_break (0); 560 break; 561 } 562 scaled = llround (frac * (double) TALER_MERCHANT_UNIT_FRAC_BASE); 563 if (scaled < 0) 564 { 565 GNUNET_break (0); 566 break; 567 } 568 if (scaled >= (long long) TALER_MERCHANT_UNIT_FRAC_BASE) 569 { 570 quantity_int++; 571 scaled -= TALER_MERCHANT_UNIT_FRAC_BASE; 572 } 573 quantity_frac_local = (uint32_t) scaled; 574 pd.quantity = quantity_int; 575 pd.quantity_frac = quantity_frac_local; 576 pd.use_fractional_quantity = (0 != quantity_frac_local); 577 } 578 pd.product_id = token; 579 580 GNUNET_array_append (products, 581 products_length, 582 pd); 583 } 584 for (token = strtok (locks_string, ";"); 585 NULL != token; 586 token = strtok (NULL, ";")) 587 { 588 const struct TALER_TESTING_Command *lock_cmd; 589 const char *uuid; 590 591 lock_cmd = TALER_TESTING_interpreter_lookup_command ( 592 is, 593 token); 594 595 if (GNUNET_OK != 596 TALER_TESTING_get_trait_lock_uuid (lock_cmd, 597 &uuid)) 598 { 599 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 600 "Could not fetch lock uuid\n"); 601 TALER_TESTING_interpreter_fail (is); 602 return; 603 } 604 605 GNUNET_array_append (locks, 606 locks_length, 607 uuid); 608 } 609 ps->po = TALER_MERCHANT_post_private_orders_create ( 610 TALER_TESTING_interpreter_get_context (is), 611 ps->merchant_url, 612 order); 613 GNUNET_assert (NULL != ps->po); 614 if (NULL != ps->payment_target) 615 TALER_MERCHANT_post_private_orders_set_options ( 616 ps->po, 617 TALER_MERCHANT_post_private_orders_option_payment_target ( 618 ps->payment_target)); 619 if (0 < products_length) 620 TALER_MERCHANT_post_private_orders_set_options ( 621 ps->po, 622 TALER_MERCHANT_post_private_orders_option_inventory_products ( 623 products_length, products)); 624 if (0 < locks_length) 625 TALER_MERCHANT_post_private_orders_set_options ( 626 ps->po, 627 TALER_MERCHANT_post_private_orders_option_lock_uuids ( 628 locks_length, locks)); 629 TALER_MERCHANT_post_private_orders_set_options ( 630 ps->po, 631 TALER_MERCHANT_post_private_orders_option_create_token ( 632 ps->make_claim_token)); 633 { 634 enum TALER_ErrorCode ec; 635 636 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 637 &order_cb, 638 ps); 639 GNUNET_assert (TALER_EC_NONE == ec); 640 } 641 GNUNET_free (products_string); 642 GNUNET_free (locks_string); 643 GNUNET_array_grow (products, 644 products_length, 645 0); 646 GNUNET_array_grow (locks, 647 locks_length, 648 0); 649 } 650 651 652 /** 653 * Run a "orders" CMD. 654 * 655 * @param cls closure. 656 * @param cmd command currently being run. 657 * @param is interpreter state. 658 */ 659 static void 660 orders_run3 (void *cls, 661 const struct TALER_TESTING_Command *cmd, 662 struct TALER_TESTING_Interpreter *is) 663 { 664 struct OrdersState *ps = cls; 665 struct GNUNET_TIME_Absolute now; 666 667 ps->is = is; 668 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 669 if (NULL == json_object_get (ps->order_terms, 670 "order_id")) 671 { 672 char *order_id; 673 674 order_id = GNUNET_STRINGS_data_to_string_alloc ( 675 &now, 676 sizeof (now)); 677 GNUNET_assert (0 == 678 json_object_set_new (ps->order_terms, 679 "order_id", 680 json_string (order_id))); 681 GNUNET_free (order_id); 682 } 683 684 GNUNET_CRYPTO_random_block (&ps->nonce, 685 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 686 ps->po = TALER_MERCHANT_post_private_orders_create ( 687 TALER_TESTING_interpreter_get_context (is), 688 ps->merchant_url, 689 ps->order_terms); 690 GNUNET_assert (NULL != ps->po); 691 { 692 enum TALER_ErrorCode ec; 693 694 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 695 &order_cb, 696 ps); 697 GNUNET_assert (TALER_EC_NONE == ec); 698 } 699 } 700 701 702 /** 703 * Free the state of a "orders" CMD, and possibly 704 * cancel it if it did not complete. 705 * 706 * @param cls closure. 707 * @param cmd command being freed. 708 */ 709 static void 710 orders_cleanup (void *cls, 711 const struct TALER_TESTING_Command *cmd) 712 { 713 struct OrdersState *ps = cls; 714 715 if (NULL != ps->po) 716 { 717 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 718 "Command '%s' did not complete (orders put)\n", 719 cmd->label); 720 TALER_MERCHANT_post_private_orders_cancel (ps->po); 721 ps->po = NULL; 722 } 723 724 if (NULL != ps->och) 725 { 726 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 727 "Command '%s' did not complete (orders lookup)\n", 728 cmd->label); 729 TALER_MERCHANT_post_orders_claim_cancel (ps->och); 730 ps->och = NULL; 731 } 732 733 json_decref (ps->contract_terms); 734 json_decref (ps->order_terms); 735 GNUNET_free_nz ((void *) ps->order_id); 736 GNUNET_free (ps); 737 } 738 739 740 /** 741 * Mark part of the contract terms as possible to forget. 742 * 743 * @param cls pointer to the result of the forget operation. 744 * @param object_id name of the object to forget. 745 * @param parent parent of the object at @e object_id. 746 */ 747 static void 748 mark_forgettable (void *cls, 749 const char *object_id, 750 json_t *parent) 751 { 752 GNUNET_assert (GNUNET_OK == 753 TALER_JSON_contract_mark_forgettable (parent, 754 object_id)); 755 } 756 757 758 /** 759 * Constructs the json for a POST order request. 760 * 761 * @param order_id the name of the order to add, can be NULL. 762 * @param refund_deadline the deadline for refunds on this order. 763 * @param pay_deadline the deadline for payment on this order. 764 * @param amount the amount this order is for, NULL for v1 orders 765 * @param[out] order where to write the json string. 766 */ 767 static void 768 make_order_json (const char *order_id, 769 struct GNUNET_TIME_Timestamp refund_deadline, 770 struct GNUNET_TIME_Timestamp pay_deadline, 771 const char *amount, 772 json_t **order) 773 { 774 struct GNUNET_TIME_Timestamp refund = refund_deadline; 775 struct GNUNET_TIME_Timestamp pay = pay_deadline; 776 json_t *contract_terms; 777 778 /* Include required fields and some dummy objects to test forgetting. */ 779 contract_terms = json_pack ( 780 "{s:s, s:s?, s:s?, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}", 781 "summary", "merchant-lib testcase", 782 "order_id", order_id, 783 "amount", amount, 784 "fulfillment_url", "https://example.com", 785 "refund_deadline", GNUNET_JSON_from_timestamp (refund), 786 "pay_deadline", GNUNET_JSON_from_timestamp (pay), 787 "dummy_obj", "EUR:1.0", 788 "dummy_array", /* For testing forgetting parts of arrays */ 789 "item", "speakers", 790 "item", "headphones", 791 "item", "earbuds"); 792 GNUNET_assert (GNUNET_OK == 793 TALER_JSON_expand_path (contract_terms, 794 "$.dummy_obj", 795 &mark_forgettable, 796 NULL)); 797 GNUNET_assert (GNUNET_OK == 798 TALER_JSON_expand_path (contract_terms, 799 "$.dummy_array[*].item", 800 &mark_forgettable, 801 NULL)); 802 *order = contract_terms; 803 } 804 805 806 struct TALER_TESTING_Command 807 TALER_TESTING_cmd_merchant_post_orders_no_claim ( 808 const char *label, 809 const char *merchant_url, 810 unsigned int http_status, 811 const char *order_id, 812 struct GNUNET_TIME_Timestamp refund_deadline, 813 struct GNUNET_TIME_Timestamp pay_deadline, 814 const char *amount) 815 { 816 struct OrdersState *ps; 817 818 ps = GNUNET_new (struct OrdersState); 819 make_order_json (order_id, 820 refund_deadline, 821 pay_deadline, 822 amount, 823 &ps->order_terms); 824 ps->http_status = http_status; 825 ps->expected_order_id = order_id; 826 ps->merchant_url = merchant_url; 827 { 828 struct TALER_TESTING_Command cmd = { 829 .cls = ps, 830 .label = label, 831 .run = &orders_run, 832 .cleanup = &orders_cleanup, 833 .traits = &orders_traits 834 }; 835 836 return cmd; 837 } 838 } 839 840 841 struct TALER_TESTING_Command 842 TALER_TESTING_cmd_merchant_post_orders ( 843 const char *label, 844 const struct GNUNET_CONFIGURATION_Handle *cfg, 845 const char *merchant_url, 846 unsigned int http_status, 847 const char *order_id, 848 struct GNUNET_TIME_Timestamp refund_deadline, 849 struct GNUNET_TIME_Timestamp pay_deadline, 850 const char *amount) 851 { 852 struct OrdersState *ps; 853 854 ps = GNUNET_new (struct OrdersState); 855 ps->cfg = cfg; 856 make_order_json (order_id, 857 refund_deadline, 858 pay_deadline, 859 amount, 860 &ps->order_terms); 861 ps->http_status = http_status; 862 ps->expected_order_id = order_id; 863 ps->merchant_url = merchant_url; 864 ps->with_claim = true; 865 { 866 struct TALER_TESTING_Command cmd = { 867 .cls = ps, 868 .label = label, 869 .run = &orders_run, 870 .cleanup = &orders_cleanup, 871 .traits = &orders_traits 872 }; 873 874 return cmd; 875 } 876 } 877 878 879 struct TALER_TESTING_Command 880 TALER_TESTING_cmd_merchant_post_orders2 ( 881 const char *label, 882 const struct GNUNET_CONFIGURATION_Handle *cfg, 883 const char *merchant_url, 884 unsigned int http_status, 885 const char *order_id, 886 struct GNUNET_TIME_Timestamp refund_deadline, 887 struct GNUNET_TIME_Timestamp pay_deadline, 888 bool claim_token, 889 const char *amount, 890 const char *payment_target, 891 const char *products, 892 const char *locks, 893 const char *duplicate_of) 894 { 895 struct OrdersState *ps; 896 897 ps = GNUNET_new (struct OrdersState); 898 ps->cfg = cfg; 899 make_order_json (order_id, 900 refund_deadline, 901 pay_deadline, 902 amount, 903 &ps->order_terms); 904 ps->http_status = http_status; 905 ps->expected_order_id = order_id; 906 ps->merchant_url = merchant_url; 907 ps->payment_target = payment_target; 908 ps->products = products; 909 ps->locks = locks; 910 ps->with_claim = (NULL == duplicate_of); 911 ps->make_claim_token = claim_token; 912 ps->duplicate_of = duplicate_of; 913 { 914 struct TALER_TESTING_Command cmd = { 915 .cls = ps, 916 .label = label, 917 .run = &orders_run2, 918 .cleanup = &orders_cleanup, 919 .traits = &orders_traits 920 }; 921 922 return cmd; 923 } 924 } 925 926 927 struct TALER_TESTING_Command 928 TALER_TESTING_cmd_merchant_post_orders3 ( 929 const char *label, 930 const struct GNUNET_CONFIGURATION_Handle *cfg, 931 const char *merchant_url, 932 unsigned int expected_http_status, 933 const char *order_id, 934 struct GNUNET_TIME_Timestamp refund_deadline, 935 struct GNUNET_TIME_Timestamp pay_deadline, 936 const char *fulfillment_url, 937 const char *amount) 938 { 939 struct OrdersState *ps; 940 941 ps = GNUNET_new (struct OrdersState); 942 ps->cfg = cfg; 943 make_order_json (order_id, 944 refund_deadline, 945 pay_deadline, 946 amount, 947 &ps->order_terms); 948 GNUNET_assert (0 == 949 json_object_set_new (ps->order_terms, 950 "fulfillment_url", 951 json_string (fulfillment_url))); 952 ps->http_status = expected_http_status; 953 ps->merchant_url = merchant_url; 954 ps->with_claim = true; 955 { 956 struct TALER_TESTING_Command cmd = { 957 .cls = ps, 958 .label = label, 959 .run = &orders_run, 960 .cleanup = &orders_cleanup, 961 .traits = &orders_traits 962 }; 963 964 return cmd; 965 } 966 } 967 968 969 struct TALER_TESTING_Command 970 TALER_TESTING_cmd_merchant_post_orders_choices ( 971 const char *label, 972 const struct GNUNET_CONFIGURATION_Handle *cfg, 973 const char *merchant_url, 974 unsigned int http_status, 975 const char *token_family_slug, 976 const char *choice_description, 977 json_t *choice_description_i18n, 978 unsigned int num_inputs, 979 unsigned int num_outputs, 980 const char *order_id, 981 struct GNUNET_TIME_Timestamp refund_deadline, 982 struct GNUNET_TIME_Timestamp pay_deadline, 983 const char *amount) 984 { 985 struct OrdersState *ps; 986 struct TALER_Amount brutto; 987 json_t *choice; 988 json_t *choices; 989 json_t *inputs; 990 json_t *outputs; 991 992 ps = GNUNET_new (struct OrdersState); 993 ps->cfg = cfg; 994 make_order_json (order_id, 995 refund_deadline, 996 pay_deadline, 997 NULL, 998 &ps->order_terms); 999 GNUNET_assert (GNUNET_OK == 1000 TALER_string_to_amount (amount, 1001 &brutto)); 1002 inputs = json_array (); 1003 GNUNET_assert (NULL != inputs); 1004 GNUNET_assert (0 == 1005 json_array_append_new ( 1006 inputs, 1007 GNUNET_JSON_PACK ( 1008 GNUNET_JSON_pack_string ("type", 1009 "token"), 1010 GNUNET_JSON_pack_uint64 ("count", 1011 num_inputs), 1012 GNUNET_JSON_pack_string ("token_family_slug", 1013 token_family_slug) 1014 ))); 1015 outputs = json_array (); 1016 GNUNET_assert (NULL != outputs); 1017 GNUNET_assert (0 == 1018 json_array_append_new ( 1019 outputs, 1020 GNUNET_JSON_PACK ( 1021 GNUNET_JSON_pack_string ("type", 1022 "token"), 1023 GNUNET_JSON_pack_uint64 ("count", 1024 num_outputs), 1025 GNUNET_JSON_pack_string ("token_family_slug", 1026 token_family_slug) 1027 ))); 1028 choice 1029 = GNUNET_JSON_PACK ( 1030 TALER_JSON_pack_amount ("amount", 1031 &brutto), 1032 GNUNET_JSON_pack_allow_null ( 1033 GNUNET_JSON_pack_string ("description", 1034 choice_description)), 1035 GNUNET_JSON_pack_allow_null ( 1036 GNUNET_JSON_pack_object_steal ("description_i18n", 1037 choice_description_i18n)), 1038 GNUNET_JSON_pack_array_steal ("inputs", 1039 inputs), 1040 GNUNET_JSON_pack_array_steal ("outputs", 1041 outputs)); 1042 choices = json_array (); 1043 GNUNET_assert (NULL != choices); 1044 GNUNET_assert (0 == 1045 json_array_append_new ( 1046 choices, 1047 choice)); 1048 GNUNET_assert (0 == 1049 json_object_set_new (ps->order_terms, 1050 "choices", 1051 choices) 1052 ); 1053 GNUNET_assert (0 == 1054 json_object_set_new (ps->order_terms, 1055 "version", 1056 json_integer (1)) 1057 ); 1058 1059 1060 ps->http_status = http_status; 1061 ps->expected_order_id = order_id; 1062 ps->merchant_url = merchant_url; 1063 ps->with_claim = true; 1064 { 1065 struct TALER_TESTING_Command cmd = { 1066 .cls = ps, 1067 .label = label, 1068 .run = &orders_run3, 1069 .cleanup = &orders_cleanup, 1070 .traits = &orders_traits 1071 }; 1072 1073 return cmd; 1074 } 1075 } 1076 1077 1078 struct TALER_TESTING_Command 1079 TALER_TESTING_cmd_merchant_post_orders_donau ( 1080 const char *label, 1081 const struct GNUNET_CONFIGURATION_Handle *cfg, 1082 const char *merchant_url, 1083 unsigned int http_status, 1084 const char *order_id, 1085 struct GNUNET_TIME_Timestamp refund_deadline, 1086 struct GNUNET_TIME_Timestamp pay_deadline, 1087 const char *amount) 1088 { 1089 struct OrdersState *ps; 1090 struct TALER_Amount brutto; 1091 json_t *choice; 1092 json_t *choices; 1093 json_t *outputs; 1094 1095 ps = GNUNET_new (struct OrdersState); 1096 ps->cfg = cfg; 1097 make_order_json (order_id, 1098 refund_deadline, 1099 pay_deadline, 1100 NULL, 1101 &ps->order_terms); 1102 GNUNET_assert (GNUNET_OK == 1103 TALER_string_to_amount (amount, 1104 &brutto)); 1105 1106 outputs = json_array (); 1107 GNUNET_assert (NULL != outputs); 1108 GNUNET_assert (0 == 1109 json_array_append_new ( 1110 outputs, 1111 GNUNET_JSON_PACK ( 1112 GNUNET_JSON_pack_string ("type", 1113 "tax-receipt") 1114 ))); 1115 choice 1116 = GNUNET_JSON_PACK ( 1117 TALER_JSON_pack_amount ("amount", 1118 &brutto), 1119 GNUNET_JSON_pack_array_steal ("outputs", 1120 outputs)); 1121 choices = json_array (); 1122 GNUNET_assert (NULL != choices); 1123 GNUNET_assert (0 == 1124 json_array_append_new ( 1125 choices, 1126 choice)); 1127 GNUNET_assert (0 == 1128 json_object_set_new (ps->order_terms, 1129 "choices", 1130 choices) 1131 ); 1132 GNUNET_assert (0 == 1133 json_object_set_new (ps->order_terms, 1134 "version", 1135 json_integer (1)) 1136 ); 1137 1138 1139 ps->http_status = http_status; 1140 ps->expected_order_id = order_id; 1141 ps->merchant_url = merchant_url; 1142 ps->with_claim = true; 1143 { 1144 struct TALER_TESTING_Command cmd = { 1145 .cls = ps, 1146 .label = label, 1147 .run = &orders_run3, 1148 .cleanup = &orders_cleanup, 1149 .traits = &orders_traits 1150 }; 1151 1152 return cmd; 1153 } 1154 }