testing_api_cmd_post_using_templates.c (25808B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-2023 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 * @file src/testing/testing_api_cmd_post_using_templates.c 21 * @brief command to test POST /using-templates 22 * @author Priscilla HUANG 23 */ 24 #include "platform.h" 25 struct PostUsingTemplatesState; 26 #define TALER_MERCHANT_POST_TEMPLATES_RESULT_CLOSURE struct PostUsingTemplatesState 27 #define TALER_MERCHANT_POST_ORDERS_CLAIM_RESULT_CLOSURE struct PostUsingTemplatesState 28 #include <taler/taler_exchange_service.h> 29 #include <taler/taler_testing_lib.h> 30 #include "taler/taler_merchant_service.h" 31 #include "taler/taler_merchant_testing_lib.h" 32 #include <taler/merchant/post-templates-TEMPLATE_ID.h> 33 #include <taler/merchant/post-orders-ORDER_ID-claim.h> 34 35 36 /** 37 * State of a "POST /templates" CMD. 38 */ 39 struct PostUsingTemplatesState 40 { 41 42 /** 43 * Handle for a "POST /templates/$TEMPLATE_ID" request. 44 */ 45 struct TALER_MERCHANT_PostTemplatesHandle *iph; 46 47 /** 48 * The interpreter state. 49 */ 50 struct TALER_TESTING_Interpreter *is; 51 52 /** 53 * The (initial) POST /orders/$ID/claim operation handle. 54 * The logic is such that after an order creation, 55 * we immediately claim the order. 56 */ 57 struct TALER_MERCHANT_PostOrdersClaimHandle *och; 58 59 /** 60 * Base URL of the merchant serving the request. 61 */ 62 const char *merchant_url; 63 64 /** 65 * ID of the using template to run. 66 */ 67 const char *using_template_id; 68 69 /** 70 * Summary given by the customer. 71 */ 72 const char *summary; 73 74 /** 75 * Amount given by the customer. 76 */ 77 struct TALER_Amount amount; 78 79 /** 80 * Raw request body for inventory templates (if set). 81 */ 82 json_t *details; 83 84 /** 85 * Label of a command that created the template we should use. 86 */ 87 const char *template_ref; 88 89 /** 90 * Order id. 91 */ 92 char *order_id; 93 94 /** 95 * The order id we expect the merchant to assign (if not NULL). 96 */ 97 const char *expected_order_id; 98 99 /** 100 * Contract terms obtained from the backend. 101 */ 102 json_t *contract_terms; 103 104 /** 105 * Order submitted to the backend. 106 */ 107 json_t *order_terms; 108 109 /** 110 * Contract terms hash code. 111 */ 112 struct TALER_PrivateContractHashP h_contract_terms; 113 114 /** 115 * Merchant signature over the orders. 116 */ 117 struct TALER_MerchantSignatureP merchant_sig; 118 119 /** 120 * Merchant public key. 121 */ 122 struct TALER_MerchantPublicKeyP merchant_pub; 123 124 /** 125 * The nonce. 126 */ 127 struct GNUNET_CRYPTO_EddsaPublicKey nonce; 128 129 /** 130 * The claim token 131 */ 132 struct TALER_ClaimTokenP claim_token; 133 134 /** 135 * Pay deadline returned when the template was instantiated. 136 */ 137 struct GNUNET_TIME_Timestamp pay_deadline; 138 139 /** 140 * Time when the template instantiation request was started. 141 */ 142 struct GNUNET_TIME_Absolute request_start; 143 144 /** 145 * Pay duration configured in the template. 146 */ 147 struct GNUNET_TIME_Relative pay_duration; 148 149 /** 150 * Whether @e pay_duration is finite and non-zero and should be checked. 151 */ 152 bool check_pay_duration; 153 154 /** 155 * Whether @e pay_duration was explicitly supplied as the expected duration. 156 */ 157 bool have_expected_pay_duration; 158 159 /** 160 * Should the command also CLAIM the order? 161 */ 162 bool with_claim; 163 164 /** 165 * If not NULL, the command should duplicate the request and verify the 166 * response is the same as in this command. 167 */ 168 const char *duplicate_of; 169 170 /** 171 * Label of command creating/updating OTP device, or NULL. 172 */ 173 const char *otp_ref; 174 175 /** 176 * Encoded key for the payment verification. 177 */ 178 const char *otp_key; 179 180 /** 181 * Option that add amount of the order 182 */ 183 const enum TALER_MerchantConfirmationAlgorithm *otp_alg; 184 185 /** 186 * Public key of the OTP device, for a challenge-signature device. 187 */ 188 const char *otp_device_pub; 189 190 /** 191 * Challenge we made up on behalf of an offline verifier, sent with 192 * the request and expected back signed after payment. NULL unless 193 * the template's device signs a challenge. 194 */ 195 struct TALER_PosChallengeP *pos_challenge; 196 197 /** 198 * Expected HTTP response code. 199 */ 200 unsigned int http_status; 201 202 }; 203 204 /** 205 * Used to fill the "using_template" CMD state with backend-provided 206 * values. Also double-checks that the using_template was correctly 207 * created. 208 * 209 * @param cls closure 210 * @param ocr response we got 211 */ 212 static void 213 using_claim_cb (struct PostUsingTemplatesState *tis, 214 const struct TALER_MERCHANT_PostOrdersClaimResponse *ocr) 215 { 216 const char *error_name; 217 unsigned int error_line; 218 struct GNUNET_TIME_Timestamp pay_deadline; 219 struct GNUNET_JSON_Specification spec[] = { 220 GNUNET_JSON_spec_fixed_auto ("merchant_pub", 221 &tis->merchant_pub), 222 GNUNET_JSON_spec_timestamp ("pay_deadline", 223 &pay_deadline), 224 GNUNET_JSON_spec_end () 225 }; 226 227 tis->och = NULL; 228 if (tis->http_status != ocr->hr.http_status) 229 { 230 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 231 "Expected status %u, got %u\n", 232 tis->http_status, 233 ocr->hr.http_status); 234 TALER_TESTING_FAIL (tis->is); 235 } 236 if (MHD_HTTP_OK != ocr->hr.http_status) 237 { 238 TALER_TESTING_interpreter_next (tis->is); 239 return; 240 } 241 tis->contract_terms = json_deep_copy ( 242 (json_t *) ocr->details.ok.contract_terms); 243 if (GNUNET_OK != 244 TALER_JSON_contract_hash (tis->contract_terms, 245 &tis->h_contract_terms)) 246 { 247 GNUNET_break (0); 248 TALER_TESTING_FAIL (tis->is); 249 } 250 tis->merchant_sig = ocr->details.ok.merchant_sig; 251 if (GNUNET_OK != 252 GNUNET_JSON_parse (tis->contract_terms, 253 spec, 254 &error_name, 255 &error_line)) 256 { 257 char *log; 258 259 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 260 "Parser failed on %s:%u\n", 261 error_name, 262 error_line); 263 log = json_dumps (tis->contract_terms, 264 JSON_INDENT (1)); 265 fprintf (stderr, 266 "%s\n", 267 log); 268 free (log); 269 TALER_TESTING_FAIL (tis->is); 270 } 271 if (GNUNET_TIME_timestamp_cmp (pay_deadline, 272 !=, 273 tis->pay_deadline)) 274 { 275 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 276 "Pay deadline in claimed contract does not match template instantiation response\n"); 277 TALER_TESTING_FAIL (tis->is); 278 } 279 TALER_TESTING_interpreter_next (tis->is); 280 } 281 282 283 /** 284 * Callback for a POST /using-templates operation. 285 * 286 * @param cls closure for this function 287 * @param por response being processed 288 */ 289 static void 290 post_using_templates_cb (struct PostUsingTemplatesState *tis, 291 const struct TALER_MERCHANT_PostTemplatesResponse *por) 292 { 293 294 tis->iph = NULL; 295 if (tis->http_status != por->hr.http_status) 296 { 297 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 298 "Unexpected response code %u (%d) to command %s\n", 299 por->hr.http_status, 300 (int) por->hr.ec, 301 TALER_TESTING_interpreter_get_current_label (tis->is)); 302 TALER_TESTING_interpreter_fail (tis->is); 303 return; 304 } 305 if (0 == tis->http_status) 306 { 307 TALER_LOG_DEBUG ("/using_templates, expected 0 status code\n"); 308 TALER_TESTING_interpreter_next (tis->is); 309 return; 310 } 311 // check for order 312 switch (por->hr.http_status) 313 { 314 case MHD_HTTP_OK: 315 tis->pay_deadline = por->details.ok.pay_deadline; 316 if (tis->check_pay_duration) 317 { 318 struct GNUNET_TIME_Absolute earliest; 319 struct GNUNET_TIME_Absolute latest; 320 321 earliest = GNUNET_TIME_absolute_subtract ( 322 GNUNET_TIME_absolute_add (tis->request_start, 323 tis->pay_duration), 324 GNUNET_TIME_UNIT_SECONDS); 325 latest = GNUNET_TIME_absolute_add ( 326 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), 327 tis->pay_duration), 328 GNUNET_TIME_UNIT_SECONDS); 329 if ( (GNUNET_TIME_absolute_cmp (tis->pay_deadline.abs_time, 330 <, 331 earliest)) || 332 (GNUNET_TIME_absolute_cmp (tis->pay_deadline.abs_time, 333 >, 334 latest)) ) 335 { 336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 337 "Template pay deadline does not match configured pay duration\n"); 338 TALER_TESTING_interpreter_fail (tis->is); 339 return; 340 } 341 } 342 if (NULL != por->details.ok.token) 343 tis->claim_token = *por->details.ok.token; 344 tis->order_id = GNUNET_strdup (por->details.ok.order_id); 345 if ((NULL != tis->expected_order_id) && 346 (0 != strcmp (por->details.ok.order_id, 347 tis->expected_order_id))) 348 { 349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 350 "Order id assigned does not match\n"); 351 TALER_TESTING_interpreter_fail (tis->is); 352 return; 353 } 354 if (NULL != tis->duplicate_of) 355 { 356 const struct TALER_TESTING_Command *order_cmd; 357 const struct TALER_ClaimTokenP *prev_token; 358 struct TALER_ClaimTokenP zero_token = {0}; 359 const struct TALER_ClaimTokenP *resp_token; 360 361 order_cmd = TALER_TESTING_interpreter_lookup_command ( 362 tis->is, 363 tis->duplicate_of); 364 if (GNUNET_OK != 365 TALER_TESTING_get_trait_claim_token (order_cmd, 366 &prev_token)) 367 { 368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 369 "Could not fetch previous order claim token\n"); 370 TALER_TESTING_interpreter_fail (tis->is); 371 return; 372 } 373 374 resp_token = (NULL != por->details.ok.token) 375 ? por->details.ok.token 376 : &zero_token; 377 if (0 != GNUNET_memcmp (prev_token, 378 resp_token)) 379 { 380 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 381 "Claim tokens for identical requests do not match\n"); 382 TALER_TESTING_interpreter_fail (tis->is); 383 return; 384 } 385 } 386 break; 387 case MHD_HTTP_BAD_REQUEST: 388 case MHD_HTTP_NOT_FOUND: 389 TALER_TESTING_interpreter_next (tis->is); 390 return; 391 case MHD_HTTP_GONE: 392 TALER_TESTING_interpreter_next (tis->is); 393 return; 394 case MHD_HTTP_CONFLICT: 395 TALER_TESTING_interpreter_next (tis->is); 396 return; 397 default: 398 { 399 char *s = json_dumps (por->hr.reply, 400 JSON_COMPACT); 401 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 402 "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n", 403 por->hr.http_status, 404 (int) por->hr.ec, 405 TALER_TESTING_interpreter_get_current_label (tis->is), 406 s); 407 GNUNET_free (s); 408 /** 409 * Not failing, as test cases are _supposed_ 410 * to create non 200 OK situations. 411 */ 412 TALER_TESTING_interpreter_next (tis->is); 413 } 414 return; 415 } 416 417 if (! tis->with_claim) 418 { 419 TALER_TESTING_interpreter_next (tis->is); 420 return; 421 } 422 tis->och = TALER_MERCHANT_post_orders_claim_create ( 423 TALER_TESTING_interpreter_get_context (tis->is), 424 tis->merchant_url, 425 tis->order_id, 426 &tis->nonce); 427 if (NULL == tis->och) 428 TALER_TESTING_FAIL (tis->is); 429 TALER_MERCHANT_post_orders_claim_set_options ( 430 tis->och, 431 TALER_MERCHANT_post_orders_claim_option_token ( 432 &tis->claim_token)); 433 { 434 enum TALER_ErrorCode ec; 435 436 ec = TALER_MERCHANT_post_orders_claim_start (tis->och, 437 &using_claim_cb, 438 tis); 439 GNUNET_assert (TALER_EC_NONE == ec); 440 } 441 } 442 443 444 /** 445 * Run the "POST /using-templates" CMD. 446 * 447 * 448 * @param cls closure. 449 * @param cmd command being run now. 450 * @param is interpreter state. 451 */ 452 static void 453 post_using_templates_run (void *cls, 454 const struct TALER_TESTING_Command *cmd, 455 struct TALER_TESTING_Interpreter *is) 456 { 457 struct PostUsingTemplatesState *tis = cls; 458 const struct TALER_TESTING_Command *ref; 459 const char *template_id; 460 const json_t *template_contract; 461 462 tis->is = is; 463 ref = TALER_TESTING_interpreter_lookup_command (is, 464 tis->template_ref); 465 if (GNUNET_OK != 466 TALER_TESTING_get_trait_template_id (ref, 467 &template_id)) 468 TALER_TESTING_FAIL (is); 469 if (GNUNET_OK != 470 TALER_TESTING_get_trait_template_contract (ref, 471 &template_contract)) 472 TALER_TESTING_FAIL (is); 473 if (tis->have_expected_pay_duration) 474 { 475 tis->check_pay_duration 476 = (! GNUNET_TIME_relative_is_zero (tis->pay_duration)) && 477 (! GNUNET_TIME_relative_is_forever (tis->pay_duration)); 478 } 479 else if (NULL != 480 json_object_get (template_contract, 481 "pay_duration")) 482 { 483 struct GNUNET_JSON_Specification spec[] = { 484 GNUNET_JSON_spec_relative_time ("pay_duration", 485 &tis->pay_duration), 486 GNUNET_JSON_spec_end () 487 }; 488 489 GNUNET_assert (GNUNET_OK == 490 GNUNET_JSON_parse ((json_t *) template_contract, 491 spec, 492 NULL, 493 NULL)); 494 tis->check_pay_duration 495 = (! GNUNET_TIME_relative_is_zero (tis->pay_duration)) && 496 (! GNUNET_TIME_relative_is_forever (tis->pay_duration)); 497 } 498 if (NULL != tis->otp_ref) 499 { 500 ref = TALER_TESTING_interpreter_lookup_command (is, 501 tis->otp_ref); 502 if (GNUNET_OK != 503 TALER_TESTING_get_trait_otp_key (ref, 504 &tis->otp_key)) 505 TALER_TESTING_FAIL (is); 506 if (GNUNET_OK != 507 TALER_TESTING_get_trait_otp_alg (ref, 508 &tis->otp_alg)) 509 TALER_TESTING_FAIL (is); 510 /* only challenge-signature devices have one */ 511 if (GNUNET_OK != 512 TALER_TESTING_get_trait_otp_device_pub (ref, 513 &tis->otp_device_pub)) 514 tis->otp_device_pub = NULL; 515 } 516 GNUNET_CRYPTO_random_block (&tis->nonce, 517 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 518 if ( (NULL != tis->otp_alg) && 519 ( (TALER_MCA_ECDSA_CHALLENGE == *tis->otp_alg) || 520 (TALER_MCA_EDDSA_CHALLENGE == *tis->otp_alg) ) ) 521 { 522 /* stand in for the offline verifier: pick an unpredictable 523 challenge that the backend must sign after payment */ 524 tis->pos_challenge = GNUNET_new (struct TALER_PosChallengeP); 525 GNUNET_CRYPTO_random_block (tis->pos_challenge, 526 sizeof (*tis->pos_challenge)); 527 } 528 tis->iph = TALER_MERCHANT_post_templates_create ( 529 TALER_TESTING_interpreter_get_context (is), 530 tis->merchant_url, 531 template_id); 532 GNUNET_assert (NULL != tis->iph); 533 if (NULL != tis->details) 534 { 535 TALER_MERCHANT_post_templates_set_options ( 536 tis->iph, 537 TALER_MERCHANT_post_templates_option_details ( 538 tis->details)); 539 } 540 else 541 { 542 if (NULL != tis->summary) 543 TALER_MERCHANT_post_templates_set_options ( 544 tis->iph, 545 TALER_MERCHANT_post_templates_option_summary ( 546 tis->summary)); 547 if (TALER_amount_is_valid (&tis->amount)) 548 TALER_MERCHANT_post_templates_set_options ( 549 tis->iph, 550 TALER_MERCHANT_post_templates_option_amount ( 551 &tis->amount)); 552 } 553 if (NULL != tis->pos_challenge) 554 TALER_MERCHANT_post_templates_set_options ( 555 tis->iph, 556 TALER_MERCHANT_post_templates_option_challenge ( 557 tis->pos_challenge)); 558 { 559 enum TALER_ErrorCode ec; 560 561 tis->request_start = GNUNET_TIME_absolute_get (); 562 ec = TALER_MERCHANT_post_templates_start (tis->iph, 563 &post_using_templates_cb, 564 tis); 565 GNUNET_assert (TALER_EC_NONE == ec); 566 } 567 } 568 569 570 /** 571 * Offers information from the POST /using-templates CMD state to other 572 * commands. 573 * 574 * @param cls closure 575 * @param[out] ret result (could be anything) 576 * @param trait name of the trait 577 * @param index index number of the object to extract. 578 * @return #GNUNET_OK on success 579 */ 580 static enum GNUNET_GenericReturnValue 581 post_using_templates_traits (void *cls, 582 const void **ret, 583 const char *trait, 584 unsigned int index) 585 { 586 struct PostUsingTemplatesState *pts = cls; 587 struct TALER_TESTING_Trait traits[] = { 588 TALER_TESTING_make_trait_order_id (pts->order_id), 589 TALER_TESTING_make_trait_contract_terms (pts->contract_terms), 590 TALER_TESTING_make_trait_order_terms (pts->order_terms), 591 TALER_TESTING_make_trait_h_contract_terms (&pts->h_contract_terms), 592 TALER_TESTING_make_trait_merchant_sig (&pts->merchant_sig), 593 TALER_TESTING_make_trait_merchant_pub (&pts->merchant_pub), 594 TALER_TESTING_make_trait_claim_nonce (&pts->nonce), 595 TALER_TESTING_make_trait_claim_token (&pts->claim_token), 596 TALER_TESTING_make_trait_otp_key (pts->otp_key), 597 TALER_TESTING_make_trait_otp_alg (pts->otp_alg), 598 TALER_TESTING_make_trait_otp_device_pub (pts->otp_device_pub), 599 TALER_TESTING_make_trait_pos_challenge (pts->pos_challenge), 600 TALER_TESTING_trait_end (), 601 }; 602 603 (void) pts; 604 return TALER_TESTING_get_trait (traits, 605 ret, 606 trait, 607 index); 608 } 609 610 611 /** 612 * Free the state of a "POST using-template" CMD, and possibly 613 * cancel a pending operation thereof. 614 * 615 * @param cls closure. 616 * @param cmd command being run. 617 */ 618 static void 619 post_using_templates_cleanup (void *cls, 620 const struct TALER_TESTING_Command *cmd) 621 { 622 struct PostUsingTemplatesState *tis = cls; 623 624 if (NULL != tis->iph) 625 { 626 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 627 "POST /using-templates operation did not complete\n"); 628 TALER_MERCHANT_post_templates_cancel (tis->iph); 629 } 630 json_decref (tis->order_terms); 631 json_decref (tis->contract_terms); 632 json_decref (tis->details); 633 GNUNET_free (tis->order_id); 634 GNUNET_free (tis->pos_challenge); 635 GNUNET_free (tis); 636 } 637 638 639 /** 640 * Mark part of the contract terms as possible to forget. 641 * 642 * @param cls pointer to the result of the forget operation. 643 * @param object_id name of the object to forget. 644 * @param parent parent of the object at @e object_id. 645 */ 646 static void 647 mark_forgettable (void *cls, 648 const char *object_id, 649 json_t *parent) 650 { 651 GNUNET_assert (GNUNET_OK == 652 TALER_JSON_contract_mark_forgettable (parent, 653 object_id)); 654 } 655 656 657 /** 658 * Constructs the json for a POST using template request. 659 * 660 * @param using_template_id the name of the using_template to add, can be NULL. 661 * @param refund_deadline the deadline for refunds on this using template. 662 * @param pay_deadline the deadline for payment on this using template. 663 * @param amount the amount this using template is for. 664 * @param[out] using_template where to write the json string. 665 */ 666 static void 667 make_order_json (const char *using_template_id, 668 struct GNUNET_TIME_Timestamp refund_deadline, 669 struct GNUNET_TIME_Timestamp pay_deadline, 670 const char *amount, 671 json_t **using_template) 672 { 673 struct GNUNET_TIME_Timestamp refund = refund_deadline; 674 struct GNUNET_TIME_Timestamp pay = pay_deadline; 675 json_t *contract_terms; 676 struct TALER_Amount tamount; 677 json_t *arr; 678 679 if (NULL != amount) 680 GNUNET_assert (GNUNET_OK == 681 TALER_string_to_amount (amount, 682 &tamount)); 683 /* Include required fields and some dummy objects to test forgetting. */ 684 arr = json_array (); 685 GNUNET_assert (NULL != arr); 686 GNUNET_assert (0 == 687 json_array_append_new ( 688 arr, 689 GNUNET_JSON_PACK ( 690 GNUNET_JSON_pack_string ( 691 "item", "speakers")))); 692 GNUNET_assert (0 == 693 json_array_append_new ( 694 arr, 695 GNUNET_JSON_PACK ( 696 GNUNET_JSON_pack_string ( 697 "item", "headphones")))); 698 GNUNET_assert (0 == 699 json_array_append_new ( 700 arr, 701 GNUNET_JSON_PACK ( 702 GNUNET_JSON_pack_string ( 703 "item", "earbuds")))); 704 contract_terms = GNUNET_JSON_PACK ( 705 GNUNET_JSON_pack_string ("summary", 706 "merchant-lib testcase"), 707 GNUNET_JSON_pack_allow_null ( 708 GNUNET_JSON_pack_string ( 709 "using_template_id", using_template_id)), 710 GNUNET_JSON_pack_conditional ( 711 NULL != amount, 712 TALER_JSON_pack_amount ("amount", 713 &tamount)), 714 GNUNET_JSON_pack_string ("fulfillment_url", 715 "https://example.com"), 716 GNUNET_JSON_pack_allow_null ( 717 GNUNET_JSON_pack_timestamp ("refund_deadline", 718 refund)), 719 GNUNET_JSON_pack_allow_null ( 720 GNUNET_JSON_pack_timestamp ("pay_deadline", 721 pay)), 722 GNUNET_JSON_pack_string ("dummy_obj", 723 "EUR:1.0"), 724 GNUNET_JSON_pack_array_steal ("dummy_array", 725 arr)); 726 GNUNET_assert (GNUNET_OK == 727 TALER_JSON_expand_path (contract_terms, 728 "$.dummy_obj", 729 &mark_forgettable, 730 NULL)); 731 GNUNET_assert (GNUNET_OK == 732 TALER_JSON_expand_path (contract_terms, 733 "$.dummy_array[*].item", 734 &mark_forgettable, 735 NULL)); 736 *using_template = contract_terms; 737 } 738 739 740 struct TALER_TESTING_Command 741 TALER_TESTING_cmd_merchant_post_using_templates ( 742 const char *label, 743 const char *template_ref, 744 const char *otp_ref, 745 const char *merchant_url, 746 const char *using_template_id, 747 const char *summary, 748 const char *amount, 749 struct GNUNET_TIME_Timestamp refund_deadline, 750 struct GNUNET_TIME_Timestamp pay_deadline, 751 unsigned int http_status) 752 { 753 struct PostUsingTemplatesState *tis; 754 755 tis = GNUNET_new (struct PostUsingTemplatesState); 756 tis->template_ref = template_ref; 757 tis->otp_ref = otp_ref; 758 tis->merchant_url = merchant_url; 759 tis->using_template_id = using_template_id; 760 tis->http_status = http_status; 761 tis->summary = summary; 762 tis->with_claim = true; 763 make_order_json (using_template_id, 764 refund_deadline, 765 pay_deadline, 766 amount, 767 &tis->order_terms); 768 if (NULL != amount) 769 GNUNET_assert (GNUNET_OK == 770 TALER_string_to_amount (amount, 771 &tis->amount)); 772 { 773 struct TALER_TESTING_Command cmd = { 774 .cls = tis, 775 .label = label, 776 .run = &post_using_templates_run, 777 .cleanup = &post_using_templates_cleanup, 778 .traits = &post_using_templates_traits 779 }; 780 781 return cmd; 782 } 783 } 784 785 786 struct TALER_TESTING_Command 787 TALER_TESTING_cmd_merchant_post_using_templates_with_expected_pay_duration ( 788 const char *label, 789 const char *template_ref, 790 const char *otp_ref, 791 const char *merchant_url, 792 const char *using_template_id, 793 const char *summary, 794 const char *amount, 795 struct GNUNET_TIME_Timestamp refund_deadline, 796 struct GNUNET_TIME_Timestamp pay_deadline, 797 struct GNUNET_TIME_Relative expected_pay_duration, 798 unsigned int http_status) 799 { 800 struct TALER_TESTING_Command cmd; 801 struct PostUsingTemplatesState *tis; 802 803 cmd = TALER_TESTING_cmd_merchant_post_using_templates ( 804 label, 805 template_ref, 806 otp_ref, 807 merchant_url, 808 using_template_id, 809 summary, 810 amount, 811 refund_deadline, 812 pay_deadline, 813 http_status); 814 tis = cmd.cls; 815 tis->pay_duration = expected_pay_duration; 816 tis->have_expected_pay_duration = true; 817 return cmd; 818 } 819 820 821 struct TALER_TESTING_Command 822 TALER_TESTING_cmd_merchant_post_using_templates2 ( 823 const char *label, 824 const char *template_ref, 825 const char *otp_ref, 826 const char *merchant_url, 827 const char *using_template_id, 828 const json_t *details, 829 unsigned int http_status) 830 { 831 struct PostUsingTemplatesState *tis; 832 833 tis = GNUNET_new (struct PostUsingTemplatesState); 834 tis->template_ref = template_ref; 835 tis->otp_ref = otp_ref; 836 tis->merchant_url = merchant_url; 837 tis->using_template_id = using_template_id; 838 tis->http_status = http_status; 839 tis->with_claim = true; 840 if (NULL != details) 841 tis->details = json_incref ((json_t *) details); 842 { 843 struct TALER_TESTING_Command cmd = { 844 .cls = tis, 845 .label = label, 846 .run = &post_using_templates_run, 847 .cleanup = &post_using_templates_cleanup, 848 .traits = &post_using_templates_traits 849 }; 850 851 return cmd; 852 } 853 } 854 855 856 /* end of testing_api_cmd_post_using_templates.c */