testing_api_cmd_post_orders.c (35104B)
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 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 const struct TALER_ClaimTokenP *resp_token; 306 307 order_cmd = TALER_TESTING_interpreter_lookup_command ( 308 ps->is, 309 ps->duplicate_of); 310 if (GNUNET_OK != 311 TALER_TESTING_get_trait_claim_token (order_cmd, 312 &prev_token)) 313 { 314 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 315 "Could not fetch previous order claim token\n"); 316 TALER_TESTING_interpreter_fail (ps->is); 317 return; 318 } 319 320 resp_token = (NULL != por->details.ok.token) 321 ? por->details.ok.token 322 : &zero_token; 323 if (0 != GNUNET_memcmp (prev_token, 324 resp_token)) 325 { 326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 327 "Claim tokens for identical requests do not match\n"); 328 TALER_TESTING_interpreter_fail (ps->is); 329 return; 330 } 331 } 332 break; 333 case MHD_HTTP_NOT_FOUND: 334 TALER_TESTING_interpreter_next (ps->is); 335 return; 336 case MHD_HTTP_GONE: 337 TALER_TESTING_interpreter_next (ps->is); 338 return; 339 case MHD_HTTP_CONFLICT: 340 TALER_TESTING_interpreter_next (ps->is); 341 return; 342 default: 343 { 344 char *s = json_dumps (por->hr.reply, 345 JSON_COMPACT); 346 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 347 "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n", 348 por->hr.http_status, 349 (int) por->hr.ec, 350 TALER_TESTING_interpreter_get_current_label (ps->is), 351 s); 352 free (s); 353 /** 354 * Not failing, as test cases are _supposed_ 355 * to create non 200 OK situations. 356 */ 357 TALER_TESTING_interpreter_next (ps->is); 358 } 359 return; 360 } 361 362 if (! ps->with_claim) 363 { 364 TALER_TESTING_interpreter_next (ps->is); 365 return; 366 } 367 ps->och = TALER_MERCHANT_post_orders_claim_create ( 368 TALER_TESTING_interpreter_get_context (ps->is), 369 ps->merchant_url, 370 ps->order_id, 371 &ps->nonce); 372 if (NULL == ps->och) 373 TALER_TESTING_FAIL (ps->is); 374 TALER_MERCHANT_post_orders_claim_set_options ( 375 ps->och, 376 TALER_MERCHANT_post_orders_claim_option_token ( 377 &ps->claim_token)); 378 { 379 enum TALER_ErrorCode ec; 380 381 ec = TALER_MERCHANT_post_orders_claim_start (ps->och, 382 &orders_claim_cb, 383 ps); 384 GNUNET_assert (TALER_EC_NONE == ec); 385 } 386 } 387 388 389 /** 390 * Run a "orders" CMD. 391 * 392 * @param cls closure. 393 * @param cmd command currently being run. 394 * @param is interpreter state. 395 */ 396 static void 397 orders_run (void *cls, 398 const struct TALER_TESTING_Command *cmd, 399 struct TALER_TESTING_Interpreter *is) 400 { 401 struct OrdersState *ps = cls; 402 403 ps->is = is; 404 if (NULL == json_object_get (ps->order_terms, 405 "order_id")) 406 { 407 struct GNUNET_TIME_Absolute now; 408 char *order_id; 409 410 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 411 order_id = GNUNET_STRINGS_data_to_string_alloc ( 412 &now, 413 sizeof (now)); 414 GNUNET_assert (0 == 415 json_object_set_new (ps->order_terms, 416 "order_id", 417 json_string (order_id))); 418 GNUNET_free (order_id); 419 } 420 GNUNET_CRYPTO_random_block (&ps->nonce, 421 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 422 ps->po = TALER_MERCHANT_post_private_orders_create ( 423 TALER_TESTING_interpreter_get_context (is), 424 ps->merchant_url, 425 ps->order_terms); 426 GNUNET_assert (NULL != ps->po); 427 { 428 enum TALER_ErrorCode ec; 429 430 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 431 &order_cb, 432 ps); 433 GNUNET_assert (TALER_EC_NONE == ec); 434 } 435 } 436 437 438 /** 439 * Run a "orders" CMD. 440 * 441 * @param cls closure. 442 * @param cmd command currently being run. 443 * @param is interpreter state. 444 */ 445 static void 446 orders_run2 (void *cls, 447 const struct TALER_TESTING_Command *cmd, 448 struct TALER_TESTING_Interpreter *is) 449 { 450 struct OrdersState *ps = cls; 451 const json_t *order; 452 char *products_string = GNUNET_strdup (ps->products); 453 char *locks_string = GNUNET_strdup (ps->locks); 454 char *token; 455 struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct *products = NULL; 456 unsigned int products_length = 0; 457 const char **locks = NULL; 458 unsigned int locks_length = 0; 459 460 ps->is = is; 461 if (NULL != ps->duplicate_of) 462 { 463 const struct TALER_TESTING_Command *order_cmd; 464 const json_t *ct; 465 466 order_cmd = TALER_TESTING_interpreter_lookup_command ( 467 is, 468 ps->duplicate_of); 469 if (GNUNET_OK != 470 TALER_TESTING_get_trait_order_terms (order_cmd, 471 &ct)) 472 { 473 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 474 "Could not fetch previous order string\n"); 475 TALER_TESTING_interpreter_fail (is); 476 return; 477 } 478 order = (json_t *) ct; 479 } 480 else 481 { 482 if (NULL == json_object_get (ps->order_terms, 483 "order_id")) 484 { 485 struct GNUNET_TIME_Absolute now; 486 char *order_id; 487 488 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 489 order_id = GNUNET_STRINGS_data_to_string_alloc ( 490 &now.abs_value_us, 491 sizeof (now.abs_value_us)); 492 GNUNET_assert (0 == 493 json_object_set_new (ps->order_terms, 494 "order_id", 495 json_string (order_id))); 496 GNUNET_free (order_id); 497 } 498 order = ps->order_terms; 499 } 500 if (NULL == order) 501 { 502 GNUNET_break (0); 503 TALER_TESTING_interpreter_fail (is); 504 return; 505 } 506 507 GNUNET_CRYPTO_random_block (&ps->nonce, 508 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 509 for (token = strtok (products_string, ";"); 510 NULL != token; 511 token = strtok (NULL, ";")) 512 { 513 char *ctok; 514 struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct pd; 515 double quantity_double = 0.0; 516 517 /* Token syntax is "[product_id]/[quantity]" */ 518 ctok = strchr (token, '/'); 519 if (NULL != ctok) 520 { 521 *ctok = '\0'; 522 ctok++; 523 { 524 char *endptr; 525 526 quantity_double = strtod (ctok, 527 &endptr); 528 if ( (endptr == ctok) || ('\0' != *endptr) || 529 (! isfinite (quantity_double)) || (quantity_double < 0.0)) 530 { 531 GNUNET_break (0); 532 break; 533 } 534 } 535 } 536 else 537 { 538 quantity_double = 1.0; 539 } 540 if (quantity_double <= 0.0) 541 { 542 GNUNET_break (0); 543 break; 544 } 545 546 { 547 double quantity_floor; 548 double frac; 549 uint64_t quantity_int; 550 uint32_t quantity_frac_local = 0; 551 long long scaled; 552 553 quantity_floor = floor (quantity_double); 554 frac = quantity_double - quantity_floor; 555 quantity_int = (uint64_t) quantity_floor; 556 if (frac < 0.0) 557 { 558 GNUNET_break (0); 559 break; 560 } 561 scaled = llround (frac * (double) TALER_MERCHANT_UNIT_FRAC_BASE); 562 if (scaled < 0) 563 { 564 GNUNET_break (0); 565 break; 566 } 567 if (scaled >= (long long) TALER_MERCHANT_UNIT_FRAC_BASE) 568 { 569 quantity_int++; 570 scaled -= TALER_MERCHANT_UNIT_FRAC_BASE; 571 } 572 quantity_frac_local = (uint32_t) scaled; 573 pd.quantity = quantity_int; 574 pd.quantity_frac = quantity_frac_local; 575 pd.use_fractional_quantity = (0 != quantity_frac_local); 576 } 577 pd.product_id = token; 578 579 GNUNET_array_append (products, 580 products_length, 581 pd); 582 } 583 for (token = strtok (locks_string, ";"); 584 NULL != token; 585 token = strtok (NULL, ";")) 586 { 587 const struct TALER_TESTING_Command *lock_cmd; 588 const char *uuid; 589 590 lock_cmd = TALER_TESTING_interpreter_lookup_command ( 591 is, 592 token); 593 594 if (GNUNET_OK != 595 TALER_TESTING_get_trait_lock_uuid (lock_cmd, 596 &uuid)) 597 { 598 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 599 "Could not fetch lock uuid\n"); 600 TALER_TESTING_interpreter_fail (is); 601 return; 602 } 603 604 GNUNET_array_append (locks, 605 locks_length, 606 uuid); 607 } 608 ps->po = TALER_MERCHANT_post_private_orders_create ( 609 TALER_TESTING_interpreter_get_context (is), 610 ps->merchant_url, 611 order); 612 GNUNET_assert (NULL != ps->po); 613 if (NULL != ps->payment_target) 614 TALER_MERCHANT_post_private_orders_set_options ( 615 ps->po, 616 TALER_MERCHANT_post_private_orders_option_payment_target ( 617 ps->payment_target)); 618 if (0 < products_length) 619 TALER_MERCHANT_post_private_orders_set_options ( 620 ps->po, 621 TALER_MERCHANT_post_private_orders_option_inventory_products ( 622 products_length, products)); 623 if (0 < locks_length) 624 TALER_MERCHANT_post_private_orders_set_options ( 625 ps->po, 626 TALER_MERCHANT_post_private_orders_option_lock_uuids ( 627 locks_length, locks)); 628 TALER_MERCHANT_post_private_orders_set_options ( 629 ps->po, 630 TALER_MERCHANT_post_private_orders_option_create_token ( 631 ps->make_claim_token)); 632 { 633 enum TALER_ErrorCode ec; 634 635 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 636 &order_cb, 637 ps); 638 GNUNET_assert (TALER_EC_NONE == ec); 639 } 640 GNUNET_free (products_string); 641 GNUNET_free (locks_string); 642 GNUNET_array_grow (products, 643 products_length, 644 0); 645 GNUNET_array_grow (locks, 646 locks_length, 647 0); 648 } 649 650 651 /** 652 * Run a "orders" CMD. 653 * 654 * @param cls closure. 655 * @param cmd command currently being run. 656 * @param is interpreter state. 657 */ 658 static void 659 orders_run3 (void *cls, 660 const struct TALER_TESTING_Command *cmd, 661 struct TALER_TESTING_Interpreter *is) 662 { 663 struct OrdersState *ps = cls; 664 struct GNUNET_TIME_Absolute now; 665 666 ps->is = is; 667 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 668 if (NULL == json_object_get (ps->order_terms, 669 "order_id")) 670 { 671 char *order_id; 672 673 order_id = GNUNET_STRINGS_data_to_string_alloc ( 674 &now, 675 sizeof (now)); 676 GNUNET_assert (0 == 677 json_object_set_new (ps->order_terms, 678 "order_id", 679 json_string (order_id))); 680 GNUNET_free (order_id); 681 } 682 683 GNUNET_CRYPTO_random_block (&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_external ( 842 const char *label, 843 const char *merchant_url, 844 unsigned int http_status, 845 const char *order_id, 846 struct GNUNET_TIME_Timestamp refund_deadline, 847 struct GNUNET_TIME_Timestamp pay_deadline, 848 const char *amount, 849 const char *amount_external) 850 { 851 struct OrdersState *ps; 852 853 ps = GNUNET_new (struct OrdersState); 854 make_order_json (order_id, 855 refund_deadline, 856 pay_deadline, 857 amount, 858 &ps->order_terms); 859 { 860 json_t *ae; 861 862 ae = json_loads (amount_external, 863 0, 864 NULL); 865 GNUNET_assert (NULL != ae); 866 GNUNET_assert (0 == 867 json_object_set_new (ps->order_terms, 868 "amount_external", 869 ae)); 870 } 871 ps->http_status = http_status; 872 ps->expected_order_id = order_id; 873 ps->merchant_url = merchant_url; 874 { 875 struct TALER_TESTING_Command cmd = { 876 .cls = ps, 877 .label = label, 878 .run = &orders_run, 879 .cleanup = &orders_cleanup, 880 .traits = &orders_traits 881 }; 882 883 return cmd; 884 } 885 } 886 887 888 struct TALER_TESTING_Command 889 TALER_TESTING_cmd_merchant_post_orders_v1 ( 890 const char *label, 891 const char *merchant_url, 892 unsigned int http_status, 893 const char *order_id, 894 struct GNUNET_TIME_Timestamp refund_deadline, 895 struct GNUNET_TIME_Timestamp pay_deadline, 896 const char *choices) 897 { 898 struct OrdersState *ps; 899 900 ps = GNUNET_new (struct OrdersState); 901 make_order_json (order_id, 902 refund_deadline, 903 pay_deadline, 904 NULL, 905 &ps->order_terms); 906 { 907 json_t *cs; 908 909 cs = json_loads (choices, 910 0, 911 NULL); 912 GNUNET_assert (NULL != cs); 913 GNUNET_assert (0 == 914 json_object_set_new (ps->order_terms, 915 "choices", 916 cs)); 917 } 918 GNUNET_assert (0 == 919 json_object_set_new (ps->order_terms, 920 "version", 921 json_integer (1))); 922 ps->http_status = http_status; 923 ps->expected_order_id = order_id; 924 ps->merchant_url = merchant_url; 925 { 926 struct TALER_TESTING_Command cmd = { 927 .cls = ps, 928 .label = label, 929 .run = &orders_run, 930 .cleanup = &orders_cleanup, 931 .traits = &orders_traits 932 }; 933 934 return cmd; 935 } 936 } 937 938 939 struct TALER_TESTING_Command 940 TALER_TESTING_cmd_merchant_post_orders ( 941 const char *label, 942 const struct GNUNET_CONFIGURATION_Handle *cfg, 943 const char *merchant_url, 944 unsigned int http_status, 945 const char *order_id, 946 struct GNUNET_TIME_Timestamp refund_deadline, 947 struct GNUNET_TIME_Timestamp pay_deadline, 948 const char *amount) 949 { 950 struct OrdersState *ps; 951 952 ps = GNUNET_new (struct OrdersState); 953 ps->cfg = cfg; 954 make_order_json (order_id, 955 refund_deadline, 956 pay_deadline, 957 amount, 958 &ps->order_terms); 959 ps->http_status = http_status; 960 ps->expected_order_id = order_id; 961 ps->merchant_url = merchant_url; 962 ps->with_claim = true; 963 { 964 struct TALER_TESTING_Command cmd = { 965 .cls = ps, 966 .label = label, 967 .run = &orders_run, 968 .cleanup = &orders_cleanup, 969 .traits = &orders_traits 970 }; 971 972 return cmd; 973 } 974 } 975 976 977 struct TALER_TESTING_Command 978 TALER_TESTING_cmd_merchant_post_orders2 ( 979 const char *label, 980 const struct GNUNET_CONFIGURATION_Handle *cfg, 981 const char *merchant_url, 982 unsigned int http_status, 983 const char *order_id, 984 struct GNUNET_TIME_Timestamp refund_deadline, 985 struct GNUNET_TIME_Timestamp pay_deadline, 986 bool claim_token, 987 const char *amount, 988 const char *payment_target, 989 const char *products, 990 const char *locks, 991 const char *duplicate_of) 992 { 993 struct OrdersState *ps; 994 995 ps = GNUNET_new (struct OrdersState); 996 ps->cfg = cfg; 997 make_order_json (order_id, 998 refund_deadline, 999 pay_deadline, 1000 amount, 1001 &ps->order_terms); 1002 ps->http_status = http_status; 1003 ps->expected_order_id = order_id; 1004 ps->merchant_url = merchant_url; 1005 ps->payment_target = payment_target; 1006 ps->products = products; 1007 ps->locks = locks; 1008 ps->with_claim = (NULL == duplicate_of); 1009 ps->make_claim_token = claim_token; 1010 ps->duplicate_of = duplicate_of; 1011 { 1012 struct TALER_TESTING_Command cmd = { 1013 .cls = ps, 1014 .label = label, 1015 .run = &orders_run2, 1016 .cleanup = &orders_cleanup, 1017 .traits = &orders_traits 1018 }; 1019 1020 return cmd; 1021 } 1022 } 1023 1024 1025 struct TALER_TESTING_Command 1026 TALER_TESTING_cmd_merchant_post_orders3 ( 1027 const char *label, 1028 const struct GNUNET_CONFIGURATION_Handle *cfg, 1029 const char *merchant_url, 1030 unsigned int expected_http_status, 1031 const char *order_id, 1032 struct GNUNET_TIME_Timestamp refund_deadline, 1033 struct GNUNET_TIME_Timestamp pay_deadline, 1034 const char *fulfillment_url, 1035 const char *amount) 1036 { 1037 struct OrdersState *ps; 1038 1039 ps = GNUNET_new (struct OrdersState); 1040 ps->cfg = cfg; 1041 make_order_json (order_id, 1042 refund_deadline, 1043 pay_deadline, 1044 amount, 1045 &ps->order_terms); 1046 GNUNET_assert (0 == 1047 json_object_set_new (ps->order_terms, 1048 "fulfillment_url", 1049 json_string (fulfillment_url))); 1050 ps->http_status = expected_http_status; 1051 ps->merchant_url = merchant_url; 1052 ps->with_claim = true; 1053 { 1054 struct TALER_TESTING_Command cmd = { 1055 .cls = ps, 1056 .label = label, 1057 .run = &orders_run, 1058 .cleanup = &orders_cleanup, 1059 .traits = &orders_traits 1060 }; 1061 1062 return cmd; 1063 } 1064 } 1065 1066 1067 struct TALER_TESTING_Command 1068 TALER_TESTING_cmd_merchant_post_orders_choices ( 1069 const char *label, 1070 const struct GNUNET_CONFIGURATION_Handle *cfg, 1071 const char *merchant_url, 1072 unsigned int http_status, 1073 const char *token_family_slug, 1074 const char *choice_description, 1075 json_t *choice_description_i18n, 1076 unsigned int num_inputs, 1077 unsigned int num_outputs, 1078 const char *order_id, 1079 struct GNUNET_TIME_Timestamp refund_deadline, 1080 struct GNUNET_TIME_Timestamp pay_deadline, 1081 const char *amount) 1082 { 1083 struct OrdersState *ps; 1084 struct TALER_Amount brutto; 1085 json_t *choice; 1086 json_t *choices; 1087 json_t *inputs; 1088 json_t *outputs; 1089 1090 ps = GNUNET_new (struct OrdersState); 1091 ps->cfg = cfg; 1092 make_order_json (order_id, 1093 refund_deadline, 1094 pay_deadline, 1095 NULL, 1096 &ps->order_terms); 1097 GNUNET_assert (GNUNET_OK == 1098 TALER_string_to_amount (amount, 1099 &brutto)); 1100 inputs = json_array (); 1101 GNUNET_assert (NULL != inputs); 1102 GNUNET_assert (0 == 1103 json_array_append_new ( 1104 inputs, 1105 GNUNET_JSON_PACK ( 1106 GNUNET_JSON_pack_string ("type", 1107 "token"), 1108 GNUNET_JSON_pack_uint64 ("count", 1109 num_inputs), 1110 GNUNET_JSON_pack_string ("token_family_slug", 1111 token_family_slug) 1112 ))); 1113 outputs = json_array (); 1114 GNUNET_assert (NULL != outputs); 1115 GNUNET_assert (0 == 1116 json_array_append_new ( 1117 outputs, 1118 GNUNET_JSON_PACK ( 1119 GNUNET_JSON_pack_string ("type", 1120 "token"), 1121 GNUNET_JSON_pack_uint64 ("count", 1122 num_outputs), 1123 GNUNET_JSON_pack_string ("token_family_slug", 1124 token_family_slug) 1125 ))); 1126 choice 1127 = GNUNET_JSON_PACK ( 1128 TALER_JSON_pack_amount ("amount", 1129 &brutto), 1130 GNUNET_JSON_pack_allow_null ( 1131 GNUNET_JSON_pack_string ("description", 1132 choice_description)), 1133 GNUNET_JSON_pack_allow_null ( 1134 GNUNET_JSON_pack_object_steal ("description_i18n", 1135 choice_description_i18n)), 1136 GNUNET_JSON_pack_array_steal ("inputs", 1137 inputs), 1138 GNUNET_JSON_pack_array_steal ("outputs", 1139 outputs)); 1140 choices = json_array (); 1141 GNUNET_assert (NULL != choices); 1142 GNUNET_assert (0 == 1143 json_array_append_new ( 1144 choices, 1145 choice)); 1146 GNUNET_assert (0 == 1147 json_object_set_new (ps->order_terms, 1148 "choices", 1149 choices) 1150 ); 1151 GNUNET_assert (0 == 1152 json_object_set_new (ps->order_terms, 1153 "version", 1154 json_integer (1)) 1155 ); 1156 1157 1158 ps->http_status = http_status; 1159 ps->expected_order_id = order_id; 1160 ps->merchant_url = merchant_url; 1161 ps->with_claim = true; 1162 { 1163 struct TALER_TESTING_Command cmd = { 1164 .cls = ps, 1165 .label = label, 1166 .run = &orders_run3, 1167 .cleanup = &orders_cleanup, 1168 .traits = &orders_traits 1169 }; 1170 1171 return cmd; 1172 } 1173 } 1174 1175 1176 struct TALER_TESTING_Command 1177 TALER_TESTING_cmd_merchant_post_orders_donau ( 1178 const char *label, 1179 const struct GNUNET_CONFIGURATION_Handle *cfg, 1180 const char *merchant_url, 1181 unsigned int http_status, 1182 const char *order_id, 1183 struct GNUNET_TIME_Timestamp refund_deadline, 1184 struct GNUNET_TIME_Timestamp pay_deadline, 1185 const char *amount) 1186 { 1187 struct OrdersState *ps; 1188 struct TALER_Amount brutto; 1189 json_t *choice; 1190 json_t *choices; 1191 json_t *outputs; 1192 1193 ps = GNUNET_new (struct OrdersState); 1194 ps->cfg = cfg; 1195 make_order_json (order_id, 1196 refund_deadline, 1197 pay_deadline, 1198 NULL, 1199 &ps->order_terms); 1200 GNUNET_assert (GNUNET_OK == 1201 TALER_string_to_amount (amount, 1202 &brutto)); 1203 1204 outputs = json_array (); 1205 GNUNET_assert (NULL != outputs); 1206 GNUNET_assert (0 == 1207 json_array_append_new ( 1208 outputs, 1209 GNUNET_JSON_PACK ( 1210 GNUNET_JSON_pack_string ("type", 1211 "tax-receipt") 1212 ))); 1213 choice 1214 = GNUNET_JSON_PACK ( 1215 TALER_JSON_pack_amount ("amount", 1216 &brutto), 1217 GNUNET_JSON_pack_array_steal ("outputs", 1218 outputs)); 1219 choices = json_array (); 1220 GNUNET_assert (NULL != choices); 1221 GNUNET_assert (0 == 1222 json_array_append_new ( 1223 choices, 1224 choice)); 1225 GNUNET_assert (0 == 1226 json_object_set_new (ps->order_terms, 1227 "choices", 1228 choices) 1229 ); 1230 GNUNET_assert (0 == 1231 json_object_set_new (ps->order_terms, 1232 "version", 1233 json_integer (1)) 1234 ); 1235 1236 1237 ps->http_status = http_status; 1238 ps->expected_order_id = order_id; 1239 ps->merchant_url = merchant_url; 1240 ps->with_claim = true; 1241 { 1242 struct TALER_TESTING_Command cmd = { 1243 .cls = ps, 1244 .label = label, 1245 .run = &orders_run3, 1246 .cleanup = &orders_cleanup, 1247 .traits = &orders_traits 1248 }; 1249 1250 return cmd; 1251 } 1252 }