merchant

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

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 */