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

Generated by: LCOV version 2.0-1