testing_api_cmd_wallet_get_order.c (24788B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020 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 testing_api_cmd_wallet_get_order.c 21 * @brief command to test GET /order/$ORDER_ID 22 * @author Jonathan Buchanan 23 */ 24 #include "taler/platform.h" 25 #include <taler/taler_exchange_service.h> 26 #include <taler/taler_testing_lib.h> 27 #include "taler/taler_merchant_service.h" 28 #include "taler/taler_merchant_testing_lib.h" 29 #include <taler/taler-merchant/get-orders-ORDER_ID.h> 30 31 32 /** 33 * State for a GET /orders/$ORDER_ID CMD. 34 */ 35 struct WalletGetOrderState 36 { 37 /** 38 * The merchant base URL. 39 */ 40 const char *merchant_url; 41 42 /** 43 * Expected HTTP response code for this CMD. 44 */ 45 unsigned int http_status; 46 47 /** 48 * The handle to the current GET /orders/$ORDER_ID request. 49 */ 50 struct TALER_MERCHANT_GetOrdersHandle *ogh; 51 52 /** 53 * The interpreter state. 54 */ 55 struct TALER_TESTING_Interpreter *is; 56 57 /** 58 * Reference to a command that created an order. 59 */ 60 const char *order_reference; 61 62 /** 63 * Reference to a command that created a paid 64 * equivalent order that we expect to be referred 65 * to during repurchase detection, or NULL. 66 */ 67 const char *repurchase_order_ref; 68 69 /** 70 * Session Id the order needs to be bound to. 71 */ 72 const char *session_id; 73 74 /** 75 * Whether the order was paid or not. 76 */ 77 bool paid; 78 79 /** 80 * Whether the order was refunded or not. 81 */ 82 bool refunded; 83 84 /** 85 * Whether the order has refunds pending. 86 */ 87 bool refund_pending; 88 }; 89 90 91 /** 92 * Callback to process a GET /orders/$ID request 93 * 94 * @param cls closure 95 * @param owgr response details 96 */ 97 static void 98 wallet_get_order_cb ( 99 void *cls, 100 const struct TALER_MERCHANT_GetOrdersResponse *owgr) 101 { 102 struct WalletGetOrderState *gos = cls; 103 const struct TALER_MERCHANT_HttpResponse *hr = &owgr->hr; 104 105 gos->ogh = NULL; 106 if (gos->http_status != hr->http_status) 107 { 108 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 109 "Unexpected response code %u (%d) to command %s\n", 110 hr->http_status, 111 (int) hr->ec, 112 TALER_TESTING_interpreter_get_current_label (gos->is)); 113 TALER_TESTING_interpreter_fail (gos->is); 114 return; 115 } 116 switch (hr->http_status) 117 { 118 case MHD_HTTP_OK: 119 if (gos->refunded != owgr->details.ok.refunded) 120 { 121 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 122 "Order refunded does not match\n"); 123 TALER_TESTING_interpreter_fail (gos->is); 124 return; 125 } 126 if (gos->refund_pending != owgr->details.ok.refund_pending) 127 { 128 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 129 "Order refund pending does not match\n"); 130 TALER_TESTING_interpreter_fail (gos->is); 131 return; 132 } 133 break; 134 case MHD_HTTP_PAYMENT_REQUIRED: 135 { 136 struct TALER_MERCHANT_PayUriData pud; 137 const struct TALER_TESTING_Command *order_cmd; 138 const char *order_id; 139 const struct TALER_ClaimTokenP *claim_token; 140 141 if (NULL != gos->repurchase_order_ref) 142 { 143 const struct TALER_TESTING_Command *rep_cmd; 144 const char *rep_id; 145 const char *ri; 146 147 rep_cmd = TALER_TESTING_interpreter_lookup_command ( 148 gos->is, 149 gos->repurchase_order_ref); 150 if (GNUNET_OK != 151 TALER_TESTING_get_trait_order_id (rep_cmd, 152 &rep_id)) 153 { 154 TALER_TESTING_FAIL (gos->is); 155 } 156 ri = owgr->details.payment_required.already_paid_order_id; 157 if ( (NULL == ri) || 158 (0 != 159 strcmp (ri, 160 rep_id)) ) 161 { 162 TALER_TESTING_FAIL (gos->is); 163 } 164 } 165 166 if (GNUNET_OK != 167 TALER_MERCHANT_parse_pay_uri ( 168 owgr->details.payment_required.taler_pay_uri, 169 &pud)) 170 { 171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 172 "Taler pay uri `%s' is malformed\n", 173 owgr->details.payment_required.taler_pay_uri); 174 TALER_TESTING_interpreter_fail (gos->is); 175 return; 176 } 177 178 order_cmd = TALER_TESTING_interpreter_lookup_command ( 179 gos->is, 180 gos->order_reference); 181 182 if (GNUNET_OK != 183 TALER_TESTING_get_trait_order_id (order_cmd, 184 &order_id)) 185 { 186 TALER_MERCHANT_parse_pay_uri_free (&pud); 187 TALER_TESTING_FAIL (gos->is); 188 } 189 190 if (GNUNET_OK != 191 TALER_TESTING_get_trait_claim_token (order_cmd, 192 &claim_token)) 193 { 194 TALER_MERCHANT_parse_pay_uri_free (&pud); 195 TALER_TESTING_FAIL (gos->is); 196 } 197 198 { 199 char *host; 200 201 host = TALER_MERCHANT_TESTING_extract_host (gos->merchant_url); 202 if ((0 != strcmp (host, 203 pud.merchant_host)) || 204 (NULL != pud.merchant_prefix_path) || 205 (0 != strcmp (order_id, 206 pud.order_id)) || 207 (NULL != pud.ssid)) 208 { 209 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 210 "Order pay uri `%s' does not match `%s'\n", 211 owgr->details.payment_required.taler_pay_uri, 212 pud.order_id); 213 TALER_TESTING_interpreter_fail (gos->is); 214 TALER_MERCHANT_parse_pay_uri_free (&pud); 215 GNUNET_free (host); 216 return; 217 } 218 GNUNET_free (host); 219 } 220 /* The claim token is not given in the pay uri if the order 221 has been claimed already. */ 222 if ((NULL != pud.claim_token) && 223 ((NULL == claim_token) || 224 (0 != GNUNET_memcmp (claim_token, 225 pud.claim_token)))) 226 { 227 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 228 "Order pay uri claim token does not match (%d/%d)\n", 229 NULL == pud.claim_token, 230 NULL == claim_token); 231 TALER_TESTING_interpreter_fail (gos->is); 232 TALER_MERCHANT_parse_pay_uri_free (&pud); 233 return; 234 } 235 TALER_MERCHANT_parse_pay_uri_free (&pud); 236 } 237 break; 238 default: 239 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 240 "Unhandled HTTP status.\n"); 241 } 242 TALER_TESTING_interpreter_next (gos->is); 243 } 244 245 246 /** 247 * Run the "GET order" CMD. 248 * 249 * @param cls closure. 250 * @param cmd command being run now. 251 * @param is interpreter state. 252 */ 253 static void 254 wallet_get_order_run (void *cls, 255 const struct TALER_TESTING_Command *cmd, 256 struct TALER_TESTING_Interpreter *is) 257 { 258 struct WalletGetOrderState *gos = cls; 259 const struct TALER_TESTING_Command *order_cmd; 260 const char *order_id; 261 const struct TALER_PrivateContractHashP *h_contract; 262 263 order_cmd = TALER_TESTING_interpreter_lookup_command ( 264 is, 265 gos->order_reference); 266 267 if (GNUNET_OK != 268 TALER_TESTING_get_trait_order_id (order_cmd, 269 &order_id)) 270 TALER_TESTING_FAIL (is); 271 272 if (GNUNET_OK != 273 TALER_TESTING_get_trait_h_contract_terms (order_cmd, 274 &h_contract)) 275 TALER_TESTING_FAIL (is); 276 277 gos->is = is; 278 gos->ogh = TALER_MERCHANT_get_orders_create ( 279 TALER_TESTING_interpreter_get_context (is), 280 gos->merchant_url, 281 order_id); 282 GNUNET_assert ( 283 GNUNET_OK == 284 TALER_MERCHANT_get_orders_set_options ( 285 gos->ogh, 286 TALER_MERCHANT_get_orders_option_h_contract (*h_contract), 287 TALER_MERCHANT_get_orders_option_session_id (gos->session_id))); 288 { 289 enum TALER_ErrorCode ec; 290 291 ec = TALER_MERCHANT_get_orders_start ( 292 gos->ogh, 293 &wallet_get_order_cb, 294 gos); 295 GNUNET_assert (TALER_EC_NONE == ec); 296 } 297 } 298 299 300 /** 301 * Free the state of a "GET order" CMD, and possibly 302 * cancel a pending operation thereof. 303 * 304 * @param cls closure. 305 * @param cmd command being run. 306 */ 307 static void 308 wallet_get_order_cleanup (void *cls, 309 const struct TALER_TESTING_Command *cmd) 310 { 311 struct WalletGetOrderState *gos = cls; 312 313 if (NULL != gos->ogh) 314 { 315 TALER_LOG_WARNING ("Get order operation did not complete\n"); 316 TALER_MERCHANT_get_orders_cancel (gos->ogh); 317 } 318 GNUNET_free (gos); 319 } 320 321 322 struct TALER_TESTING_Command 323 TALER_TESTING_cmd_wallet_get_order ( 324 const char *label, 325 const char *merchant_url, 326 const char *order_reference, 327 bool paid, 328 bool refunded, 329 bool refund_pending, 330 unsigned int http_status) 331 { 332 struct WalletGetOrderState *gos; 333 334 gos = GNUNET_new (struct WalletGetOrderState); 335 gos->merchant_url = merchant_url; 336 gos->order_reference = order_reference; 337 gos->http_status = http_status; 338 gos->paid = paid; 339 gos->refunded = refunded; 340 gos->refund_pending = refund_pending; 341 { 342 struct TALER_TESTING_Command cmd = { 343 .cls = gos, 344 .label = label, 345 .run = &wallet_get_order_run, 346 .cleanup = &wallet_get_order_cleanup 347 }; 348 349 return cmd; 350 } 351 } 352 353 354 struct TALER_TESTING_Command 355 TALER_TESTING_cmd_wallet_get_order2 ( 356 const char *label, 357 const char *merchant_url, 358 const char *order_reference, 359 const char *session_id, 360 bool paid, 361 bool refunded, 362 bool refund_pending, 363 const char *repurchase_order_ref, 364 unsigned int http_status) 365 { 366 struct WalletGetOrderState *gos; 367 368 gos = GNUNET_new (struct WalletGetOrderState); 369 gos->merchant_url = merchant_url; 370 gos->order_reference = order_reference; 371 gos->http_status = http_status; 372 gos->paid = paid; 373 gos->session_id = session_id; 374 gos->refunded = refunded; 375 gos->refund_pending = refund_pending; 376 gos->repurchase_order_ref = repurchase_order_ref; 377 { 378 struct TALER_TESTING_Command cmd = { 379 .cls = gos, 380 .label = label, 381 .run = &wallet_get_order_run, 382 .cleanup = &wallet_get_order_cleanup 383 }; 384 385 return cmd; 386 } 387 } 388 389 390 struct WalletPollOrderConcludeState 391 { 392 /** 393 * The interpreter state. 394 */ 395 struct TALER_TESTING_Interpreter *is; 396 397 /** 398 * Reference to a command that can provide a poll order start command. 399 */ 400 const char *start_reference; 401 402 /** 403 * Already paid order ID expected, or NULL for none. 404 */ 405 const char *already_paid_order_id; 406 407 /** 408 * Task to wait for the deadline. 409 */ 410 struct GNUNET_SCHEDULER_Task *task; 411 412 /** 413 * Amount of a refund expected. 414 */ 415 struct TALER_Amount expected_refund_amount; 416 417 /** 418 * Expected HTTP response status code. 419 */ 420 unsigned int expected_http_status; 421 422 /** 423 * Are we expecting a refund? 424 */ 425 bool expected_refund; 426 }; 427 428 429 struct WalletPollOrderStartState 430 { 431 /** 432 * The merchant base URL. 433 */ 434 const char *merchant_url; 435 436 /** 437 * The handle to the current GET /orders/$ORDER_ID request. 438 */ 439 struct TALER_MERCHANT_GetOrdersHandle *ogh; 440 441 /** 442 * The interpreter state. 443 */ 444 struct TALER_TESTING_Interpreter *is; 445 446 /** 447 * Reference to a command that created an order. 448 */ 449 const char *order_ref; 450 451 /** 452 * Which session ID to poll for. 453 */ 454 const char *session_id; 455 456 /** 457 * How long to wait for server to return a response. 458 */ 459 struct GNUNET_TIME_Relative timeout; 460 461 /** 462 * Conclude state waiting for completion (if any). 463 */ 464 struct WalletPollOrderConcludeState *cs; 465 466 /** 467 * The HTTP status code returned by the backend. 468 */ 469 unsigned int http_status; 470 471 /** 472 * When the request should be completed by. 473 */ 474 struct GNUNET_TIME_Absolute deadline; 475 476 /** 477 * Minimum refund to wait for. 478 */ 479 struct TALER_Amount refund_threshold; 480 481 /** 482 * Available refund as returned by the merchant. 483 */ 484 struct TALER_Amount refund_available; 485 486 /** 487 * Already paid order ID returned, or NULL for none. 488 */ 489 char *already_paid_order_id; 490 491 /** 492 * Should we poll for a refund? 493 */ 494 bool wait_for_refund; 495 496 /** 497 * Did we receive a refund according to response from the merchant? 498 */ 499 bool refunded; 500 501 /** 502 * Was the order paid according to response from the merchant? 503 */ 504 bool paid; 505 506 /** 507 * Has the order a pending refund according to response from the merchant? 508 */ 509 bool refund_pending; 510 }; 511 512 513 /** 514 * Task called when either the timeout for the GET /private/order/$ID command 515 * expired or we got a response. Checks if the result is what we expected. 516 * 517 * @param cls a `struct WalletPollOrderConcludeState` 518 */ 519 static void 520 conclude_task (void *cls) 521 { 522 struct WalletPollOrderConcludeState *ppc = cls; 523 const struct TALER_TESTING_Command *poll_cmd; 524 struct WalletPollOrderStartState *cps; 525 struct GNUNET_TIME_Absolute now; 526 527 ppc->task = NULL; 528 poll_cmd = 529 TALER_TESTING_interpreter_lookup_command (ppc->is, 530 ppc->start_reference); 531 if (NULL == poll_cmd) 532 TALER_TESTING_FAIL (ppc->is); 533 cps = poll_cmd->cls; 534 if (NULL != cps->ogh) 535 { 536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 537 "Expected poll GET /orders/$ORDER_ID to have completed, but it did not!\n"); 538 TALER_TESTING_FAIL (ppc->is); 539 } 540 if (cps->http_status != ppc->expected_http_status) 541 { 542 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 543 "Expected HTTP status %u, got %u\n", 544 ppc->expected_http_status, 545 cps->http_status); 546 TALER_TESTING_FAIL (ppc->is); 547 } 548 if (ppc->expected_refund != cps->refunded) 549 { 550 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 551 "Order was %srefunded, contrary to our expectations\n", 552 cps->refunded ? "" : "NOT "); 553 TALER_TESTING_FAIL (ppc->is); 554 } 555 if ( (NULL == ppc->already_paid_order_id) 556 ^ (NULL == cps->already_paid_order_id) ) 557 { 558 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 559 "Mismatch in already paid order IDs: %s vs %s\n", 560 ppc->already_paid_order_id, 561 cps->already_paid_order_id); 562 TALER_TESTING_FAIL (ppc->is); 563 } 564 if ( (NULL != ppc->already_paid_order_id) && 565 (0 != strcmp (ppc->already_paid_order_id, 566 cps->already_paid_order_id) ) ) 567 { 568 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 569 "Mismatch in already paid order IDs: %s vs %s\n", 570 ppc->already_paid_order_id, 571 cps->already_paid_order_id); 572 TALER_TESTING_FAIL (ppc->is); 573 } 574 575 if (cps->refunded) 576 { 577 if (0 != TALER_amount_cmp (&ppc->expected_refund_amount, 578 &cps->refund_available)) 579 { 580 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 581 "Refund amount %s does not match our expectation!\n", 582 TALER_amount2s (&cps->refund_available)); 583 TALER_TESTING_FAIL (ppc->is); 584 } 585 } 586 // FIXME: add checks for cps->paid/refund_available status flags? 587 now = GNUNET_TIME_absolute_get (); 588 if ((GNUNET_TIME_absolute_add (cps->deadline, 589 GNUNET_TIME_UNIT_SECONDS).abs_value_us < 590 now.abs_value_us) ) 591 { 592 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 593 "Expected answer to be delayed until %llu, but got response at %llu\n", 594 (unsigned long long) cps->deadline.abs_value_us, 595 (unsigned long long) now.abs_value_us); 596 TALER_TESTING_FAIL (ppc->is); 597 } 598 TALER_TESTING_interpreter_next (ppc->is); 599 } 600 601 602 /** 603 * Process response from a GET /orders/$ID request 604 * 605 * @param cls a `struct WalletPollOrderStartState *` 606 * @param owgr response details 607 */ 608 static void 609 wallet_poll_order_cb ( 610 void *cls, 611 const struct TALER_MERCHANT_GetOrdersResponse *owgr) 612 { 613 struct WalletPollOrderStartState *pos = cls; 614 const struct TALER_MERCHANT_HttpResponse *hr = &owgr->hr; 615 616 pos->ogh = NULL; 617 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 618 "GET /orders/$ID finished with status %u.\n", 619 hr->http_status); 620 pos->http_status = hr->http_status; 621 switch (hr->http_status) 622 { 623 case MHD_HTTP_OK: 624 pos->paid = true; 625 pos->refunded = owgr->details.ok.refunded; 626 pos->refund_pending = owgr->details.ok.refund_pending; 627 if (owgr->details.ok.refunded) 628 pos->refund_available = owgr->details.ok.refund_amount; 629 break; 630 case MHD_HTTP_PAYMENT_REQUIRED: 631 if (NULL != owgr->details.payment_required.already_paid_order_id) 632 pos->already_paid_order_id = GNUNET_strdup ( 633 owgr->details.payment_required.already_paid_order_id); 634 break; 635 default: 636 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 637 "Unhandled HTTP status.\n"); 638 break; 639 } 640 if ( (NULL != pos->cs) && 641 (NULL != pos->cs->task) ) 642 { 643 GNUNET_SCHEDULER_cancel (pos->cs->task); 644 pos->cs->task = GNUNET_SCHEDULER_add_now (&conclude_task, 645 pos->cs); 646 } 647 } 648 649 650 /** 651 * Run the "GET order" CMD. 652 * 653 * @param cls closure. 654 * @param cmd command being run now. 655 * @param is interpreter state. 656 */ 657 static void 658 wallet_poll_order_start_run (void *cls, 659 const struct TALER_TESTING_Command *cmd, 660 struct TALER_TESTING_Interpreter *is) 661 { 662 struct WalletPollOrderStartState *pos = cls; 663 const struct TALER_TESTING_Command *order_cmd; 664 const char *order_id; 665 const struct TALER_PrivateContractHashP *h_contract; 666 667 order_cmd = TALER_TESTING_interpreter_lookup_command ( 668 is, 669 pos->order_ref); 670 671 if (GNUNET_OK != 672 TALER_TESTING_get_trait_order_id (order_cmd, 673 &order_id)) 674 TALER_TESTING_FAIL (is); 675 676 if (GNUNET_OK != 677 TALER_TESTING_get_trait_h_contract_terms (order_cmd, 678 &h_contract)) 679 TALER_TESTING_FAIL (is); 680 681 /* add 1s grace time to timeout */ 682 pos->deadline 683 = GNUNET_TIME_absolute_add (GNUNET_TIME_relative_to_absolute (pos->timeout), 684 GNUNET_TIME_UNIT_SECONDS); 685 pos->is = is; 686 pos->ogh = TALER_MERCHANT_get_orders_create ( 687 TALER_TESTING_interpreter_get_context (is), 688 pos->merchant_url, 689 order_id); 690 TALER_MERCHANT_get_orders_set_options ( 691 pos->ogh, 692 TALER_MERCHANT_get_orders_option_h_contract (*h_contract)); 693 TALER_MERCHANT_get_orders_set_options ( 694 pos->ogh, 695 TALER_MERCHANT_get_orders_option_timeout (pos->timeout), 696 TALER_MERCHANT_get_orders_option_session_id (pos->session_id)); 697 if (pos->wait_for_refund) 698 TALER_MERCHANT_get_orders_set_options ( 699 pos->ogh, 700 TALER_MERCHANT_get_orders_option_min_refund (pos->refund_threshold)); 701 { 702 enum TALER_ErrorCode ec; 703 704 ec = TALER_MERCHANT_get_orders_start ( 705 pos->ogh, 706 &wallet_poll_order_cb, 707 pos); 708 GNUNET_assert (TALER_EC_NONE == ec); 709 } 710 /* We CONTINUE to run the interpreter while the long-polled command 711 completes asynchronously! */ 712 TALER_TESTING_interpreter_next (pos->is); 713 } 714 715 716 /** 717 * Free the state of a "GET order" CMD, and possibly 718 * cancel a pending operation thereof. 719 * 720 * @param cls closure. 721 * @param cmd command being run. 722 */ 723 static void 724 wallet_poll_order_start_cleanup (void *cls, 725 const struct TALER_TESTING_Command *cmd) 726 { 727 struct WalletPollOrderStartState *pos = cls; 728 729 if (NULL != pos->ogh) 730 { 731 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 732 "Command `%s' was not terminated\n", 733 TALER_TESTING_interpreter_get_current_label ( 734 pos->is)); 735 TALER_MERCHANT_get_orders_cancel (pos->ogh); 736 } 737 GNUNET_free (pos->already_paid_order_id); 738 GNUNET_free (pos); 739 } 740 741 742 struct TALER_TESTING_Command 743 TALER_TESTING_cmd_wallet_poll_order_start ( 744 const char *label, 745 const char *merchant_url, 746 const char *order_ref, 747 struct GNUNET_TIME_Relative timeout, 748 const char *await_refund) 749 { 750 struct WalletPollOrderStartState *pos; 751 752 pos = GNUNET_new (struct WalletPollOrderStartState); 753 pos->order_ref = order_ref; 754 pos->merchant_url = merchant_url; 755 pos->timeout = timeout; 756 if (NULL != await_refund) 757 { 758 pos->wait_for_refund = true; 759 GNUNET_assert (GNUNET_OK == 760 TALER_string_to_amount (await_refund, 761 &pos->refund_threshold)); 762 } 763 { 764 struct TALER_TESTING_Command cmd = { 765 .cls = pos, 766 .label = label, 767 .run = &wallet_poll_order_start_run, 768 .cleanup = &wallet_poll_order_start_cleanup 769 }; 770 771 return cmd; 772 } 773 } 774 775 776 struct TALER_TESTING_Command 777 TALER_TESTING_cmd_wallet_poll_order_start2 ( 778 const char *label, 779 const char *merchant_url, 780 const char *order_ref, 781 struct GNUNET_TIME_Relative timeout, 782 const char *await_refund, 783 const char *session_id) 784 { 785 struct WalletPollOrderStartState *pos; 786 struct TALER_TESTING_Command cmd; 787 788 cmd = TALER_TESTING_cmd_wallet_poll_order_start (label, 789 merchant_url, 790 order_ref, 791 timeout, 792 await_refund); 793 pos = cmd.cls; 794 pos->session_id = session_id; 795 return cmd; 796 } 797 798 799 /** 800 * Run the "GET order conclude" CMD. 801 * 802 * @param cls closure. 803 * @param cmd command being run now. 804 * @param is interpreter state. 805 */ 806 static void 807 wallet_poll_order_conclude_run (void *cls, 808 const struct TALER_TESTING_Command *cmd, 809 struct TALER_TESTING_Interpreter *is) 810 { 811 struct WalletPollOrderConcludeState *poc = cls; 812 const struct TALER_TESTING_Command *poll_cmd; 813 struct WalletPollOrderStartState *pos; 814 815 poc->is = is; 816 poll_cmd = 817 TALER_TESTING_interpreter_lookup_command (is, 818 poc->start_reference); 819 if (NULL == poll_cmd) 820 TALER_TESTING_FAIL (poc->is); 821 GNUNET_assert (poll_cmd->run == &wallet_poll_order_start_run); 822 pos = poll_cmd->cls; 823 pos->cs = poc; 824 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 825 "Waiting on GET /orders/$ID of %s (%s)\n", 826 poc->start_reference, 827 (NULL == pos->ogh) 828 ? "finished" 829 : "active"); 830 if (NULL == pos->ogh) 831 poc->task = GNUNET_SCHEDULER_add_now (&conclude_task, 832 poc); 833 else 834 poc->task = GNUNET_SCHEDULER_add_at (pos->deadline, 835 &conclude_task, 836 poc); 837 } 838 839 840 /** 841 * Free the state of a "GET order" CMD, and possibly 842 * cancel a pending operation thereof. 843 * 844 * @param cls closure. 845 * @param cmd command being run. 846 */ 847 static void 848 wallet_poll_order_conclude_cleanup (void *cls, 849 const struct TALER_TESTING_Command *cmd) 850 { 851 struct WalletPollOrderConcludeState *poc = cls; 852 853 if (NULL != poc->task) 854 { 855 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 856 "Command `%s' was not terminated\n", 857 TALER_TESTING_interpreter_get_current_label ( 858 poc->is)); 859 GNUNET_SCHEDULER_cancel (poc->task); 860 poc->task = NULL; 861 } 862 GNUNET_free (poc); 863 } 864 865 866 struct TALER_TESTING_Command 867 TALER_TESTING_cmd_wallet_poll_order_conclude ( 868 const char *label, 869 unsigned int expected_http_status, 870 const char *expected_refund_amount, 871 const char *poll_start_reference) 872 { 873 struct WalletPollOrderConcludeState *cps; 874 875 cps = GNUNET_new (struct WalletPollOrderConcludeState); 876 cps->start_reference = poll_start_reference; 877 cps->expected_http_status = expected_http_status; 878 if (NULL != expected_refund_amount) 879 { 880 cps->expected_refund = true; 881 GNUNET_assert (GNUNET_OK == 882 TALER_string_to_amount (expected_refund_amount, 883 &cps->expected_refund_amount)); 884 } 885 { 886 struct TALER_TESTING_Command cmd = { 887 .cls = cps, 888 .label = label, 889 .run = &wallet_poll_order_conclude_run, 890 .cleanup = &wallet_poll_order_conclude_cleanup 891 }; 892 893 return cmd; 894 } 895 } 896 897 898 struct TALER_TESTING_Command 899 TALER_TESTING_cmd_wallet_poll_order_conclude2 ( 900 const char *label, 901 unsigned int expected_http_status, 902 const char *expected_refund_amount, 903 const char *poll_start_reference, 904 const char *already_paid_order_id) 905 { 906 struct WalletPollOrderConcludeState *cps; 907 struct TALER_TESTING_Command cmd; 908 909 cmd = TALER_TESTING_cmd_wallet_poll_order_conclude ( 910 label, 911 expected_http_status, 912 expected_refund_amount, 913 poll_start_reference); 914 cps = cmd.cls; 915 cps->already_paid_order_id = already_paid_order_id; 916 return cmd; 917 } 918 919 920 /* end of testing_api_cmd_wallet_get_order.c */