testing_api_cmd_post_orders.c (32544B)
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 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 if (NULL == por->details.ok.token) 320 prev_token = &zero_token; 321 if (0 != GNUNET_memcmp (prev_token, 322 por->details.ok.token)) 323 { 324 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 325 "Claim tokens for identical requests do not match\n"); 326 TALER_TESTING_interpreter_fail (ps->is); 327 return; 328 } 329 } 330 break; 331 case MHD_HTTP_NOT_FOUND: 332 TALER_TESTING_interpreter_next (ps->is); 333 return; 334 case MHD_HTTP_GONE: 335 TALER_TESTING_interpreter_next (ps->is); 336 return; 337 case MHD_HTTP_CONFLICT: 338 TALER_TESTING_interpreter_next (ps->is); 339 return; 340 default: 341 { 342 char *s = json_dumps (por->hr.reply, 343 JSON_COMPACT); 344 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 345 "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n", 346 por->hr.http_status, 347 (int) por->hr.ec, 348 TALER_TESTING_interpreter_get_current_label (ps->is), 349 s); 350 free (s); 351 /** 352 * Not failing, as test cases are _supposed_ 353 * to create non 200 OK situations. 354 */ 355 TALER_TESTING_interpreter_next (ps->is); 356 } 357 return; 358 } 359 360 if (! ps->with_claim) 361 { 362 TALER_TESTING_interpreter_next (ps->is); 363 return; 364 } 365 ps->och = TALER_MERCHANT_post_orders_claim_create ( 366 TALER_TESTING_interpreter_get_context (ps->is), 367 ps->merchant_url, 368 ps->order_id, 369 &ps->nonce); 370 if (NULL == ps->och) 371 TALER_TESTING_FAIL (ps->is); 372 TALER_MERCHANT_post_orders_claim_set_options ( 373 ps->och, 374 TALER_MERCHANT_post_orders_claim_option_token ( 375 &ps->claim_token)); 376 { 377 enum TALER_ErrorCode ec; 378 379 ec = TALER_MERCHANT_post_orders_claim_start (ps->och, 380 &orders_claim_cb, 381 ps); 382 GNUNET_assert (TALER_EC_NONE == ec); 383 } 384 } 385 386 387 /** 388 * Run a "orders" CMD. 389 * 390 * @param cls closure. 391 * @param cmd command currently being run. 392 * @param is interpreter state. 393 */ 394 static void 395 orders_run (void *cls, 396 const struct TALER_TESTING_Command *cmd, 397 struct TALER_TESTING_Interpreter *is) 398 { 399 struct OrdersState *ps = cls; 400 401 ps->is = is; 402 if (NULL == json_object_get (ps->order_terms, 403 "order_id")) 404 { 405 struct GNUNET_TIME_Absolute now; 406 char *order_id; 407 408 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 409 order_id = GNUNET_STRINGS_data_to_string_alloc ( 410 &now, 411 sizeof (now)); 412 GNUNET_assert (0 == 413 json_object_set_new (ps->order_terms, 414 "order_id", 415 json_string (order_id))); 416 GNUNET_free (order_id); 417 } 418 GNUNET_CRYPTO_random_block (&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 (&ps->nonce, 506 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 507 for (token = strtok (products_string, ";"); 508 NULL != token; 509 token = strtok (NULL, ";")) 510 { 511 char *ctok; 512 struct TALER_MERCHANT_PostPrivateOrdersInventoryProduct pd; 513 double quantity_double = 0.0; 514 515 /* Token syntax is "[product_id]/[quantity]" */ 516 ctok = strchr (token, '/'); 517 if (NULL != ctok) 518 { 519 *ctok = '\0'; 520 ctok++; 521 { 522 char *endptr; 523 524 quantity_double = strtod (ctok, 525 &endptr); 526 if ( (endptr == ctok) || ('\0' != *endptr) || 527 (! isfinite (quantity_double)) || (quantity_double < 0.0)) 528 { 529 GNUNET_break (0); 530 break; 531 } 532 } 533 } 534 else 535 { 536 quantity_double = 1.0; 537 } 538 if (quantity_double <= 0.0) 539 { 540 GNUNET_break (0); 541 break; 542 } 543 544 { 545 double quantity_floor; 546 double frac; 547 uint64_t quantity_int; 548 uint32_t quantity_frac_local = 0; 549 long long scaled; 550 551 quantity_floor = floor (quantity_double); 552 frac = quantity_double - quantity_floor; 553 quantity_int = (uint64_t) quantity_floor; 554 if (frac < 0.0) 555 { 556 GNUNET_break (0); 557 break; 558 } 559 scaled = llround (frac * (double) TALER_MERCHANT_UNIT_FRAC_BASE); 560 if (scaled < 0) 561 { 562 GNUNET_break (0); 563 break; 564 } 565 if (scaled >= (long long) TALER_MERCHANT_UNIT_FRAC_BASE) 566 { 567 quantity_int++; 568 scaled -= TALER_MERCHANT_UNIT_FRAC_BASE; 569 } 570 quantity_frac_local = (uint32_t) scaled; 571 pd.quantity = quantity_int; 572 pd.quantity_frac = quantity_frac_local; 573 pd.use_fractional_quantity = (0 != quantity_frac_local); 574 } 575 pd.product_id = token; 576 577 GNUNET_array_append (products, 578 products_length, 579 pd); 580 } 581 for (token = strtok (locks_string, ";"); 582 NULL != token; 583 token = strtok (NULL, ";")) 584 { 585 const struct TALER_TESTING_Command *lock_cmd; 586 const char *uuid; 587 588 lock_cmd = TALER_TESTING_interpreter_lookup_command ( 589 is, 590 token); 591 592 if (GNUNET_OK != 593 TALER_TESTING_get_trait_lock_uuid (lock_cmd, 594 &uuid)) 595 { 596 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 597 "Could not fetch lock uuid\n"); 598 TALER_TESTING_interpreter_fail (is); 599 return; 600 } 601 602 GNUNET_array_append (locks, 603 locks_length, 604 uuid); 605 } 606 ps->po = TALER_MERCHANT_post_private_orders_create ( 607 TALER_TESTING_interpreter_get_context (is), 608 ps->merchant_url, 609 order); 610 GNUNET_assert (NULL != ps->po); 611 if (NULL != ps->payment_target) 612 TALER_MERCHANT_post_private_orders_set_options ( 613 ps->po, 614 TALER_MERCHANT_post_private_orders_option_payment_target ( 615 ps->payment_target)); 616 if (0 < products_length) 617 TALER_MERCHANT_post_private_orders_set_options ( 618 ps->po, 619 TALER_MERCHANT_post_private_orders_option_inventory_products ( 620 products_length, products)); 621 if (0 < locks_length) 622 TALER_MERCHANT_post_private_orders_set_options ( 623 ps->po, 624 TALER_MERCHANT_post_private_orders_option_lock_uuids ( 625 locks_length, locks)); 626 TALER_MERCHANT_post_private_orders_set_options ( 627 ps->po, 628 TALER_MERCHANT_post_private_orders_option_create_token ( 629 ps->make_claim_token)); 630 { 631 enum TALER_ErrorCode ec; 632 633 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 634 &order_cb, 635 ps); 636 GNUNET_assert (TALER_EC_NONE == ec); 637 } 638 GNUNET_free (products_string); 639 GNUNET_free (locks_string); 640 GNUNET_array_grow (products, 641 products_length, 642 0); 643 GNUNET_array_grow (locks, 644 locks_length, 645 0); 646 } 647 648 649 /** 650 * Run a "orders" CMD. 651 * 652 * @param cls closure. 653 * @param cmd command currently being run. 654 * @param is interpreter state. 655 */ 656 static void 657 orders_run3 (void *cls, 658 const struct TALER_TESTING_Command *cmd, 659 struct TALER_TESTING_Interpreter *is) 660 { 661 struct OrdersState *ps = cls; 662 struct GNUNET_TIME_Absolute now; 663 664 ps->is = is; 665 now = GNUNET_TIME_absolute_get_monotonic (ps->cfg); 666 if (NULL == json_object_get (ps->order_terms, 667 "order_id")) 668 { 669 char *order_id; 670 671 order_id = GNUNET_STRINGS_data_to_string_alloc ( 672 &now, 673 sizeof (now)); 674 GNUNET_assert (0 == 675 json_object_set_new (ps->order_terms, 676 "order_id", 677 json_string (order_id))); 678 GNUNET_free (order_id); 679 } 680 681 GNUNET_CRYPTO_random_block (&ps->nonce, 682 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 683 ps->po = TALER_MERCHANT_post_private_orders_create ( 684 TALER_TESTING_interpreter_get_context (is), 685 ps->merchant_url, 686 ps->order_terms); 687 GNUNET_assert (NULL != ps->po); 688 { 689 enum TALER_ErrorCode ec; 690 691 ec = TALER_MERCHANT_post_private_orders_start (ps->po, 692 &order_cb, 693 ps); 694 GNUNET_assert (TALER_EC_NONE == ec); 695 } 696 } 697 698 699 /** 700 * Free the state of a "orders" CMD, and possibly 701 * cancel it if it did not complete. 702 * 703 * @param cls closure. 704 * @param cmd command being freed. 705 */ 706 static void 707 orders_cleanup (void *cls, 708 const struct TALER_TESTING_Command *cmd) 709 { 710 struct OrdersState *ps = cls; 711 712 if (NULL != ps->po) 713 { 714 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 715 "Command '%s' did not complete (orders put)\n", 716 cmd->label); 717 TALER_MERCHANT_post_private_orders_cancel (ps->po); 718 ps->po = NULL; 719 } 720 721 if (NULL != ps->och) 722 { 723 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 724 "Command '%s' did not complete (orders lookup)\n", 725 cmd->label); 726 TALER_MERCHANT_post_orders_claim_cancel (ps->och); 727 ps->och = NULL; 728 } 729 730 json_decref (ps->contract_terms); 731 json_decref (ps->order_terms); 732 GNUNET_free_nz ((void *) ps->order_id); 733 GNUNET_free (ps); 734 } 735 736 737 /** 738 * Mark part of the contract terms as possible to forget. 739 * 740 * @param cls pointer to the result of the forget operation. 741 * @param object_id name of the object to forget. 742 * @param parent parent of the object at @e object_id. 743 */ 744 static void 745 mark_forgettable (void *cls, 746 const char *object_id, 747 json_t *parent) 748 { 749 GNUNET_assert (GNUNET_OK == 750 TALER_JSON_contract_mark_forgettable (parent, 751 object_id)); 752 } 753 754 755 /** 756 * Constructs the json for a POST order request. 757 * 758 * @param order_id the name of the order to add, can be NULL. 759 * @param refund_deadline the deadline for refunds on this order. 760 * @param pay_deadline the deadline for payment on this order. 761 * @param amount the amount this order is for, NULL for v1 orders 762 * @param[out] order where to write the json string. 763 */ 764 static void 765 make_order_json (const char *order_id, 766 struct GNUNET_TIME_Timestamp refund_deadline, 767 struct GNUNET_TIME_Timestamp pay_deadline, 768 const char *amount, 769 json_t **order) 770 { 771 struct GNUNET_TIME_Timestamp refund = refund_deadline; 772 struct GNUNET_TIME_Timestamp pay = pay_deadline; 773 json_t *contract_terms; 774 775 /* Include required fields and some dummy objects to test forgetting. */ 776 contract_terms = json_pack ( 777 "{s:s, s:s?, s:s?, s:s, s:o, s:o, s:s, s:[{s:s}, {s:s}, {s:s}]}", 778 "summary", "merchant-lib testcase", 779 "order_id", order_id, 780 "amount", amount, 781 "fulfillment_url", "https://example.com", 782 "refund_deadline", GNUNET_JSON_from_timestamp (refund), 783 "pay_deadline", GNUNET_JSON_from_timestamp (pay), 784 "dummy_obj", "EUR:1.0", 785 "dummy_array", /* For testing forgetting parts of arrays */ 786 "item", "speakers", 787 "item", "headphones", 788 "item", "earbuds"); 789 GNUNET_assert (GNUNET_OK == 790 TALER_JSON_expand_path (contract_terms, 791 "$.dummy_obj", 792 &mark_forgettable, 793 NULL)); 794 GNUNET_assert (GNUNET_OK == 795 TALER_JSON_expand_path (contract_terms, 796 "$.dummy_array[*].item", 797 &mark_forgettable, 798 NULL)); 799 *order = contract_terms; 800 } 801 802 803 struct TALER_TESTING_Command 804 TALER_TESTING_cmd_merchant_post_orders_no_claim ( 805 const char *label, 806 const char *merchant_url, 807 unsigned int http_status, 808 const char *order_id, 809 struct GNUNET_TIME_Timestamp refund_deadline, 810 struct GNUNET_TIME_Timestamp pay_deadline, 811 const char *amount) 812 { 813 struct OrdersState *ps; 814 815 ps = GNUNET_new (struct OrdersState); 816 make_order_json (order_id, 817 refund_deadline, 818 pay_deadline, 819 amount, 820 &ps->order_terms); 821 ps->http_status = http_status; 822 ps->expected_order_id = order_id; 823 ps->merchant_url = merchant_url; 824 { 825 struct TALER_TESTING_Command cmd = { 826 .cls = ps, 827 .label = label, 828 .run = &orders_run, 829 .cleanup = &orders_cleanup, 830 .traits = &orders_traits 831 }; 832 833 return cmd; 834 } 835 } 836 837 838 struct TALER_TESTING_Command 839 TALER_TESTING_cmd_merchant_post_orders ( 840 const char *label, 841 const struct GNUNET_CONFIGURATION_Handle *cfg, 842 const char *merchant_url, 843 unsigned int http_status, 844 const char *order_id, 845 struct GNUNET_TIME_Timestamp refund_deadline, 846 struct GNUNET_TIME_Timestamp pay_deadline, 847 const char *amount) 848 { 849 struct OrdersState *ps; 850 851 ps = GNUNET_new (struct OrdersState); 852 ps->cfg = cfg; 853 make_order_json (order_id, 854 refund_deadline, 855 pay_deadline, 856 amount, 857 &ps->order_terms); 858 ps->http_status = http_status; 859 ps->expected_order_id = order_id; 860 ps->merchant_url = merchant_url; 861 ps->with_claim = true; 862 { 863 struct TALER_TESTING_Command cmd = { 864 .cls = ps, 865 .label = label, 866 .run = &orders_run, 867 .cleanup = &orders_cleanup, 868 .traits = &orders_traits 869 }; 870 871 return cmd; 872 } 873 } 874 875 876 struct TALER_TESTING_Command 877 TALER_TESTING_cmd_merchant_post_orders2 ( 878 const char *label, 879 const struct GNUNET_CONFIGURATION_Handle *cfg, 880 const char *merchant_url, 881 unsigned int http_status, 882 const char *order_id, 883 struct GNUNET_TIME_Timestamp refund_deadline, 884 struct GNUNET_TIME_Timestamp pay_deadline, 885 bool claim_token, 886 const char *amount, 887 const char *payment_target, 888 const char *products, 889 const char *locks, 890 const char *duplicate_of) 891 { 892 struct OrdersState *ps; 893 894 ps = GNUNET_new (struct OrdersState); 895 ps->cfg = cfg; 896 make_order_json (order_id, 897 refund_deadline, 898 pay_deadline, 899 amount, 900 &ps->order_terms); 901 ps->http_status = http_status; 902 ps->expected_order_id = order_id; 903 ps->merchant_url = merchant_url; 904 ps->payment_target = payment_target; 905 ps->products = products; 906 ps->locks = locks; 907 ps->with_claim = (NULL == duplicate_of); 908 ps->make_claim_token = claim_token; 909 ps->duplicate_of = duplicate_of; 910 { 911 struct TALER_TESTING_Command cmd = { 912 .cls = ps, 913 .label = label, 914 .run = &orders_run2, 915 .cleanup = &orders_cleanup, 916 .traits = &orders_traits 917 }; 918 919 return cmd; 920 } 921 } 922 923 924 struct TALER_TESTING_Command 925 TALER_TESTING_cmd_merchant_post_orders3 ( 926 const char *label, 927 const struct GNUNET_CONFIGURATION_Handle *cfg, 928 const char *merchant_url, 929 unsigned int expected_http_status, 930 const char *order_id, 931 struct GNUNET_TIME_Timestamp refund_deadline, 932 struct GNUNET_TIME_Timestamp pay_deadline, 933 const char *fulfillment_url, 934 const char *amount) 935 { 936 struct OrdersState *ps; 937 938 ps = GNUNET_new (struct OrdersState); 939 ps->cfg = cfg; 940 make_order_json (order_id, 941 refund_deadline, 942 pay_deadline, 943 amount, 944 &ps->order_terms); 945 GNUNET_assert (0 == 946 json_object_set_new (ps->order_terms, 947 "fulfillment_url", 948 json_string (fulfillment_url))); 949 ps->http_status = expected_http_status; 950 ps->merchant_url = merchant_url; 951 ps->with_claim = true; 952 { 953 struct TALER_TESTING_Command cmd = { 954 .cls = ps, 955 .label = label, 956 .run = &orders_run, 957 .cleanup = &orders_cleanup, 958 .traits = &orders_traits 959 }; 960 961 return cmd; 962 } 963 } 964 965 966 struct TALER_TESTING_Command 967 TALER_TESTING_cmd_merchant_post_orders_choices ( 968 const char *label, 969 const struct GNUNET_CONFIGURATION_Handle *cfg, 970 const char *merchant_url, 971 unsigned int http_status, 972 const char *token_family_slug, 973 const char *choice_description, 974 json_t *choice_description_i18n, 975 unsigned int num_inputs, 976 unsigned int num_outputs, 977 const char *order_id, 978 struct GNUNET_TIME_Timestamp refund_deadline, 979 struct GNUNET_TIME_Timestamp pay_deadline, 980 const char *amount) 981 { 982 struct OrdersState *ps; 983 struct TALER_Amount brutto; 984 json_t *choice; 985 json_t *choices; 986 json_t *inputs; 987 json_t *outputs; 988 989 ps = GNUNET_new (struct OrdersState); 990 ps->cfg = cfg; 991 make_order_json (order_id, 992 refund_deadline, 993 pay_deadline, 994 NULL, 995 &ps->order_terms); 996 GNUNET_assert (GNUNET_OK == 997 TALER_string_to_amount (amount, 998 &brutto)); 999 inputs = json_array (); 1000 GNUNET_assert (NULL != inputs); 1001 GNUNET_assert (0 == 1002 json_array_append_new ( 1003 inputs, 1004 GNUNET_JSON_PACK ( 1005 GNUNET_JSON_pack_string ("type", 1006 "token"), 1007 GNUNET_JSON_pack_uint64 ("count", 1008 num_inputs), 1009 GNUNET_JSON_pack_string ("token_family_slug", 1010 token_family_slug) 1011 ))); 1012 outputs = json_array (); 1013 GNUNET_assert (NULL != outputs); 1014 GNUNET_assert (0 == 1015 json_array_append_new ( 1016 outputs, 1017 GNUNET_JSON_PACK ( 1018 GNUNET_JSON_pack_string ("type", 1019 "token"), 1020 GNUNET_JSON_pack_uint64 ("count", 1021 num_outputs), 1022 GNUNET_JSON_pack_string ("token_family_slug", 1023 token_family_slug) 1024 ))); 1025 choice 1026 = GNUNET_JSON_PACK ( 1027 TALER_JSON_pack_amount ("amount", 1028 &brutto), 1029 GNUNET_JSON_pack_allow_null ( 1030 GNUNET_JSON_pack_string ("description", 1031 choice_description)), 1032 GNUNET_JSON_pack_allow_null ( 1033 GNUNET_JSON_pack_object_steal ("description_i18n", 1034 choice_description_i18n)), 1035 GNUNET_JSON_pack_array_steal ("inputs", 1036 inputs), 1037 GNUNET_JSON_pack_array_steal ("outputs", 1038 outputs)); 1039 choices = json_array (); 1040 GNUNET_assert (NULL != choices); 1041 GNUNET_assert (0 == 1042 json_array_append_new ( 1043 choices, 1044 choice)); 1045 GNUNET_assert (0 == 1046 json_object_set_new (ps->order_terms, 1047 "choices", 1048 choices) 1049 ); 1050 GNUNET_assert (0 == 1051 json_object_set_new (ps->order_terms, 1052 "version", 1053 json_integer (1)) 1054 ); 1055 1056 1057 ps->http_status = http_status; 1058 ps->expected_order_id = order_id; 1059 ps->merchant_url = merchant_url; 1060 ps->with_claim = true; 1061 { 1062 struct TALER_TESTING_Command cmd = { 1063 .cls = ps, 1064 .label = label, 1065 .run = &orders_run3, 1066 .cleanup = &orders_cleanup, 1067 .traits = &orders_traits 1068 }; 1069 1070 return cmd; 1071 } 1072 } 1073 1074 1075 struct TALER_TESTING_Command 1076 TALER_TESTING_cmd_merchant_post_orders_donau ( 1077 const char *label, 1078 const struct GNUNET_CONFIGURATION_Handle *cfg, 1079 const char *merchant_url, 1080 unsigned int http_status, 1081 const char *order_id, 1082 struct GNUNET_TIME_Timestamp refund_deadline, 1083 struct GNUNET_TIME_Timestamp pay_deadline, 1084 const char *amount) 1085 { 1086 struct OrdersState *ps; 1087 struct TALER_Amount brutto; 1088 json_t *choice; 1089 json_t *choices; 1090 json_t *outputs; 1091 1092 ps = GNUNET_new (struct OrdersState); 1093 ps->cfg = cfg; 1094 make_order_json (order_id, 1095 refund_deadline, 1096 pay_deadline, 1097 NULL, 1098 &ps->order_terms); 1099 GNUNET_assert (GNUNET_OK == 1100 TALER_string_to_amount (amount, 1101 &brutto)); 1102 1103 outputs = json_array (); 1104 GNUNET_assert (NULL != outputs); 1105 GNUNET_assert (0 == 1106 json_array_append_new ( 1107 outputs, 1108 GNUNET_JSON_PACK ( 1109 GNUNET_JSON_pack_string ("type", 1110 "tax-receipt") 1111 ))); 1112 choice 1113 = GNUNET_JSON_PACK ( 1114 TALER_JSON_pack_amount ("amount", 1115 &brutto), 1116 GNUNET_JSON_pack_array_steal ("outputs", 1117 outputs)); 1118 choices = json_array (); 1119 GNUNET_assert (NULL != choices); 1120 GNUNET_assert (0 == 1121 json_array_append_new ( 1122 choices, 1123 choice)); 1124 GNUNET_assert (0 == 1125 json_object_set_new (ps->order_terms, 1126 "choices", 1127 choices) 1128 ); 1129 GNUNET_assert (0 == 1130 json_object_set_new (ps->order_terms, 1131 "version", 1132 json_integer (1)) 1133 ); 1134 1135 1136 ps->http_status = http_status; 1137 ps->expected_order_id = order_id; 1138 ps->merchant_url = merchant_url; 1139 ps->with_claim = true; 1140 { 1141 struct TALER_TESTING_Command cmd = { 1142 .cls = ps, 1143 .label = label, 1144 .run = &orders_run3, 1145 .cleanup = &orders_cleanup, 1146 .traits = &orders_traits 1147 }; 1148 1149 return cmd; 1150 } 1151 }