LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_merchant_get_order.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 68.6 % 366 251
Test Date: 2026-09-11 17:45:24 Functions: 93.8 % 16 15

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020-2024 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_merchant_get_order.c
      21              :  * @brief command to test GET /private/orders/$ORDER_ID.
      22              :  * @author Jonathan Buchanan
      23              :  */
      24              : #include "platform.h"
      25              : #include <taler/taler_exchange_service.h>
      26              : #include <taler/taler_testing_lib.h>
      27              : #include "taler/taler_merchant_testing_lib.h"
      28              : #include <taler/merchant/get-private-orders-ORDER_ID.h>
      29              : 
      30              : 
      31              : /**
      32              :  * State for a GET /private/orders/$ORDER_ID CMD.
      33              :  */
      34              : struct MerchantGetOrderState
      35              : {
      36              :   /**
      37              :    * The merchant base URL.
      38              :    */
      39              :   const char *merchant_url;
      40              : 
      41              :   /**
      42              :    * Expected HTTP response code for this CMD.
      43              :    */
      44              :   unsigned int http_status;
      45              : 
      46              :   /**
      47              :    * The handle to the current GET /private/orders/$ORDER_ID request.
      48              :    */
      49              :   struct TALER_MERCHANT_GetPrivateOrderHandle *ogh;
      50              : 
      51              :   /**
      52              :    * The interpreter state.
      53              :    */
      54              :   struct TALER_TESTING_Interpreter *is;
      55              : 
      56              :   /**
      57              :    * Reference to a command that created an order.
      58              :    */
      59              :   const char *order_reference;
      60              : 
      61              :   /**
      62              :    * Expected order status.
      63              :    */
      64              :   enum TALER_MERCHANT_OrderStatusCode osc;
      65              : 
      66              :   /**
      67              :    * A NULL-terminated list of refunds associated with this order.
      68              :    */
      69              :   const char **refunds;
      70              : 
      71              :   /**
      72              :    * The length of @e refunds.
      73              :    */
      74              :   unsigned int refunds_length;
      75              : 
      76              :   /**
      77              :    * A NULL-terminated list of transfers associated with this order.
      78              :    */
      79              :   const char **transfers;
      80              : 
      81              :   /**
      82              :    * The length of @e transfers.
      83              :    */
      84              :   unsigned int transfers_length;
      85              : 
      86              :   /**
      87              :    * A list of forget commands that apply to this order's contract terms.
      88              :    */
      89              :   const char **forgets;
      90              : 
      91              :   /**
      92              :    * The length of @e forgets.
      93              :    */
      94              :   unsigned int forgets_length;
      95              : 
      96              :   /**
      97              :    * Set to a session ID, if we should pass one as part
      98              :    * of the request.
      99              :    */
     100              :   const char *session_id;
     101              : 
     102              :   /**
     103              :    * Set if we expect to be referred to another equivalent order which was
     104              :    * already paid by the wallet under this @e session_id.
     105              :    */
     106              :   const char *repurchase_order_ref;
     107              : 
     108              :   /**
     109              :    * Expected minimum age.
     110              :    */
     111              :   unsigned int expected_min_age;
     112              : 
     113              :   /**
     114              :    * True if we should pass the 'allow_refunded_for_repurchase' flag.
     115              :    */
     116              :   bool allow_refunded_for_repurchase;
     117              : 
     118              :   /**
     119              :    * Whether the order was refunded or not.
     120              :    */
     121              :   bool refunded;
     122              : 
     123              :   /**
     124              :    * Whether the order was wired or not.
     125              :    */
     126              :   bool wired;
     127              : };
     128              : 
     129              : 
     130              : /**
     131              :  * Forget part of the contract terms.
     132              :  *
     133              :  * @param cls pointer to the result of the forget operation.
     134              :  * @param object_id name of the object to forget.
     135              :  * @param parent parent of the object at @e object_id.
     136              :  */
     137              : static void
     138            0 : apply_forget (void *cls,
     139              :               const char *object_id,
     140              :               json_t *parent)
     141              : {
     142            0 :   int *res = cls;
     143              : 
     144            0 :   if (GNUNET_SYSERR ==
     145            0 :       TALER_JSON_contract_part_forget (parent,
     146              :                                        object_id))
     147            0 :     *res = GNUNET_SYSERR;
     148            0 : }
     149              : 
     150              : 
     151              : /**
     152              :  * Callback to process a GET /orders/$ID request
     153              :  *
     154              :  * @param cls closure
     155              :  * @param osr order status response details
     156              :  */
     157              : /* FIXME_POLYMORPHISM: TALER_MERCHANT_GetPrivateOrderCallback is used in this
     158              :    compilation unit with two different closure types (struct MerchantGetOrderState here,
     159              :    struct MerchantPollOrderStartState in merchant_poll_order_cb below), so a single
     160              :    TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE override cannot type both. Left as
     161              :    void *cls; adopting the RESULT_CLOSURE pattern needs a manual refactor. */
     162              : static void
     163           35 : merchant_get_order_cb (
     164              :   void *cls,
     165              :   const struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
     166              : {
     167           35 :   struct MerchantGetOrderState *gos = cls;
     168              : 
     169           35 :   gos->ogh = NULL;
     170           35 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     171              :               "GET /private/orders/$ID completed with status %u\n",
     172              :               osr->hr.http_status);
     173           35 :   if (gos->http_status != osr->hr.http_status)
     174              :   {
     175            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     176              :                 "Unexpected response code %u (%d) to command %s\n",
     177              :                 osr->hr.http_status,
     178              :                 (int) osr->hr.ec,
     179              :                 TALER_TESTING_interpreter_get_current_label (gos->is));
     180            0 :     TALER_TESTING_interpreter_fail (gos->is);
     181            0 :     return;
     182              :   }
     183           35 :   switch (osr->hr.http_status)
     184              :   {
     185           35 :   case MHD_HTTP_OK:
     186           35 :     if (gos->osc != osr->details.ok.status)
     187              :     {
     188            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     189              :                   "Order paid does not match: %d vs %d\n",
     190              :                   gos->osc,
     191              :                   osr->details.ok.status);
     192            0 :       TALER_TESTING_interpreter_fail (gos->is);
     193            0 :       return;
     194              :     }
     195           35 :     switch (osr->details.ok.status)
     196              :     {
     197           20 :     case TALER_MERCHANT_OSC_PAID:
     198              :       {
     199              :         const struct TALER_TESTING_Command *order_cmd;
     200              :         struct TALER_Amount refunded_total;
     201              : 
     202           20 :         if ( (0 != gos->expected_min_age) &&
     203            0 :              (gos->expected_min_age !=
     204            0 :               json_integer_value (
     205            0 :                 json_object_get (
     206            0 :                   osr->details.ok.details.paid.contract_terms,
     207              :                   "minimum_age"))) )
     208              :         {
     209            0 :           GNUNET_break (0);
     210            0 :           TALER_TESTING_interpreter_fail (gos->is);
     211            0 :           return;
     212              :         }
     213           20 :         order_cmd = TALER_TESTING_interpreter_lookup_command (
     214              :           gos->is,
     215              :           gos->order_reference);
     216              : 
     217              :         {
     218              :           const json_t *expected_contract_terms;
     219              :           json_t *ct;
     220              : 
     221           20 :           if (GNUNET_OK !=
     222           20 :               TALER_TESTING_get_trait_contract_terms (order_cmd,
     223              :                                                       &expected_contract_terms))
     224              :           {
     225            0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     226              :                         "Could not fetch order contract terms\n");
     227            0 :             TALER_TESTING_interpreter_fail (gos->is);
     228            0 :             return;
     229              :           }
     230              : 
     231           20 :           ct = json_deep_copy (expected_contract_terms);
     232              : 
     233              :           /* Apply all forgets, then compare */
     234           32 :           for (unsigned int i = 0; i < gos->forgets_length; ++i)
     235              :           {
     236              :             const struct TALER_TESTING_Command *forget_cmd;
     237              :             const uint32_t *paths_length;
     238              : 
     239           12 :             forget_cmd = TALER_TESTING_interpreter_lookup_command (
     240              :               gos->is,
     241           12 :               gos->forgets[i]);
     242              : 
     243           12 :             if (GNUNET_OK !=
     244           12 :                 TALER_TESTING_get_trait_paths_length (forget_cmd,
     245              :                                                       &paths_length))
     246              :             {
     247            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     248              :                           "Couldn't fetch forget paths length\n");
     249            0 :               json_decref (ct);
     250            0 :               TALER_TESTING_interpreter_fail (gos->is);
     251            0 :               return;
     252              :             }
     253              : 
     254           24 :             for (unsigned int j = 0; j < *paths_length; ++j)
     255              :             {
     256              :               const char *path;
     257           12 :               int res = GNUNET_OK;
     258              : 
     259           12 :               if (GNUNET_OK !=
     260           12 :                   TALER_TESTING_get_trait_paths (forget_cmd,
     261              :                                                  j,
     262              :                                                  &path))
     263              :               {
     264            0 :                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     265              :                             "Couldn't fetch forget path\n");
     266            0 :                 json_decref (ct);
     267            0 :                 TALER_TESTING_interpreter_fail (gos->is);
     268            0 :                 return;
     269              :               }
     270              : 
     271           12 :               GNUNET_assert (GNUNET_OK ==
     272              :                              TALER_JSON_expand_path (ct,
     273              :                                                      path,
     274              :                                                      &apply_forget,
     275              :                                                      &res));
     276           12 :               GNUNET_assert (GNUNET_OK == res);
     277              :             }
     278              :           }
     279              : 
     280           20 :           if (1 != json_equal (ct,
     281           20 :                                osr->details.ok.details.paid.contract_terms))
     282              :           {
     283            0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     284              :                         "Order contract terms do not match\n");
     285            0 :             json_decref (ct);
     286            0 :             TALER_TESTING_interpreter_fail (gos->is);
     287            0 :             return;
     288              :           }
     289              : 
     290           20 :           json_decref (ct);
     291              :         }
     292           20 :         if (gos->wired != osr->details.ok.details.paid.wired)
     293              :         {
     294            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     295              :                       "Order wired does not match\n");
     296            0 :           TALER_TESTING_interpreter_fail (gos->is);
     297            0 :           return;
     298              :         }
     299           20 :         if (gos->transfers_length != osr->details.ok.details.paid.wts_len)
     300              :         {
     301            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     302              :                       "Number of transfers found does not match\n");
     303            0 :           TALER_TESTING_interpreter_fail (gos->is);
     304            0 :           return;
     305              :         }
     306           29 :         for (unsigned int i = 0; i < gos->transfers_length; ++i)
     307              :         {
     308              :           const struct TALER_TESTING_Command *transfer_cmd;
     309              : 
     310            9 :           transfer_cmd = TALER_TESTING_interpreter_lookup_command (
     311              :             gos->is,
     312            9 :             gos->transfers[i]);
     313              :           {
     314              :             const struct TALER_WireTransferIdentifierRawP *wtid;
     315              : 
     316            9 :             if (GNUNET_OK !=
     317            9 :                 TALER_TESTING_get_trait_wtid (transfer_cmd,
     318              :                                               &wtid))
     319              :             {
     320            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     321              :                           "Could not fetch wire transfer id\n");
     322            0 :               TALER_TESTING_interpreter_fail (gos->is);
     323            0 :               return;
     324              :             }
     325            9 :             if (0 != GNUNET_memcmp (wtid,
     326              :                                     &osr->details.ok.details.paid.wts[i].
     327              :                                     wtid))
     328              :             {
     329            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     330              :                           "Wire transfer id does not match\n");
     331            0 :               TALER_TESTING_interpreter_fail (gos->is);
     332            0 :               return;
     333              :             }
     334              :           }
     335              :           {
     336              :             const char *exchange_url;
     337              : 
     338            9 :             if (GNUNET_OK !=
     339            9 :                 TALER_TESTING_get_trait_exchange_url (transfer_cmd,
     340              :                                                       &exchange_url))
     341              :             {
     342            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     343              :                           "Could not fetch wire transfer exchange url\n");
     344            0 :               TALER_TESTING_interpreter_fail (gos->is);
     345            0 :               return;
     346              :             }
     347            9 :             if (0 != strcmp (
     348              :                   exchange_url,
     349            9 :                   osr->details.ok.details.paid.wts[i].exchange_url))
     350              :             {
     351            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     352              :                           "Wire transfer exchange url does not match\n");
     353            0 :               TALER_TESTING_interpreter_fail (gos->is);
     354            0 :               return;
     355              :             }
     356              :           }
     357              :         }
     358           20 :         if (gos->refunded != osr->details.ok.details.paid.refunded)
     359              :         {
     360            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     361              :                       "Order refunded does not match\n");
     362            0 :           TALER_TESTING_interpreter_fail (gos->is);
     363            0 :           return;
     364              :         }
     365           20 :         if (gos->refunds_length !=
     366           20 :             osr->details.ok.details.paid.refunds_len)
     367              :         {
     368            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     369              :                       "Number of refunds found does not match\n");
     370            0 :           TALER_TESTING_interpreter_fail (gos->is);
     371            0 :           return;
     372              :         }
     373           20 :         if (0 < gos->refunds_length)
     374            4 :           GNUNET_assert (
     375              :             GNUNET_OK ==
     376              :             TALER_amount_set_zero (
     377              :               osr->details.ok.details.paid.refund_amount.currency,
     378              :               &refunded_total));
     379           28 :         for (unsigned int i = 0; i < gos->refunds_length; ++i)
     380              :         {
     381              :           const struct TALER_TESTING_Command *refund_cmd;
     382              : 
     383            8 :           refund_cmd = TALER_TESTING_interpreter_lookup_command (
     384              :             gos->is,
     385            8 :             gos->refunds[i]);
     386              :           {
     387              :             const struct TALER_Amount *expected_amount;
     388            8 :             struct TALER_Amount *amount_found =
     389            8 :               &osr->details.ok.details.paid.refunds[i].refund_amount;
     390              : 
     391            8 :             if (GNUNET_OK !=
     392            8 :                 TALER_TESTING_get_trait_amount (refund_cmd,
     393              :                                                 &expected_amount))
     394              :             {
     395            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     396              :                           "Could not fetch refund amount\n");
     397            0 :               TALER_TESTING_interpreter_fail (gos->is);
     398            0 :               return;
     399              :             }
     400            8 :             GNUNET_assert (0 <= TALER_amount_add (&refunded_total,
     401              :                                                   &refunded_total,
     402              :                                                   amount_found));
     403            8 :             if ((GNUNET_OK !=
     404            8 :                  TALER_amount_cmp_currency (expected_amount,
     405            8 :                                             &refunded_total)) ||
     406            8 :                 (0 != TALER_amount_cmp (expected_amount,
     407              :                                         &refunded_total)))
     408              :             {
     409            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     410              :                           "Refund amounts do not match\n");
     411            0 :               TALER_TESTING_interpreter_fail (gos->is);
     412            0 :               return;
     413              :             }
     414              :           }
     415              :           {
     416              :             const char *expected_reason;
     417              : 
     418            8 :             if (GNUNET_OK !=
     419            8 :                 TALER_TESTING_get_trait_reason (refund_cmd,
     420              :                                                 &expected_reason))
     421              :             {
     422            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     423              :                           "Could not fetch reason\n");
     424            0 :               TALER_TESTING_interpreter_fail (gos->is);
     425            0 :               return;
     426              :             }
     427            8 :             if (0 !=
     428            8 :                 strcmp (
     429              :                   expected_reason,
     430            8 :                   osr->details.ok.details.paid.refunds[i].reason))
     431              :             {
     432            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     433              :                           "Refund reason does not match\n");
     434            0 :               TALER_TESTING_interpreter_fail (gos->is);
     435            0 :               return;
     436              :             }
     437              :           }
     438              :         }
     439              : 
     440           20 :         if (gos->wired != osr->details.ok.details.paid.wired)
     441              :         {
     442            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     443              :                       "Order wired does not match\n");
     444            0 :           TALER_TESTING_interpreter_fail (gos->is);
     445            0 :           return;
     446              :         }
     447              :       }
     448           20 :       break;
     449            9 :     case TALER_MERCHANT_OSC_CLAIMED:
     450              :       /* FIXME: Check contract terms... */
     451           11 :       if ( (0 != gos->expected_min_age) &&
     452            2 :            (gos->expected_min_age !=
     453            2 :             json_integer_value (
     454            2 :               json_object_get (
     455            2 :                 osr->details.ok.details.claimed.contract_terms,
     456              :                 "minimum_age"))) )
     457              :       {
     458            0 :         GNUNET_break (0);
     459            0 :         TALER_TESTING_interpreter_fail (gos->is);
     460            0 :         return;
     461              :       }
     462            9 :       break;
     463            6 :     case TALER_MERCHANT_OSC_UNPAID:
     464              :       {
     465              :         struct TALER_MERCHANT_PayUriData pud;
     466              :         const struct TALER_TESTING_Command *order_cmd;
     467              :         const char *order_id;
     468              :         const struct TALER_ClaimTokenP *claim_token;
     469              : 
     470            6 :         if (NULL != gos->repurchase_order_ref)
     471              :         {
     472              :           const struct TALER_TESTING_Command *rep_cmd;
     473              :           const char *rep_id;
     474              :           const char *ri;
     475              : 
     476            2 :           rep_cmd = TALER_TESTING_interpreter_lookup_command (
     477              :             gos->is,
     478              :             gos->repurchase_order_ref);
     479            2 :           if (GNUNET_OK !=
     480            2 :               TALER_TESTING_get_trait_order_id (rep_cmd,
     481              :                                                 &rep_id))
     482              :           {
     483            0 :             TALER_TESTING_FAIL (gos->is);
     484              :           }
     485            2 :           ri = osr->details.ok.details.unpaid.already_paid_order_id;
     486            2 :           if ( (NULL == ri) ||
     487              :                (0 !=
     488            2 :                 strcmp (ri,
     489              :                         rep_id)) )
     490              :           {
     491            0 :             TALER_TESTING_FAIL (gos->is);
     492              :           }
     493              :         }
     494              : 
     495            6 :         if (GNUNET_OK !=
     496            6 :             TALER_MERCHANT_parse_pay_uri (
     497            6 :               osr->details.ok.details.unpaid.taler_pay_uri,
     498              :               &pud))
     499              :         {
     500            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     501              :                       "Taler pay uri `%s' is malformed\n",
     502              :                       osr->details.ok.details.unpaid.taler_pay_uri);
     503            0 :           TALER_TESTING_interpreter_fail (gos->is);
     504            0 :           return;
     505              :         }
     506              : 
     507            6 :         order_cmd = TALER_TESTING_interpreter_lookup_command (
     508              :           gos->is,
     509              :           gos->order_reference);
     510              : 
     511            6 :         if (GNUNET_OK !=
     512            6 :             TALER_TESTING_get_trait_order_id (order_cmd,
     513              :                                               &order_id))
     514              :         {
     515            0 :           TALER_MERCHANT_parse_pay_uri_free (&pud);
     516            0 :           TALER_TESTING_FAIL (gos->is);
     517              :         }
     518              : 
     519            6 :         if (GNUNET_OK !=
     520            6 :             TALER_TESTING_get_trait_claim_token (order_cmd,
     521              :                                                  &claim_token))
     522              :         {
     523            0 :           TALER_MERCHANT_parse_pay_uri_free (&pud);
     524            0 :           TALER_TESTING_FAIL (gos->is);
     525              :         }
     526              :         {
     527              :           char *host;
     528              : 
     529            6 :           host = TALER_MERCHANT_TESTING_extract_host (gos->merchant_url);
     530            6 :           if ((0 != strcmp (host,
     531            6 :                             pud.merchant_host)) ||
     532            6 :               (NULL != pud.merchant_prefix_path) ||
     533            6 :               (0 != strcmp (order_id,
     534            6 :                             pud.order_id)) ||
     535            6 :               (NULL != pud.ssid))
     536              :           {
     537            0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     538              :                         "Order pay uri `%s' does not match, wanted %s/%s\n",
     539              :                         osr->details.ok.details.unpaid.taler_pay_uri,
     540              :                         host,
     541              :                         order_id);
     542            0 :             TALER_TESTING_interpreter_fail (gos->is);
     543            0 :             TALER_MERCHANT_parse_pay_uri_free (&pud);
     544            0 :             GNUNET_free (host);
     545            0 :             return;
     546              :           }
     547            6 :           GNUNET_free (host);
     548              :         }
     549              :         /* The claim token is not given in the pay uri if the order
     550              :            has been claimed already. */
     551            6 :         if ( (NULL != pud.claim_token) &&
     552            6 :              ( (NULL == claim_token) ||
     553            6 :                (0 != GNUNET_memcmp (claim_token,
     554              :                                     pud.claim_token)) ) )
     555              :         {
     556            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     557              :                       "Order pay uri claim token does not match (%d/%d/%d/%d)\n",
     558              :                       NULL == pud.claim_token,
     559              :                       NULL == claim_token,
     560              :                       (NULL != pud.claim_token) &&
     561              :                       GNUNET_is_zero (pud.claim_token),
     562              :                       (NULL != claim_token) &&
     563              :                       GNUNET_is_zero (claim_token));
     564            0 :           TALER_TESTING_interpreter_fail (gos->is);
     565            0 :           TALER_MERCHANT_parse_pay_uri_free (&pud);
     566            0 :           return;
     567              :         }
     568            6 :         TALER_MERCHANT_parse_pay_uri_free (&pud);
     569            6 :         break;
     570              :       }
     571              :     }
     572           35 :     break;
     573            0 :   default:
     574            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     575              :                 "Unhandled HTTP status.\n");
     576              :   }
     577           35 :   TALER_TESTING_interpreter_next (gos->is);
     578              : }
     579              : 
     580              : 
     581              : /**
     582              :  * Run the "GET order" CMD.
     583              :  *
     584              :  * @param cls closure.
     585              :  * @param cmd command being run now.
     586              :  * @param is interpreter state.
     587              :  */
     588              : static void
     589           35 : merchant_get_order_run (void *cls,
     590              :                         const struct TALER_TESTING_Command *cmd,
     591              :                         struct TALER_TESTING_Interpreter *is)
     592              : {
     593           35 :   struct MerchantGetOrderState *gos = cls;
     594              :   const struct TALER_TESTING_Command *order_cmd;
     595              :   const char *order_id;
     596              :   const struct TALER_PrivateContractHashP *h_contract;
     597              : 
     598           35 :   order_cmd = TALER_TESTING_interpreter_lookup_command (
     599              :     is,
     600              :     gos->order_reference);
     601              : 
     602           35 :   if (GNUNET_OK !=
     603           35 :       TALER_TESTING_get_trait_order_id (order_cmd,
     604              :                                         &order_id))
     605            0 :     TALER_TESTING_FAIL (is);
     606              : 
     607           35 :   if (GNUNET_OK !=
     608           35 :       TALER_TESTING_get_trait_h_contract_terms (order_cmd,
     609              :                                                 &h_contract))
     610            0 :     TALER_TESTING_FAIL (is);
     611              : 
     612           35 :   gos->is = is;
     613           35 :   gos->ogh = TALER_MERCHANT_get_private_order_create (
     614              :     TALER_TESTING_interpreter_get_context (is),
     615              :     gos->merchant_url,
     616              :     order_id);
     617           35 :   GNUNET_assert (NULL != gos->ogh);
     618           35 :   if (NULL != gos->session_id)
     619              :   {
     620           10 :     TALER_MERCHANT_get_private_order_set_options (
     621              :       gos->ogh,
     622              :       TALER_MERCHANT_get_private_order_option_session_id (
     623              :         gos->session_id));
     624              :   }
     625              :   {
     626              :     enum TALER_ErrorCode ec;
     627              : 
     628           35 :     ec = TALER_MERCHANT_get_private_order_start (
     629              :       gos->ogh,
     630              :       &merchant_get_order_cb,
     631              :       gos);
     632           35 :     GNUNET_assert (TALER_EC_NONE == ec);
     633              :   }
     634              : }
     635              : 
     636              : 
     637              : /**
     638              :  * Free the state of a "GET order" CMD, and possibly
     639              :  * cancel a pending operation thereof.
     640              :  *
     641              :  * @param cls closure.
     642              :  * @param cmd command being run.
     643              :  */
     644              : static void
     645           35 : merchant_get_order_cleanup (void *cls,
     646              :                             const struct TALER_TESTING_Command *cmd)
     647              : {
     648           35 :   struct MerchantGetOrderState *gos = cls;
     649              : 
     650           35 :   if (NULL != gos->ogh)
     651              :   {
     652            0 :     TALER_LOG_WARNING ("Get order operation did not complete\n");
     653            0 :     TALER_MERCHANT_get_private_order_cancel (gos->ogh);
     654              :   }
     655           35 :   GNUNET_array_grow (gos->transfers,
     656              :                      gos->transfers_length,
     657              :                      0);
     658           35 :   GNUNET_array_grow (gos->refunds,
     659              :                      gos->refunds_length,
     660              :                      0);
     661           35 :   GNUNET_array_grow (gos->forgets,
     662              :                      gos->forgets_length,
     663              :                      0);
     664           35 :   GNUNET_free (gos);
     665           35 : }
     666              : 
     667              : 
     668              : struct TALER_TESTING_Command
     669           12 : TALER_TESTING_cmd_merchant_get_order (
     670              :   const char *label,
     671              :   const char *merchant_url,
     672              :   const char *order_reference,
     673              :   enum TALER_MERCHANT_OrderStatusCode osc,
     674              :   bool refunded,
     675              :   unsigned int http_status,
     676              :   ...)
     677              : {
     678              :   struct MerchantGetOrderState *gos;
     679              : 
     680           12 :   gos = GNUNET_new (struct MerchantGetOrderState);
     681           12 :   gos->merchant_url = merchant_url;
     682           12 :   gos->order_reference = order_reference;
     683           12 :   gos->osc = osc;
     684           12 :   gos->refunded = refunded;
     685           12 :   gos->http_status = http_status;
     686           12 :   if (refunded)
     687              :   {
     688              :     const char *clabel;
     689              :     va_list ap;
     690              : 
     691            2 :     va_start (ap, http_status);
     692            6 :     while (NULL != (clabel = va_arg (ap, const char *)))
     693              :     {
     694            4 :       GNUNET_array_append (gos->refunds,
     695              :                            gos->refunds_length,
     696              :                            clabel);
     697              :     }
     698            2 :     va_end (ap);
     699              :   }
     700              :   {
     701           12 :     struct TALER_TESTING_Command cmd = {
     702              :       .cls = gos,
     703              :       .label = label,
     704              :       .run = &merchant_get_order_run,
     705              :       .cleanup = &merchant_get_order_cleanup
     706              :     };
     707              : 
     708           12 :     return cmd;
     709              :   }
     710              : }
     711              : 
     712              : 
     713              : struct TALER_TESTING_Command
     714           11 : TALER_TESTING_cmd_merchant_get_order2 (
     715              :   const char *label,
     716              :   const char *merchant_url,
     717              :   const char *order_reference,
     718              :   enum TALER_MERCHANT_OrderStatusCode osc,
     719              :   bool wired,
     720              :   const char **transfers,
     721              :   bool refunded,
     722              :   const char **refunds,
     723              :   const char **forgets,
     724              :   unsigned int http_status)
     725              : {
     726              :   struct MerchantGetOrderState *gos;
     727              : 
     728           11 :   gos = GNUNET_new (struct MerchantGetOrderState);
     729           11 :   gos->merchant_url = merchant_url;
     730           11 :   gos->order_reference = order_reference;
     731           11 :   gos->osc = osc;
     732           11 :   gos->wired = wired;
     733           11 :   gos->refunded = refunded;
     734           11 :   gos->http_status = http_status;
     735           11 :   if (wired)
     736              :   {
     737           18 :     for (const char **clabel = transfers; *clabel != NULL; ++clabel)
     738              :     {
     739            9 :       GNUNET_array_append (gos->transfers,
     740              :                            gos->transfers_length,
     741              :                            *clabel);
     742              :     }
     743              :   }
     744           11 :   if (refunded)
     745              :   {
     746            6 :     for (const char **clabel = refunds; *clabel != NULL; ++clabel)
     747              :     {
     748            4 :       GNUNET_array_append (gos->refunds,
     749              :                            gos->refunds_length,
     750              :                            *clabel);
     751              :     }
     752              :   }
     753           11 :   if (NULL != forgets)
     754              :   {
     755           18 :     for (const char **clabel = forgets; *clabel != NULL; ++clabel)
     756              :     {
     757           12 :       GNUNET_array_append (gos->forgets,
     758              :                            gos->forgets_length,
     759              :                            *clabel);
     760              :     }
     761              :   }
     762              :   {
     763           11 :     struct TALER_TESTING_Command cmd = {
     764              :       .cls = gos,
     765              :       .label = label,
     766              :       .run = &merchant_get_order_run,
     767              :       .cleanup = &merchant_get_order_cleanup
     768              :     };
     769              : 
     770           11 :     return cmd;
     771              :   }
     772              : }
     773              : 
     774              : 
     775              : struct TALER_TESTING_Command
     776           10 : TALER_TESTING_cmd_merchant_get_order3 (
     777              :   const char *label,
     778              :   const char *merchant_url,
     779              :   const char *order_reference,
     780              :   enum TALER_MERCHANT_OrderStatusCode osc,
     781              :   const char *session_id,
     782              :   const char *repurchase_order_ref,
     783              :   unsigned int expected_http_status)
     784              : {
     785              :   struct MerchantGetOrderState *gos;
     786              : 
     787           10 :   gos = GNUNET_new (struct MerchantGetOrderState);
     788           10 :   gos->merchant_url = merchant_url;
     789           10 :   gos->order_reference = order_reference;
     790           10 :   gos->osc = osc;
     791           10 :   gos->session_id = session_id;
     792           10 :   gos->repurchase_order_ref = repurchase_order_ref;
     793           10 :   gos->http_status = expected_http_status;
     794              :   {
     795           10 :     struct TALER_TESTING_Command cmd = {
     796              :       .cls = gos,
     797              :       .label = label,
     798              :       .run = &merchant_get_order_run,
     799              :       .cleanup = &merchant_get_order_cleanup
     800              :     };
     801              : 
     802           10 :     return cmd;
     803              :   }
     804              : }
     805              : 
     806              : 
     807              : struct TALER_TESTING_Command
     808            2 : TALER_TESTING_cmd_merchant_get_order4 (
     809              :   const char *label,
     810              :   const char *merchant_url,
     811              :   const char *order_reference,
     812              :   enum TALER_MERCHANT_OrderStatusCode osc,
     813              :   uint32_t expected_min_age,
     814              :   unsigned int expected_http_status)
     815              : {
     816              :   struct MerchantGetOrderState *gos;
     817              : 
     818            2 :   gos = GNUNET_new (struct MerchantGetOrderState);
     819            2 :   gos->merchant_url = merchant_url;
     820            2 :   gos->order_reference = order_reference;
     821            2 :   gos->osc = osc;
     822            2 :   gos->expected_min_age = expected_min_age;
     823            2 :   gos->http_status = expected_http_status;
     824              :   {
     825            2 :     struct TALER_TESTING_Command cmd = {
     826              :       .cls = gos,
     827              :       .label = label,
     828              :       .run = &merchant_get_order_run,
     829              :       .cleanup = &merchant_get_order_cleanup
     830              :     };
     831              : 
     832            2 :     return cmd;
     833              :   }
     834              : }
     835              : 
     836              : 
     837              : struct MerchantPollOrderConcludeState
     838              : {
     839              :   /**
     840              :    * The interpreter state.
     841              :    */
     842              :   struct TALER_TESTING_Interpreter *is;
     843              : 
     844              :   /**
     845              :    * Reference to a command that can provide a poll order start command.
     846              :    */
     847              :   const char *start_reference;
     848              : 
     849              :   /**
     850              :    * Task to wait for the deadline.
     851              :    */
     852              :   struct GNUNET_SCHEDULER_Task *task;
     853              : 
     854              :   /**
     855              :    * Expected HTTP response status code.
     856              :    */
     857              :   unsigned int expected_http_status;
     858              : };
     859              : 
     860              : 
     861              : struct MerchantPollOrderStartState
     862              : {
     863              :   /**
     864              :    * The merchant base URL.
     865              :    */
     866              :   const char *merchant_url;
     867              : 
     868              :   /**
     869              :    * The handle to the current GET /private/orders/$ORDER_ID request.
     870              :    */
     871              :   struct TALER_MERCHANT_GetPrivateOrderHandle *ogh;
     872              : 
     873              :   /**
     874              :    * The interpreter state.
     875              :    */
     876              :   struct TALER_TESTING_Interpreter *is;
     877              : 
     878              :   /**
     879              :    * Reference to a command that created an order.
     880              :    */
     881              :   const char *order_id;
     882              : 
     883              :   /**
     884              :    * How long to wait for server to return a response.
     885              :    */
     886              :   struct GNUNET_TIME_Relative timeout;
     887              : 
     888              :   /**
     889              :    * Conclude state waiting for completion (if any).
     890              :    */
     891              :   struct MerchantPollOrderConcludeState *cs;
     892              : 
     893              :   /**
     894              :    * The HTTP status code returned by the backend.
     895              :    */
     896              :   unsigned int http_status;
     897              : 
     898              :   /**
     899              :    * When the request should be completed by.
     900              :    */
     901              :   struct GNUNET_TIME_Absolute deadline;
     902              : };
     903              : 
     904              : 
     905              : /**
     906              :  * Task called when either the timeout for the GET /private/order/$ID command
     907              :  * expired or we got a response.  Checks if the result is what we expected.
     908              :  *
     909              :  * @param cls a `struct MerchantPollOrderConcludeState`
     910              :  */
     911              : static void
     912            4 : conclude_task (void *cls)
     913              : {
     914            4 :   struct MerchantPollOrderConcludeState *ppc = cls;
     915              :   const struct TALER_TESTING_Command *poll_cmd;
     916              :   struct MerchantPollOrderStartState *cps;
     917              :   struct GNUNET_TIME_Absolute now;
     918              : 
     919            4 :   ppc->task = NULL;
     920              :   poll_cmd =
     921            4 :     TALER_TESTING_interpreter_lookup_command (ppc->is,
     922              :                                               ppc->start_reference);
     923            4 :   if (NULL == poll_cmd)
     924            0 :     TALER_TESTING_FAIL (ppc->is);
     925            4 :   cps = poll_cmd->cls;
     926            4 :   if (NULL != cps->ogh)
     927              :   {
     928            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     929              :                 "Expected poll GET /private/orders/$ORDER_ID to have completed, but it did not!\n");
     930            0 :     TALER_TESTING_FAIL (ppc->is);
     931              :   }
     932            4 :   if (cps->http_status != ppc->expected_http_status)
     933              :   {
     934            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     935              :                 "Expected HTTP status %u, got %u\n",
     936              :                 ppc->expected_http_status,
     937              :                 cps->http_status);
     938            0 :     TALER_TESTING_FAIL (ppc->is);
     939              :   }
     940            4 :   now = GNUNET_TIME_absolute_get ();
     941            4 :   if ((GNUNET_TIME_absolute_add (cps->deadline,
     942            4 :                                  GNUNET_TIME_UNIT_SECONDS).abs_value_us <
     943            4 :        now.abs_value_us) )
     944              :   {
     945            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     946              :                 "Expected answer to be delayed until %llu, but got response at %llu\n",
     947              :                 (unsigned long long) cps->deadline.abs_value_us,
     948              :                 (unsigned long long) now.abs_value_us);
     949            0 :     TALER_TESTING_FAIL (ppc->is);
     950              :   }
     951            4 :   TALER_TESTING_interpreter_next (ppc->is);
     952              : }
     953              : 
     954              : 
     955              : /**
     956              :  * Callback to process a GET /private/orders/$ID request
     957              :  *
     958              :  * @param cls closure
     959              :  * @param osr order status response details
     960              :  */
     961              : /* FIXME_POLYMORPHISM: see merchant_get_order_cb above — same GetPrivateOrderCallback
     962              :    typedef is reused here with a different closure type, so this compilation unit cannot
     963              :    adopt a single TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE override. Left as
     964              :    void *cls. */
     965              : static void
     966            4 : merchant_poll_order_cb (
     967              :   void *cls,
     968              :   const struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
     969              : {
     970            4 :   struct MerchantPollOrderStartState *pos = cls;
     971            4 :   const struct TALER_MERCHANT_HttpResponse *hr = &osr->hr;
     972              : 
     973            4 :   pos->ogh = NULL;
     974            4 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     975              :               "GET /private/orders/$ID finished with status %u.\n",
     976              :               hr->http_status);
     977            4 :   pos->http_status = hr->http_status;
     978            4 :   switch (hr->http_status)
     979              :   {
     980            4 :   case MHD_HTTP_OK:
     981              :     // FIXME: keep data from 'osr' here for checking?
     982            4 :     break;
     983            0 :   default:
     984            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     985              :                 "Unhandled HTTP status.\n");
     986              :   }
     987            4 :   if (NULL != pos->cs)
     988              :   {
     989            2 :     GNUNET_SCHEDULER_cancel (pos->cs->task);
     990            2 :     pos->cs->task = GNUNET_SCHEDULER_add_now (&conclude_task,
     991            2 :                                               pos->cs);
     992              :   }
     993            4 : }
     994              : 
     995              : 
     996              : /**
     997              :  * Run the "GET order" CMD.
     998              :  *
     999              :  * @param cls closure.
    1000              :  * @param cmd command being run now.
    1001              :  * @param is interpreter state.
    1002              :  */
    1003              : static void
    1004            4 : merchant_poll_order_start_run (void *cls,
    1005              :                                const struct TALER_TESTING_Command *cmd,
    1006              :                                struct TALER_TESTING_Interpreter *is)
    1007              : {
    1008            4 :   struct MerchantPollOrderStartState *pos = cls;
    1009              : 
    1010              :   /* add 1s grace time to timeout */
    1011              :   pos->deadline
    1012            4 :     = GNUNET_TIME_absolute_add (GNUNET_TIME_relative_to_absolute (pos->timeout),
    1013              :                                 GNUNET_TIME_UNIT_SECONDS);
    1014            4 :   pos->is = is;
    1015            4 :   pos->ogh = TALER_MERCHANT_get_private_order_create (
    1016              :     TALER_TESTING_interpreter_get_context (is),
    1017              :     pos->merchant_url,
    1018              :     pos->order_id);
    1019            4 :   GNUNET_assert (NULL != pos->ogh);
    1020            4 :   if (pos->timeout.rel_value_us > 0)
    1021              :   {
    1022            4 :     TALER_MERCHANT_get_private_order_set_options (
    1023              :       pos->ogh,
    1024              :       TALER_MERCHANT_get_private_order_option_timeout (
    1025              :         pos->timeout));
    1026              :   }
    1027              :   {
    1028              :     enum TALER_ErrorCode ec;
    1029              : 
    1030            4 :     ec = TALER_MERCHANT_get_private_order_start (
    1031              :       pos->ogh,
    1032              :       &merchant_poll_order_cb,
    1033              :       pos);
    1034            4 :     GNUNET_assert (TALER_EC_NONE == ec);
    1035              :   }
    1036              :   /* We CONTINUE to run the interpreter while the long-polled command
    1037              :      completes asynchronously! */
    1038            4 :   TALER_TESTING_interpreter_next (pos->is);
    1039            4 : }
    1040              : 
    1041              : 
    1042              : /**
    1043              :  * Free the state of a "GET order" CMD, and possibly
    1044              :  * cancel a pending operation thereof.
    1045              :  *
    1046              :  * @param cls closure.
    1047              :  * @param cmd command being run.
    1048              :  */
    1049              : static void
    1050            4 : merchant_poll_order_start_cleanup (void *cls,
    1051              :                                    const struct TALER_TESTING_Command *cmd)
    1052              : {
    1053            4 :   struct MerchantPollOrderStartState *pos = cls;
    1054              : 
    1055            4 :   if (NULL != pos->ogh)
    1056              :   {
    1057            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1058              :                 "Command `%s' was not terminated\n",
    1059              :                 TALER_TESTING_interpreter_get_current_label (
    1060              :                   pos->is));
    1061            0 :     TALER_MERCHANT_get_private_order_cancel (pos->ogh);
    1062              :   }
    1063            4 :   GNUNET_free (pos);
    1064            4 : }
    1065              : 
    1066              : 
    1067              : struct TALER_TESTING_Command
    1068            4 : TALER_TESTING_cmd_poll_order_start (
    1069              :   const char *label,
    1070              :   const char *merchant_url,
    1071              :   const char *order_id,
    1072              :   struct GNUNET_TIME_Relative timeout)
    1073              : {
    1074              :   struct MerchantPollOrderStartState *pos;
    1075              : 
    1076            4 :   pos = GNUNET_new (struct MerchantPollOrderStartState);
    1077            4 :   pos->order_id = order_id;
    1078            4 :   pos->merchant_url = merchant_url;
    1079            4 :   pos->timeout = timeout;
    1080              :   {
    1081            4 :     struct TALER_TESTING_Command cmd = {
    1082              :       .cls = pos,
    1083              :       .label = label,
    1084              :       .run = &merchant_poll_order_start_run,
    1085              :       .cleanup = &merchant_poll_order_start_cleanup
    1086              :     };
    1087              : 
    1088            4 :     return cmd;
    1089              :   }
    1090              : }
    1091              : 
    1092              : 
    1093              : /**
    1094              :  * Run the "GET order conclude" CMD.
    1095              :  *
    1096              :  * @param cls closure.
    1097              :  * @param cmd command being run now.
    1098              :  * @param is interpreter state.
    1099              :  */
    1100              : static void
    1101            4 : merchant_poll_order_conclude_run (void *cls,
    1102              :                                   const struct TALER_TESTING_Command *cmd,
    1103              :                                   struct TALER_TESTING_Interpreter *is)
    1104              : {
    1105            4 :   struct MerchantPollOrderConcludeState *poc = cls;
    1106              :   const struct TALER_TESTING_Command *poll_cmd;
    1107              :   struct MerchantPollOrderStartState *pos;
    1108              : 
    1109            4 :   poc->is = is;
    1110              :   poll_cmd =
    1111            4 :     TALER_TESTING_interpreter_lookup_command (is,
    1112              :                                               poc->start_reference);
    1113            4 :   if (NULL == poll_cmd)
    1114            0 :     TALER_TESTING_FAIL (poc->is);
    1115            4 :   GNUNET_assert (poll_cmd->run == &merchant_poll_order_start_run);
    1116            4 :   pos = poll_cmd->cls;
    1117            4 :   pos->cs = poc;
    1118            4 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1119              :               "Waiting on GET /private/orders/$ID of %s (%s)\n",
    1120              :               poc->start_reference,
    1121              :               (NULL == pos->ogh)
    1122              :               ? "finished"
    1123              :               : "active");
    1124            4 :   if (NULL == pos->ogh)
    1125            2 :     poc->task = GNUNET_SCHEDULER_add_now (&conclude_task,
    1126              :                                           poc);
    1127              :   else
    1128            2 :     poc->task = GNUNET_SCHEDULER_add_at (pos->deadline,
    1129              :                                          &conclude_task,
    1130              :                                          poc);
    1131              : }
    1132              : 
    1133              : 
    1134              : /**
    1135              :  * Free the state of a "GET order" CMD, and possibly
    1136              :  * cancel a pending operation thereof.
    1137              :  *
    1138              :  * @param cls closure.
    1139              :  * @param cmd command being run.
    1140              :  */
    1141              : static void
    1142            4 : merchant_poll_order_conclude_cleanup (void *cls,
    1143              :                                       const struct TALER_TESTING_Command *cmd)
    1144              : {
    1145            4 :   struct MerchantPollOrderConcludeState *poc = cls;
    1146              : 
    1147            4 :   if (NULL != poc->task)
    1148              :   {
    1149            0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    1150              :                 "Command `%s' was not terminated\n",
    1151              :                 TALER_TESTING_interpreter_get_current_label (
    1152              :                   poc->is));
    1153            0 :     GNUNET_SCHEDULER_cancel (poc->task);
    1154            0 :     poc->task = NULL;
    1155              :   }
    1156            4 :   GNUNET_free (poc);
    1157            4 : }
    1158              : 
    1159              : 
    1160              : struct TALER_TESTING_Command
    1161            4 : TALER_TESTING_cmd_poll_order_conclude (const char *label,
    1162              :                                        unsigned int http_status,
    1163              :                                        const char *poll_start_reference)
    1164              : {
    1165              :   struct MerchantPollOrderConcludeState *cps;
    1166              : 
    1167            4 :   cps = GNUNET_new (struct MerchantPollOrderConcludeState);
    1168            4 :   cps->start_reference = poll_start_reference;
    1169            4 :   cps->expected_http_status = http_status;
    1170              :   {
    1171            4 :     struct TALER_TESTING_Command cmd = {
    1172              :       .cls = cps,
    1173              :       .label = label,
    1174              :       .run = &merchant_poll_order_conclude_run,
    1175              :       .cleanup = &merchant_poll_order_conclude_cleanup
    1176              :     };
    1177              : 
    1178            4 :     return cmd;
    1179              :   }
    1180              : }
    1181              : 
    1182              : 
    1183              : /* end of testing_api_cmd_merchant_get_order.c */
        

Generated by: LCOV version 2.0-1