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