testing_api_cmd_post_using_templates.c (24375B)
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 * Expected HTTP response code. 187 */ 188 unsigned int http_status; 189 190 }; 191 192 /** 193 * Used to fill the "using_template" CMD state with backend-provided 194 * values. Also double-checks that the using_template was correctly 195 * created. 196 * 197 * @param cls closure 198 * @param ocr response we got 199 */ 200 static void 201 using_claim_cb (struct PostUsingTemplatesState *tis, 202 const struct TALER_MERCHANT_PostOrdersClaimResponse *ocr) 203 { 204 const char *error_name; 205 unsigned int error_line; 206 struct GNUNET_TIME_Timestamp pay_deadline; 207 struct GNUNET_JSON_Specification spec[] = { 208 GNUNET_JSON_spec_fixed_auto ("merchant_pub", 209 &tis->merchant_pub), 210 GNUNET_JSON_spec_timestamp ("pay_deadline", 211 &pay_deadline), 212 GNUNET_JSON_spec_end () 213 }; 214 215 tis->och = NULL; 216 if (tis->http_status != ocr->hr.http_status) 217 { 218 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 219 "Expected status %u, got %u\n", 220 tis->http_status, 221 ocr->hr.http_status); 222 TALER_TESTING_FAIL (tis->is); 223 } 224 if (MHD_HTTP_OK != ocr->hr.http_status) 225 { 226 TALER_TESTING_interpreter_next (tis->is); 227 return; 228 } 229 tis->contract_terms = json_deep_copy ( 230 (json_t *) ocr->details.ok.contract_terms); 231 if (GNUNET_OK != 232 TALER_JSON_contract_hash (tis->contract_terms, 233 &tis->h_contract_terms)) 234 { 235 GNUNET_break (0); 236 TALER_TESTING_FAIL (tis->is); 237 } 238 tis->merchant_sig = ocr->details.ok.merchant_sig; 239 if (GNUNET_OK != 240 GNUNET_JSON_parse (tis->contract_terms, 241 spec, 242 &error_name, 243 &error_line)) 244 { 245 char *log; 246 247 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 248 "Parser failed on %s:%u\n", 249 error_name, 250 error_line); 251 log = json_dumps (tis->contract_terms, 252 JSON_INDENT (1)); 253 fprintf (stderr, 254 "%s\n", 255 log); 256 free (log); 257 TALER_TESTING_FAIL (tis->is); 258 } 259 if (GNUNET_TIME_timestamp_cmp (pay_deadline, 260 !=, 261 tis->pay_deadline)) 262 { 263 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 264 "Pay deadline in claimed contract does not match template instantiation response\n"); 265 TALER_TESTING_FAIL (tis->is); 266 } 267 TALER_TESTING_interpreter_next (tis->is); 268 } 269 270 271 /** 272 * Callback for a POST /using-templates operation. 273 * 274 * @param cls closure for this function 275 * @param por response being processed 276 */ 277 static void 278 post_using_templates_cb (struct PostUsingTemplatesState *tis, 279 const struct TALER_MERCHANT_PostTemplatesResponse *por) 280 { 281 282 tis->iph = NULL; 283 if (tis->http_status != por->hr.http_status) 284 { 285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 286 "Unexpected response code %u (%d) to command %s\n", 287 por->hr.http_status, 288 (int) por->hr.ec, 289 TALER_TESTING_interpreter_get_current_label (tis->is)); 290 TALER_TESTING_interpreter_fail (tis->is); 291 return; 292 } 293 if (0 == tis->http_status) 294 { 295 TALER_LOG_DEBUG ("/using_templates, expected 0 status code\n"); 296 TALER_TESTING_interpreter_next (tis->is); 297 return; 298 } 299 // check for order 300 switch (por->hr.http_status) 301 { 302 case MHD_HTTP_OK: 303 tis->pay_deadline = por->details.ok.pay_deadline; 304 if (tis->check_pay_duration) 305 { 306 struct GNUNET_TIME_Absolute earliest; 307 struct GNUNET_TIME_Absolute latest; 308 309 earliest = GNUNET_TIME_absolute_subtract ( 310 GNUNET_TIME_absolute_add (tis->request_start, 311 tis->pay_duration), 312 GNUNET_TIME_UNIT_SECONDS); 313 latest = GNUNET_TIME_absolute_add ( 314 GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), 315 tis->pay_duration), 316 GNUNET_TIME_UNIT_SECONDS); 317 if ( (GNUNET_TIME_absolute_cmp (tis->pay_deadline.abs_time, 318 <, 319 earliest)) || 320 (GNUNET_TIME_absolute_cmp (tis->pay_deadline.abs_time, 321 >, 322 latest)) ) 323 { 324 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 325 "Template pay deadline does not match configured pay duration\n"); 326 TALER_TESTING_interpreter_fail (tis->is); 327 return; 328 } 329 } 330 if (NULL != por->details.ok.token) 331 tis->claim_token = *por->details.ok.token; 332 tis->order_id = GNUNET_strdup (por->details.ok.order_id); 333 if ((NULL != tis->expected_order_id) && 334 (0 != strcmp (por->details.ok.order_id, 335 tis->expected_order_id))) 336 { 337 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 338 "Order id assigned does not match\n"); 339 TALER_TESTING_interpreter_fail (tis->is); 340 return; 341 } 342 if (NULL != tis->duplicate_of) 343 { 344 const struct TALER_TESTING_Command *order_cmd; 345 const struct TALER_ClaimTokenP *prev_token; 346 struct TALER_ClaimTokenP zero_token = {0}; 347 const struct TALER_ClaimTokenP *resp_token; 348 349 order_cmd = TALER_TESTING_interpreter_lookup_command ( 350 tis->is, 351 tis->duplicate_of); 352 if (GNUNET_OK != 353 TALER_TESTING_get_trait_claim_token (order_cmd, 354 &prev_token)) 355 { 356 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 357 "Could not fetch previous order claim token\n"); 358 TALER_TESTING_interpreter_fail (tis->is); 359 return; 360 } 361 362 resp_token = (NULL != por->details.ok.token) 363 ? por->details.ok.token 364 : &zero_token; 365 if (0 != GNUNET_memcmp (prev_token, 366 resp_token)) 367 { 368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 369 "Claim tokens for identical requests do not match\n"); 370 TALER_TESTING_interpreter_fail (tis->is); 371 return; 372 } 373 } 374 break; 375 case MHD_HTTP_NOT_FOUND: 376 TALER_TESTING_interpreter_next (tis->is); 377 return; 378 case MHD_HTTP_GONE: 379 TALER_TESTING_interpreter_next (tis->is); 380 return; 381 case MHD_HTTP_CONFLICT: 382 TALER_TESTING_interpreter_next (tis->is); 383 return; 384 default: 385 { 386 char *s = json_dumps (por->hr.reply, 387 JSON_COMPACT); 388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 389 "Unexpected status code from /orders: %u (%d) at %s; JSON: %s\n", 390 por->hr.http_status, 391 (int) por->hr.ec, 392 TALER_TESTING_interpreter_get_current_label (tis->is), 393 s); 394 GNUNET_free (s); 395 /** 396 * Not failing, as test cases are _supposed_ 397 * to create non 200 OK situations. 398 */ 399 TALER_TESTING_interpreter_next (tis->is); 400 } 401 return; 402 } 403 404 if (! tis->with_claim) 405 { 406 TALER_TESTING_interpreter_next (tis->is); 407 return; 408 } 409 tis->och = TALER_MERCHANT_post_orders_claim_create ( 410 TALER_TESTING_interpreter_get_context (tis->is), 411 tis->merchant_url, 412 tis->order_id, 413 &tis->nonce); 414 if (NULL == tis->och) 415 TALER_TESTING_FAIL (tis->is); 416 TALER_MERCHANT_post_orders_claim_set_options ( 417 tis->och, 418 TALER_MERCHANT_post_orders_claim_option_token ( 419 &tis->claim_token)); 420 { 421 enum TALER_ErrorCode ec; 422 423 ec = TALER_MERCHANT_post_orders_claim_start (tis->och, 424 &using_claim_cb, 425 tis); 426 GNUNET_assert (TALER_EC_NONE == ec); 427 } 428 } 429 430 431 /** 432 * Run the "POST /using-templates" CMD. 433 * 434 * 435 * @param cls closure. 436 * @param cmd command being run now. 437 * @param is interpreter state. 438 */ 439 static void 440 post_using_templates_run (void *cls, 441 const struct TALER_TESTING_Command *cmd, 442 struct TALER_TESTING_Interpreter *is) 443 { 444 struct PostUsingTemplatesState *tis = cls; 445 const struct TALER_TESTING_Command *ref; 446 const char *template_id; 447 const json_t *template_contract; 448 449 tis->is = is; 450 ref = TALER_TESTING_interpreter_lookup_command (is, 451 tis->template_ref); 452 if (GNUNET_OK != 453 TALER_TESTING_get_trait_template_id (ref, 454 &template_id)) 455 TALER_TESTING_FAIL (is); 456 if (GNUNET_OK != 457 TALER_TESTING_get_trait_template_contract (ref, 458 &template_contract)) 459 TALER_TESTING_FAIL (is); 460 if (tis->have_expected_pay_duration) 461 { 462 tis->check_pay_duration 463 = (! GNUNET_TIME_relative_is_zero (tis->pay_duration)) && 464 (! GNUNET_TIME_relative_is_forever (tis->pay_duration)); 465 } 466 else if (NULL != 467 json_object_get (template_contract, 468 "pay_duration")) 469 { 470 struct GNUNET_JSON_Specification spec[] = { 471 GNUNET_JSON_spec_relative_time ("pay_duration", 472 &tis->pay_duration), 473 GNUNET_JSON_spec_end () 474 }; 475 476 GNUNET_assert (GNUNET_OK == 477 GNUNET_JSON_parse ((json_t *) template_contract, 478 spec, 479 NULL, 480 NULL)); 481 tis->check_pay_duration 482 = (! GNUNET_TIME_relative_is_zero (tis->pay_duration)) && 483 (! GNUNET_TIME_relative_is_forever (tis->pay_duration)); 484 } 485 if (NULL != tis->otp_ref) 486 { 487 ref = TALER_TESTING_interpreter_lookup_command (is, 488 tis->otp_ref); 489 if (GNUNET_OK != 490 TALER_TESTING_get_trait_otp_key (ref, 491 &tis->otp_key)) 492 TALER_TESTING_FAIL (is); 493 if (GNUNET_OK != 494 TALER_TESTING_get_trait_otp_alg (ref, 495 &tis->otp_alg)) 496 TALER_TESTING_FAIL (is); 497 } 498 GNUNET_CRYPTO_random_block (&tis->nonce, 499 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 500 tis->iph = TALER_MERCHANT_post_templates_create ( 501 TALER_TESTING_interpreter_get_context (is), 502 tis->merchant_url, 503 template_id); 504 GNUNET_assert (NULL != tis->iph); 505 if (NULL != tis->details) 506 { 507 TALER_MERCHANT_post_templates_set_options ( 508 tis->iph, 509 TALER_MERCHANT_post_templates_option_details ( 510 tis->details)); 511 } 512 else 513 { 514 if (NULL != tis->summary) 515 TALER_MERCHANT_post_templates_set_options ( 516 tis->iph, 517 TALER_MERCHANT_post_templates_option_summary ( 518 tis->summary)); 519 if (TALER_amount_is_valid (&tis->amount)) 520 TALER_MERCHANT_post_templates_set_options ( 521 tis->iph, 522 TALER_MERCHANT_post_templates_option_amount ( 523 &tis->amount)); 524 } 525 { 526 enum TALER_ErrorCode ec; 527 528 tis->request_start = GNUNET_TIME_absolute_get (); 529 ec = TALER_MERCHANT_post_templates_start (tis->iph, 530 &post_using_templates_cb, 531 tis); 532 GNUNET_assert (TALER_EC_NONE == ec); 533 } 534 } 535 536 537 /** 538 * Offers information from the POST /using-templates CMD state to other 539 * commands. 540 * 541 * @param cls closure 542 * @param[out] ret result (could be anything) 543 * @param trait name of the trait 544 * @param index index number of the object to extract. 545 * @return #GNUNET_OK on success 546 */ 547 static enum GNUNET_GenericReturnValue 548 post_using_templates_traits (void *cls, 549 const void **ret, 550 const char *trait, 551 unsigned int index) 552 { 553 struct PostUsingTemplatesState *pts = cls; 554 struct TALER_TESTING_Trait traits[] = { 555 TALER_TESTING_make_trait_order_id (pts->order_id), 556 TALER_TESTING_make_trait_contract_terms (pts->contract_terms), 557 TALER_TESTING_make_trait_order_terms (pts->order_terms), 558 TALER_TESTING_make_trait_h_contract_terms (&pts->h_contract_terms), 559 TALER_TESTING_make_trait_merchant_sig (&pts->merchant_sig), 560 TALER_TESTING_make_trait_merchant_pub (&pts->merchant_pub), 561 TALER_TESTING_make_trait_claim_nonce (&pts->nonce), 562 TALER_TESTING_make_trait_claim_token (&pts->claim_token), 563 TALER_TESTING_make_trait_otp_key (pts->otp_key), 564 TALER_TESTING_make_trait_otp_alg (pts->otp_alg), 565 TALER_TESTING_trait_end (), 566 }; 567 568 (void) pts; 569 return TALER_TESTING_get_trait (traits, 570 ret, 571 trait, 572 index); 573 } 574 575 576 /** 577 * Free the state of a "POST using-template" CMD, and possibly 578 * cancel a pending operation thereof. 579 * 580 * @param cls closure. 581 * @param cmd command being run. 582 */ 583 static void 584 post_using_templates_cleanup (void *cls, 585 const struct TALER_TESTING_Command *cmd) 586 { 587 struct PostUsingTemplatesState *tis = cls; 588 589 if (NULL != tis->iph) 590 { 591 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 592 "POST /using-templates operation did not complete\n"); 593 TALER_MERCHANT_post_templates_cancel (tis->iph); 594 } 595 json_decref (tis->order_terms); 596 json_decref (tis->contract_terms); 597 json_decref (tis->details); 598 GNUNET_free (tis->order_id); 599 GNUNET_free (tis); 600 } 601 602 603 /** 604 * Mark part of the contract terms as possible to forget. 605 * 606 * @param cls pointer to the result of the forget operation. 607 * @param object_id name of the object to forget. 608 * @param parent parent of the object at @e object_id. 609 */ 610 static void 611 mark_forgettable (void *cls, 612 const char *object_id, 613 json_t *parent) 614 { 615 GNUNET_assert (GNUNET_OK == 616 TALER_JSON_contract_mark_forgettable (parent, 617 object_id)); 618 } 619 620 621 /** 622 * Constructs the json for a POST using template request. 623 * 624 * @param using_template_id the name of the using_template to add, can be NULL. 625 * @param refund_deadline the deadline for refunds on this using template. 626 * @param pay_deadline the deadline for payment on this using template. 627 * @param amount the amount this using template is for. 628 * @param[out] using_template where to write the json string. 629 */ 630 static void 631 make_order_json (const char *using_template_id, 632 struct GNUNET_TIME_Timestamp refund_deadline, 633 struct GNUNET_TIME_Timestamp pay_deadline, 634 const char *amount, 635 json_t **using_template) 636 { 637 struct GNUNET_TIME_Timestamp refund = refund_deadline; 638 struct GNUNET_TIME_Timestamp pay = pay_deadline; 639 json_t *contract_terms; 640 struct TALER_Amount tamount; 641 json_t *arr; 642 643 if (NULL != amount) 644 GNUNET_assert (GNUNET_OK == 645 TALER_string_to_amount (amount, 646 &tamount)); 647 /* Include required fields and some dummy objects to test forgetting. */ 648 arr = json_array (); 649 GNUNET_assert (NULL != arr); 650 GNUNET_assert (0 == 651 json_array_append_new ( 652 arr, 653 GNUNET_JSON_PACK ( 654 GNUNET_JSON_pack_string ( 655 "item", "speakers")))); 656 GNUNET_assert (0 == 657 json_array_append_new ( 658 arr, 659 GNUNET_JSON_PACK ( 660 GNUNET_JSON_pack_string ( 661 "item", "headphones")))); 662 GNUNET_assert (0 == 663 json_array_append_new ( 664 arr, 665 GNUNET_JSON_PACK ( 666 GNUNET_JSON_pack_string ( 667 "item", "earbuds")))); 668 contract_terms = GNUNET_JSON_PACK ( 669 GNUNET_JSON_pack_string ("summary", 670 "merchant-lib testcase"), 671 GNUNET_JSON_pack_allow_null ( 672 GNUNET_JSON_pack_string ( 673 "using_template_id", using_template_id)), 674 GNUNET_JSON_pack_conditional ( 675 NULL != amount, 676 TALER_JSON_pack_amount ("amount", 677 &tamount)), 678 GNUNET_JSON_pack_string ("fulfillment_url", 679 "https://example.com"), 680 GNUNET_JSON_pack_allow_null ( 681 GNUNET_JSON_pack_timestamp ("refund_deadline", 682 refund)), 683 GNUNET_JSON_pack_allow_null ( 684 GNUNET_JSON_pack_timestamp ("pay_deadline", 685 pay)), 686 GNUNET_JSON_pack_string ("dummy_obj", 687 "EUR:1.0"), 688 GNUNET_JSON_pack_array_steal ("dummy_array", 689 arr)); 690 GNUNET_assert (GNUNET_OK == 691 TALER_JSON_expand_path (contract_terms, 692 "$.dummy_obj", 693 &mark_forgettable, 694 NULL)); 695 GNUNET_assert (GNUNET_OK == 696 TALER_JSON_expand_path (contract_terms, 697 "$.dummy_array[*].item", 698 &mark_forgettable, 699 NULL)); 700 *using_template = contract_terms; 701 } 702 703 704 struct TALER_TESTING_Command 705 TALER_TESTING_cmd_merchant_post_using_templates ( 706 const char *label, 707 const char *template_ref, 708 const char *otp_ref, 709 const char *merchant_url, 710 const char *using_template_id, 711 const char *summary, 712 const char *amount, 713 struct GNUNET_TIME_Timestamp refund_deadline, 714 struct GNUNET_TIME_Timestamp pay_deadline, 715 unsigned int http_status) 716 { 717 struct PostUsingTemplatesState *tis; 718 719 tis = GNUNET_new (struct PostUsingTemplatesState); 720 tis->template_ref = template_ref; 721 tis->otp_ref = otp_ref; 722 tis->merchant_url = merchant_url; 723 tis->using_template_id = using_template_id; 724 tis->http_status = http_status; 725 tis->summary = summary; 726 tis->with_claim = true; 727 make_order_json (using_template_id, 728 refund_deadline, 729 pay_deadline, 730 amount, 731 &tis->order_terms); 732 if (NULL != amount) 733 GNUNET_assert (GNUNET_OK == 734 TALER_string_to_amount (amount, 735 &tis->amount)); 736 { 737 struct TALER_TESTING_Command cmd = { 738 .cls = tis, 739 .label = label, 740 .run = &post_using_templates_run, 741 .cleanup = &post_using_templates_cleanup, 742 .traits = &post_using_templates_traits 743 }; 744 745 return cmd; 746 } 747 } 748 749 750 struct TALER_TESTING_Command 751 TALER_TESTING_cmd_merchant_post_using_templates_with_expected_pay_duration ( 752 const char *label, 753 const char *template_ref, 754 const char *otp_ref, 755 const char *merchant_url, 756 const char *using_template_id, 757 const char *summary, 758 const char *amount, 759 struct GNUNET_TIME_Timestamp refund_deadline, 760 struct GNUNET_TIME_Timestamp pay_deadline, 761 struct GNUNET_TIME_Relative expected_pay_duration, 762 unsigned int http_status) 763 { 764 struct TALER_TESTING_Command cmd; 765 struct PostUsingTemplatesState *tis; 766 767 cmd = TALER_TESTING_cmd_merchant_post_using_templates ( 768 label, 769 template_ref, 770 otp_ref, 771 merchant_url, 772 using_template_id, 773 summary, 774 amount, 775 refund_deadline, 776 pay_deadline, 777 http_status); 778 tis = cmd.cls; 779 tis->pay_duration = expected_pay_duration; 780 tis->have_expected_pay_duration = true; 781 return cmd; 782 } 783 784 785 struct TALER_TESTING_Command 786 TALER_TESTING_cmd_merchant_post_using_templates2 ( 787 const char *label, 788 const char *template_ref, 789 const char *otp_ref, 790 const char *merchant_url, 791 const char *using_template_id, 792 const json_t *details, 793 unsigned int http_status) 794 { 795 struct PostUsingTemplatesState *tis; 796 797 tis = GNUNET_new (struct PostUsingTemplatesState); 798 tis->template_ref = template_ref; 799 tis->otp_ref = otp_ref; 800 tis->merchant_url = merchant_url; 801 tis->using_template_id = using_template_id; 802 tis->http_status = http_status; 803 tis->with_claim = true; 804 if (NULL != details) 805 tis->details = json_incref ((json_t *) details); 806 { 807 struct TALER_TESTING_Command cmd = { 808 .cls = tis, 809 .label = label, 810 .run = &post_using_templates_run, 811 .cleanup = &post_using_templates_cleanup, 812 .traits = &post_using_templates_traits 813 }; 814 815 return cmd; 816 } 817 } 818 819 820 /* end of testing_api_cmd_post_using_templates.c */