testing_api_cmd_post_orders.c (32570B)
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 ( 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 }