LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_merchant_get_order.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 243 355 68.5 %
Date: 2025-06-23 16:22:09 Functions: 15 16 93.8 %

          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          30 : merchant_get_order_cb (
     159             :   void *cls,
     160             :   const struct TALER_MERCHANT_OrderStatusResponse *osr)
     161             : {
     162          30 :   struct MerchantGetOrderState *gos = cls;
     163             : 
     164          30 :   gos->ogh = NULL;
     165          30 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     166             :               "GET /private/orders/$ID completed with status %u\n",
     167             :               osr->hr.http_status);
     168          30 :   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          30 :   switch (osr->hr.http_status)
     179             :   {
     180          30 :   case MHD_HTTP_OK:
     181          30 :     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          30 :     switch (osr->details.ok.status)
     191             :     {
     192          16 :     case TALER_MERCHANT_OSC_PAID:
     193             :       {
     194             :         const struct TALER_TESTING_Command *order_cmd;
     195             :         struct TALER_Amount refunded_total;
     196             : 
     197          16 :         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          16 :         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          16 :           if (GNUNET_OK !=
     217          16 :               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          16 :           ct = json_deep_copy (expected_contract_terms);
     227             : 
     228             :           /* Apply all forgets, then compare */
     229          28 :           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          16 :           if (1 != json_equal (ct,
     274          16 :                                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          16 :           json_decref (ct);
     283             :         }
     284          16 :         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          16 :         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          24 :         for (unsigned int i = 0; i < gos->transfers_length; ++i)
     299             :         {
     300             :           const struct TALER_TESTING_Command *transfer_cmd;
     301             : 
     302           8 :           transfer_cmd = TALER_TESTING_interpreter_lookup_command (
     303             :             gos->is,
     304           8 :             gos->transfers[i]);
     305             :           {
     306             :             const struct TALER_WireTransferIdentifierRawP *wtid;
     307             : 
     308           8 :             if (GNUNET_OK !=
     309           8 :                 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           8 :             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           8 :             if (GNUNET_OK !=
     331           8 :                 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           8 :             if (0 != strcmp (
     340             :                   exchange_url,
     341           8 :                   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          16 :         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          16 :         if (gos->refunds_length !=
     358          16 :             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          16 :         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          24 :         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          16 :         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          16 :       break;
     441           8 :     case TALER_MERCHANT_OSC_CLAIMED:
     442             :       /* FIXME: Check contract terms... */
     443          10 :       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           8 :       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          30 :     break;
     565           0 :   default:
     566           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     567             :                 "Unhandled HTTP status.\n");
     568             :   }
     569          30 :   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          30 : merchant_get_order_run (void *cls,
     582             :                         const struct TALER_TESTING_Command *cmd,
     583             :                         struct TALER_TESTING_Interpreter *is)
     584             : {
     585          30 :   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          30 :   order_cmd = TALER_TESTING_interpreter_lookup_command (
     591             :     is,
     592             :     gos->order_reference);
     593             : 
     594          30 :   if (GNUNET_OK !=
     595          30 :       TALER_TESTING_get_trait_order_id (order_cmd,
     596             :                                         &order_id))
     597           0 :     TALER_TESTING_FAIL (is);
     598             : 
     599          30 :   if (GNUNET_OK !=
     600          30 :       TALER_TESTING_get_trait_h_contract_terms (order_cmd,
     601             :                                                 &h_contract))
     602           0 :     TALER_TESTING_FAIL (is);
     603             : 
     604          30 :   gos->is = is;
     605          30 :   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          30 :     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          30 : merchant_get_order_cleanup (void *cls,
     625             :                             const struct TALER_TESTING_Command *cmd)
     626             : {
     627          30 :   struct MerchantGetOrderState *gos = cls;
     628             : 
     629          30 :   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          30 :   GNUNET_array_grow (gos->transfers,
     635             :                      gos->transfers_length,
     636             :                      0);
     637          30 :   GNUNET_array_grow (gos->refunds,
     638             :                      gos->refunds_length,
     639             :                      0);
     640          30 :   GNUNET_array_grow (gos->forgets,
     641             :                      gos->forgets_length,
     642             :                      0);
     643          30 :   GNUNET_free (gos);
     644          30 : }
     645             : 
     646             : 
     647             : struct TALER_TESTING_Command
     648           8 : 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           8 :   gos = GNUNET_new (struct MerchantGetOrderState);
     660           8 :   gos->merchant_url = merchant_url;
     661           8 :   gos->order_reference = order_reference;
     662           8 :   gos->osc = osc;
     663           8 :   gos->refunded = refunded;
     664           8 :   gos->http_status = http_status;
     665           8 :   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           8 :     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           8 :     return cmd;
     688             :   }
     689             : }
     690             : 
     691             : 
     692             : struct TALER_TESTING_Command
     693          10 : 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          10 :   gos = GNUNET_new (struct MerchantGetOrderState);
     708          10 :   gos->merchant_url = merchant_url;
     709          10 :   gos->order_reference = order_reference;
     710          10 :   gos->osc = osc;
     711          10 :   gos->wired = wired;
     712          10 :   gos->refunded = refunded;
     713          10 :   gos->http_status = http_status;
     714          10 :   if (wired)
     715             :   {
     716          16 :     for (const char **clabel = transfers; *clabel != NULL; ++clabel)
     717             :     {
     718           8 :       GNUNET_array_append (gos->transfers,
     719             :                            gos->transfers_length,
     720             :                            *clabel);
     721             :     }
     722             :   }
     723          10 :   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          10 :   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          10 :     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          10 :     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 1.16