merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

testing_api_cmd_wallet_get_order.c (24630B)


      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     h_contract);
    283   if (NULL != gos->session_id)
    284     TALER_MERCHANT_get_orders_set_options (
    285       gos->ogh,
    286       TALER_MERCHANT_get_orders_option_session_id (gos->session_id));
    287   {
    288     enum TALER_ErrorCode ec;
    289 
    290     ec = TALER_MERCHANT_get_orders_start (
    291       gos->ogh,
    292       &wallet_get_order_cb,
    293       gos);
    294     GNUNET_assert (TALER_EC_NONE == ec);
    295   }
    296 }
    297 
    298 
    299 /**
    300  * Free the state of a "GET order" CMD, and possibly
    301  * cancel a pending operation thereof.
    302  *
    303  * @param cls closure.
    304  * @param cmd command being run.
    305  */
    306 static void
    307 wallet_get_order_cleanup (void *cls,
    308                           const struct TALER_TESTING_Command *cmd)
    309 {
    310   struct WalletGetOrderState *gos = cls;
    311 
    312   if (NULL != gos->ogh)
    313   {
    314     TALER_LOG_WARNING ("Get order operation did not complete\n");
    315     TALER_MERCHANT_get_orders_cancel (gos->ogh);
    316   }
    317   GNUNET_free (gos);
    318 }
    319 
    320 
    321 struct TALER_TESTING_Command
    322 TALER_TESTING_cmd_wallet_get_order (
    323   const char *label,
    324   const char *merchant_url,
    325   const char *order_reference,
    326   bool paid,
    327   bool refunded,
    328   bool refund_pending,
    329   unsigned int http_status)
    330 {
    331   struct WalletGetOrderState *gos;
    332 
    333   gos = GNUNET_new (struct WalletGetOrderState);
    334   gos->merchant_url = merchant_url;
    335   gos->order_reference = order_reference;
    336   gos->http_status = http_status;
    337   gos->paid = paid;
    338   gos->refunded = refunded;
    339   gos->refund_pending = refund_pending;
    340   {
    341     struct TALER_TESTING_Command cmd = {
    342       .cls = gos,
    343       .label = label,
    344       .run = &wallet_get_order_run,
    345       .cleanup = &wallet_get_order_cleanup
    346     };
    347 
    348     return cmd;
    349   }
    350 }
    351 
    352 
    353 struct TALER_TESTING_Command
    354 TALER_TESTING_cmd_wallet_get_order2 (
    355   const char *label,
    356   const char *merchant_url,
    357   const char *order_reference,
    358   const char *session_id,
    359   bool paid,
    360   bool refunded,
    361   bool refund_pending,
    362   const char *repurchase_order_ref,
    363   unsigned int http_status)
    364 {
    365   struct WalletGetOrderState *gos;
    366 
    367   gos = GNUNET_new (struct WalletGetOrderState);
    368   gos->merchant_url = merchant_url;
    369   gos->order_reference = order_reference;
    370   gos->http_status = http_status;
    371   gos->paid = paid;
    372   gos->session_id = session_id;
    373   gos->refunded = refunded;
    374   gos->refund_pending = refund_pending;
    375   gos->repurchase_order_ref = repurchase_order_ref;
    376   {
    377     struct TALER_TESTING_Command cmd = {
    378       .cls = gos,
    379       .label = label,
    380       .run = &wallet_get_order_run,
    381       .cleanup = &wallet_get_order_cleanup
    382     };
    383 
    384     return cmd;
    385   }
    386 }
    387 
    388 
    389 struct WalletPollOrderConcludeState
    390 {
    391   /**
    392    * The interpreter state.
    393    */
    394   struct TALER_TESTING_Interpreter *is;
    395 
    396   /**
    397    * Reference to a command that can provide a poll order start command.
    398    */
    399   const char *start_reference;
    400 
    401   /**
    402    * Already paid order ID expected, or NULL for none.
    403    */
    404   const char *already_paid_order_id;
    405 
    406   /**
    407    * Task to wait for the deadline.
    408    */
    409   struct GNUNET_SCHEDULER_Task *task;
    410 
    411   /**
    412    * Amount of a refund expected.
    413    */
    414   struct TALER_Amount expected_refund_amount;
    415 
    416   /**
    417    * Expected HTTP response status code.
    418    */
    419   unsigned int expected_http_status;
    420 
    421   /**
    422    * Are we expecting a refund?
    423    */
    424   bool expected_refund;
    425 };
    426 
    427 
    428 struct WalletPollOrderStartState
    429 {
    430   /**
    431    * The merchant base URL.
    432    */
    433   const char *merchant_url;
    434 
    435   /**
    436    * The handle to the current GET /orders/$ORDER_ID request.
    437    */
    438   struct TALER_MERCHANT_GetOrdersHandle *ogh;
    439 
    440   /**
    441    * The interpreter state.
    442    */
    443   struct TALER_TESTING_Interpreter *is;
    444 
    445   /**
    446    * Reference to a command that created an order.
    447    */
    448   const char *order_ref;
    449 
    450   /**
    451    * Which session ID to poll for.
    452    */
    453   const char *session_id;
    454 
    455   /**
    456    * How long to wait for server to return a response.
    457    */
    458   struct GNUNET_TIME_Relative timeout;
    459 
    460   /**
    461    * Conclude state waiting for completion (if any).
    462    */
    463   struct WalletPollOrderConcludeState *cs;
    464 
    465   /**
    466    * The HTTP status code returned by the backend.
    467    */
    468   unsigned int http_status;
    469 
    470   /**
    471    * When the request should be completed by.
    472    */
    473   struct GNUNET_TIME_Absolute deadline;
    474 
    475   /**
    476    * Minimum refund to wait for.
    477    */
    478   struct TALER_Amount refund_threshold;
    479 
    480   /**
    481    * Available refund as returned by the merchant.
    482    */
    483   struct TALER_Amount refund_available;
    484 
    485   /**
    486    * Already paid order ID returned, or NULL for none.
    487    */
    488   char *already_paid_order_id;
    489 
    490   /**
    491    * Should we poll for a refund?
    492    */
    493   bool wait_for_refund;
    494 
    495   /**
    496    * Did we receive a refund according to response from the merchant?
    497    */
    498   bool refunded;
    499 
    500   /**
    501    * Was the order paid according to response from the merchant?
    502    */
    503   bool paid;
    504 
    505   /**
    506    * Has the order a pending refund according to response from the merchant?
    507    */
    508   bool refund_pending;
    509 };
    510 
    511 
    512 /**
    513  * Task called when either the timeout for the GET /private/order/$ID command
    514  * expired or we got a response.  Checks if the result is what we expected.
    515  *
    516  * @param cls a `struct WalletPollOrderConcludeState`
    517  */
    518 static void
    519 conclude_task (void *cls)
    520 {
    521   struct WalletPollOrderConcludeState *ppc = cls;
    522   const struct TALER_TESTING_Command *poll_cmd;
    523   struct WalletPollOrderStartState *cps;
    524   struct GNUNET_TIME_Absolute now;
    525 
    526   ppc->task = NULL;
    527   poll_cmd =
    528     TALER_TESTING_interpreter_lookup_command (ppc->is,
    529                                               ppc->start_reference);
    530   if (NULL == poll_cmd)
    531     TALER_TESTING_FAIL (ppc->is);
    532   cps = poll_cmd->cls;
    533   if (NULL != cps->ogh)
    534   {
    535     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    536                 "Expected poll GET /orders/$ORDER_ID to have completed, but it did not!\n");
    537     TALER_TESTING_FAIL (ppc->is);
    538   }
    539   if (cps->http_status != ppc->expected_http_status)
    540   {
    541     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    542                 "Expected HTTP status %u, got %u\n",
    543                 ppc->expected_http_status,
    544                 cps->http_status);
    545     TALER_TESTING_FAIL (ppc->is);
    546   }
    547   if (ppc->expected_refund != cps->refunded)
    548   {
    549     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    550                 "Order was %srefunded, contrary to our expectations\n",
    551                 cps->refunded ? "" : "NOT ");
    552     TALER_TESTING_FAIL (ppc->is);
    553   }
    554   if ( (NULL == ppc->already_paid_order_id)
    555        ^ (NULL == cps->already_paid_order_id) )
    556   {
    557     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    558                 "Mismatch in already paid order IDs: %s vs %s\n",
    559                 ppc->already_paid_order_id,
    560                 cps->already_paid_order_id);
    561     TALER_TESTING_FAIL (ppc->is);
    562   }
    563   if ( (NULL != ppc->already_paid_order_id) &&
    564        (0 != strcmp (ppc->already_paid_order_id,
    565                      cps->already_paid_order_id) ) )
    566   {
    567     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    568                 "Mismatch in already paid order IDs: %s vs %s\n",
    569                 ppc->already_paid_order_id,
    570                 cps->already_paid_order_id);
    571     TALER_TESTING_FAIL (ppc->is);
    572   }
    573 
    574   if (cps->refunded)
    575   {
    576     if (0 != TALER_amount_cmp (&ppc->expected_refund_amount,
    577                                &cps->refund_available))
    578     {
    579       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    580                   "Refund amount %s does not match our expectation!\n",
    581                   TALER_amount2s (&cps->refund_available));
    582       TALER_TESTING_FAIL (ppc->is);
    583     }
    584   }
    585   // FIXME: add checks for cps->paid/refund_available status flags?
    586   now = GNUNET_TIME_absolute_get ();
    587   if ((GNUNET_TIME_absolute_add (cps->deadline,
    588                                  GNUNET_TIME_UNIT_SECONDS).abs_value_us <
    589        now.abs_value_us) )
    590   {
    591     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    592                 "Expected answer to be delayed until %llu, but got response at %llu\n",
    593                 (unsigned long long) cps->deadline.abs_value_us,
    594                 (unsigned long long) now.abs_value_us);
    595     TALER_TESTING_FAIL (ppc->is);
    596   }
    597   TALER_TESTING_interpreter_next (ppc->is);
    598 }
    599 
    600 
    601 /**
    602  * Process response from a GET /orders/$ID request
    603  *
    604  * @param cls a `struct WalletPollOrderStartState *`
    605  * @param owgr response details
    606  */
    607 static void
    608 wallet_poll_order_cb (
    609   void *cls,
    610   const struct TALER_MERCHANT_GetOrdersResponse *owgr)
    611 {
    612   struct WalletPollOrderStartState *pos = cls;
    613   const struct TALER_MERCHANT_HttpResponse *hr = &owgr->hr;
    614 
    615   pos->ogh = NULL;
    616   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    617               "GET /orders/$ID finished with status %u.\n",
    618               hr->http_status);
    619   pos->http_status = hr->http_status;
    620   switch (hr->http_status)
    621   {
    622   case MHD_HTTP_OK:
    623     pos->paid = true;
    624     pos->refunded = owgr->details.ok.refunded;
    625     pos->refund_pending = owgr->details.ok.refund_pending;
    626     if (owgr->details.ok.refunded)
    627       pos->refund_available = owgr->details.ok.refund_amount;
    628     break;
    629   case MHD_HTTP_PAYMENT_REQUIRED:
    630     if (NULL != owgr->details.payment_required.already_paid_order_id)
    631       pos->already_paid_order_id = GNUNET_strdup (
    632         owgr->details.payment_required.already_paid_order_id);
    633     break;
    634   default:
    635     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    636                 "Unhandled HTTP status.\n");
    637     break;
    638   }
    639   if ( (NULL != pos->cs) &&
    640        (NULL != pos->cs->task) )
    641   {
    642     GNUNET_SCHEDULER_cancel (pos->cs->task);
    643     pos->cs->task = GNUNET_SCHEDULER_add_now (&conclude_task,
    644                                               pos->cs);
    645   }
    646 }
    647 
    648 
    649 /**
    650  * Run the "GET order" CMD.
    651  *
    652  * @param cls closure.
    653  * @param cmd command being run now.
    654  * @param is interpreter state.
    655  */
    656 static void
    657 wallet_poll_order_start_run (void *cls,
    658                              const struct TALER_TESTING_Command *cmd,
    659                              struct TALER_TESTING_Interpreter *is)
    660 {
    661   struct WalletPollOrderStartState *pos = cls;
    662   const struct TALER_TESTING_Command *order_cmd;
    663   const char *order_id;
    664   const struct TALER_PrivateContractHashP *h_contract;
    665 
    666   order_cmd = TALER_TESTING_interpreter_lookup_command (
    667     is,
    668     pos->order_ref);
    669 
    670   if (GNUNET_OK !=
    671       TALER_TESTING_get_trait_order_id (order_cmd,
    672                                         &order_id))
    673     TALER_TESTING_FAIL (is);
    674 
    675   if (GNUNET_OK !=
    676       TALER_TESTING_get_trait_h_contract_terms (order_cmd,
    677                                                 &h_contract))
    678     TALER_TESTING_FAIL (is);
    679 
    680   /* add 1s grace time to timeout */
    681   pos->deadline
    682     = GNUNET_TIME_absolute_add (GNUNET_TIME_relative_to_absolute (pos->timeout),
    683                                 GNUNET_TIME_UNIT_SECONDS);
    684   pos->is = is;
    685   pos->ogh = TALER_MERCHANT_get_orders_create (
    686     TALER_TESTING_interpreter_get_context (is),
    687     pos->merchant_url,
    688     order_id,
    689     h_contract);
    690   TALER_MERCHANT_get_orders_set_options (
    691     pos->ogh,
    692     TALER_MERCHANT_get_orders_option_timeout (pos->timeout),
    693     TALER_MERCHANT_get_orders_option_session_id (pos->session_id));
    694   if (pos->wait_for_refund)
    695     TALER_MERCHANT_get_orders_set_options (
    696       pos->ogh,
    697       TALER_MERCHANT_get_orders_option_min_refund (pos->refund_threshold));
    698   {
    699     enum TALER_ErrorCode ec;
    700 
    701     ec = TALER_MERCHANT_get_orders_start (
    702       pos->ogh,
    703       &wallet_poll_order_cb,
    704       pos);
    705     GNUNET_assert (TALER_EC_NONE == ec);
    706   }
    707   /* We CONTINUE to run the interpreter while the long-polled command
    708      completes asynchronously! */
    709   TALER_TESTING_interpreter_next (pos->is);
    710 }
    711 
    712 
    713 /**
    714  * Free the state of a "GET order" CMD, and possibly
    715  * cancel a pending operation thereof.
    716  *
    717  * @param cls closure.
    718  * @param cmd command being run.
    719  */
    720 static void
    721 wallet_poll_order_start_cleanup (void *cls,
    722                                  const struct TALER_TESTING_Command *cmd)
    723 {
    724   struct WalletPollOrderStartState *pos = cls;
    725 
    726   if (NULL != pos->ogh)
    727   {
    728     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    729                 "Command `%s' was not terminated\n",
    730                 TALER_TESTING_interpreter_get_current_label (
    731                   pos->is));
    732     TALER_MERCHANT_get_orders_cancel (pos->ogh);
    733   }
    734   GNUNET_free (pos->already_paid_order_id);
    735   GNUNET_free (pos);
    736 }
    737 
    738 
    739 struct TALER_TESTING_Command
    740 TALER_TESTING_cmd_wallet_poll_order_start (
    741   const char *label,
    742   const char *merchant_url,
    743   const char *order_ref,
    744   struct GNUNET_TIME_Relative timeout,
    745   const char *await_refund)
    746 {
    747   struct WalletPollOrderStartState *pos;
    748 
    749   pos = GNUNET_new (struct WalletPollOrderStartState);
    750   pos->order_ref = order_ref;
    751   pos->merchant_url = merchant_url;
    752   pos->timeout = timeout;
    753   if (NULL != await_refund)
    754   {
    755     pos->wait_for_refund = true;
    756     GNUNET_assert (GNUNET_OK ==
    757                    TALER_string_to_amount (await_refund,
    758                                            &pos->refund_threshold));
    759   }
    760   {
    761     struct TALER_TESTING_Command cmd = {
    762       .cls = pos,
    763       .label = label,
    764       .run = &wallet_poll_order_start_run,
    765       .cleanup = &wallet_poll_order_start_cleanup
    766     };
    767 
    768     return cmd;
    769   }
    770 }
    771 
    772 
    773 struct TALER_TESTING_Command
    774 TALER_TESTING_cmd_wallet_poll_order_start2 (
    775   const char *label,
    776   const char *merchant_url,
    777   const char *order_ref,
    778   struct GNUNET_TIME_Relative timeout,
    779   const char *await_refund,
    780   const char *session_id)
    781 {
    782   struct WalletPollOrderStartState *pos;
    783   struct TALER_TESTING_Command cmd;
    784 
    785   cmd = TALER_TESTING_cmd_wallet_poll_order_start (label,
    786                                                    merchant_url,
    787                                                    order_ref,
    788                                                    timeout,
    789                                                    await_refund);
    790   pos = cmd.cls;
    791   pos->session_id = session_id;
    792   return cmd;
    793 }
    794 
    795 
    796 /**
    797  * Run the "GET order conclude" CMD.
    798  *
    799  * @param cls closure.
    800  * @param cmd command being run now.
    801  * @param is interpreter state.
    802  */
    803 static void
    804 wallet_poll_order_conclude_run (void *cls,
    805                                 const struct TALER_TESTING_Command *cmd,
    806                                 struct TALER_TESTING_Interpreter *is)
    807 {
    808   struct WalletPollOrderConcludeState *poc = cls;
    809   const struct TALER_TESTING_Command *poll_cmd;
    810   struct WalletPollOrderStartState *pos;
    811 
    812   poc->is = is;
    813   poll_cmd =
    814     TALER_TESTING_interpreter_lookup_command (is,
    815                                               poc->start_reference);
    816   if (NULL == poll_cmd)
    817     TALER_TESTING_FAIL (poc->is);
    818   GNUNET_assert (poll_cmd->run == &wallet_poll_order_start_run);
    819   pos = poll_cmd->cls;
    820   pos->cs = poc;
    821   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    822               "Waiting on GET /orders/$ID of %s (%s)\n",
    823               poc->start_reference,
    824               (NULL == pos->ogh)
    825               ? "finished"
    826               : "active");
    827   if (NULL == pos->ogh)
    828     poc->task = GNUNET_SCHEDULER_add_now (&conclude_task,
    829                                           poc);
    830   else
    831     poc->task = GNUNET_SCHEDULER_add_at (pos->deadline,
    832                                          &conclude_task,
    833                                          poc);
    834 }
    835 
    836 
    837 /**
    838  * Free the state of a "GET order" CMD, and possibly
    839  * cancel a pending operation thereof.
    840  *
    841  * @param cls closure.
    842  * @param cmd command being run.
    843  */
    844 static void
    845 wallet_poll_order_conclude_cleanup (void *cls,
    846                                     const struct TALER_TESTING_Command *cmd)
    847 {
    848   struct WalletPollOrderConcludeState *poc = cls;
    849 
    850   if (NULL != poc->task)
    851   {
    852     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    853                 "Command `%s' was not terminated\n",
    854                 TALER_TESTING_interpreter_get_current_label (
    855                   poc->is));
    856     GNUNET_SCHEDULER_cancel (poc->task);
    857     poc->task = NULL;
    858   }
    859   GNUNET_free (poc);
    860 }
    861 
    862 
    863 struct TALER_TESTING_Command
    864 TALER_TESTING_cmd_wallet_poll_order_conclude (
    865   const char *label,
    866   unsigned int expected_http_status,
    867   const char *expected_refund_amount,
    868   const char *poll_start_reference)
    869 {
    870   struct WalletPollOrderConcludeState *cps;
    871 
    872   cps = GNUNET_new (struct WalletPollOrderConcludeState);
    873   cps->start_reference = poll_start_reference;
    874   cps->expected_http_status = expected_http_status;
    875   if (NULL != expected_refund_amount)
    876   {
    877     cps->expected_refund = true;
    878     GNUNET_assert (GNUNET_OK ==
    879                    TALER_string_to_amount (expected_refund_amount,
    880                                            &cps->expected_refund_amount));
    881   }
    882   {
    883     struct TALER_TESTING_Command cmd = {
    884       .cls = cps,
    885       .label = label,
    886       .run = &wallet_poll_order_conclude_run,
    887       .cleanup = &wallet_poll_order_conclude_cleanup
    888     };
    889 
    890     return cmd;
    891   }
    892 }
    893 
    894 
    895 struct TALER_TESTING_Command
    896 TALER_TESTING_cmd_wallet_poll_order_conclude2 (
    897   const char *label,
    898   unsigned int expected_http_status,
    899   const char *expected_refund_amount,
    900   const char *poll_start_reference,
    901   const char *already_paid_order_id)
    902 {
    903   struct WalletPollOrderConcludeState *cps;
    904   struct TALER_TESTING_Command cmd;
    905 
    906   cmd = TALER_TESTING_cmd_wallet_poll_order_conclude (
    907     label,
    908     expected_http_status,
    909     expected_refund_amount,
    910     poll_start_reference);
    911   cps = cmd.cls;
    912   cps->already_paid_order_id = already_paid_order_id;
    913   return cmd;
    914 }
    915 
    916 
    917 /* end of testing_api_cmd_wallet_get_order.c */