LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_refund.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 71.6 % 95 68
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 6 6

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2023 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/testing_api_cmd_refund.c
      21              :  * @brief Implement the /refund test command, plus other
      22              :  *        corollary commands (?).
      23              :  * @author Marcello Stanisci
      24              :  */
      25              : #include "taler/taler_json_lib.h"
      26              : #include <gnunet/gnunet_curl_lib.h>
      27              : struct RefundState;
      28              : #define TALER_EXCHANGE_POST_COINS_REFUND_RESULT_CLOSURE struct RefundState
      29              : #include "taler/exchange/post-coins-COIN_PUB-refund.h"
      30              : #include "taler/taler_testing_lib.h"
      31              : 
      32              : 
      33              : /**
      34              :  * State for a "refund" CMD.
      35              :  */
      36              : struct RefundState
      37              : {
      38              :   /**
      39              :    * Expected HTTP response code.
      40              :    */
      41              :   unsigned int expected_response_code;
      42              : 
      43              :   /**
      44              :    * Amount to be refunded.
      45              :    */
      46              :   const char *refund_amount;
      47              : 
      48              :   /**
      49              :    * Reference to any command that can provide a coin to refund.
      50              :    */
      51              :   const char *coin_reference;
      52              : 
      53              :   /**
      54              :    * Refund transaction identifier.
      55              :    */
      56              :   uint64_t refund_transaction_id;
      57              : 
      58              :   /**
      59              :    * Entry in the coin's history generated by this operation.
      60              :    */
      61              :   struct TALER_EXCHANGE_CoinHistoryEntry che;
      62              : 
      63              :   /**
      64              :    * Public key of the refunded coin.
      65              :    */
      66              :   struct TALER_CoinSpendPublicKeyP coin;
      67              : 
      68              :   /**
      69              :    * Handle to the refund operation.
      70              :    */
      71              :   struct TALER_EXCHANGE_PostCoinsRefundHandle *rh;
      72              : 
      73              :   /**
      74              :    * Interpreter state.
      75              :    */
      76              :   struct TALER_TESTING_Interpreter *is;
      77              : };
      78              : 
      79              : 
      80              : /**
      81              :  * Check the result for the refund request, just check if the
      82              :  * response code is acceptable.
      83              :  *
      84              :  * @param rs closure
      85              :  * @param rr response details
      86              :  */
      87              : static void
      88           14 : refund_cb (struct RefundState *rs,
      89              :            const struct TALER_EXCHANGE_PostCoinsRefundResponse *rr)
      90              : {
      91           14 :   const struct TALER_EXCHANGE_HttpResponse *hr = &rr->hr;
      92              : 
      93           14 :   rs->rh = NULL;
      94           14 :   if (rs->expected_response_code != hr->http_status)
      95              :   {
      96            0 :     TALER_TESTING_unexpected_status (rs->is,
      97              :                                      hr->http_status,
      98              :                                      rs->expected_response_code);
      99            0 :     return;
     100              :   }
     101           14 :   if (MHD_HTTP_OK == hr->http_status)
     102              :   {
     103              :     struct TALER_Amount refund_amount;
     104              : 
     105           10 :     if (GNUNET_OK !=
     106           10 :         TALER_string_to_amount (rs->refund_amount,
     107              :                                 &refund_amount))
     108              :     {
     109            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     110              :                   "Failed to parse amount `%s'\n",
     111              :                   rs->refund_amount);
     112            0 :       TALER_TESTING_interpreter_fail (rs->is);
     113            0 :       return;
     114              :     }
     115           10 :     if (0 >
     116           10 :         TALER_amount_subtract (&rs->che.amount,
     117              :                                &refund_amount,
     118           10 :                                &rs->che.details.refund.refund_fee))
     119              :     {
     120            0 :       GNUNET_break (0);
     121            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     122              :                   "Failed to subtract %s from %s\n",
     123              :                   TALER_amount2s (&rs->che.details.refund.refund_fee),
     124              :                   rs->refund_amount);
     125            0 :       TALER_TESTING_interpreter_fail (rs->is);
     126            0 :       return;
     127              :     }
     128              :   }
     129           14 :   TALER_TESTING_interpreter_next (rs->is);
     130              : }
     131              : 
     132              : 
     133              : /**
     134              :  * Run the command.
     135              :  *
     136              :  * @param cls closure.
     137              :  * @param cmd the command to execute.
     138              :  * @param is the interpreter state.
     139              :  */
     140              : static void
     141           14 : refund_run (void *cls,
     142              :             const struct TALER_TESTING_Command *cmd,
     143              :             struct TALER_TESTING_Interpreter *is)
     144              : {
     145           14 :   struct RefundState *rs = cls;
     146              :   const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     147              :   const json_t *contract_terms;
     148              :   struct TALER_PrivateContractHashP h_contract_terms;
     149              :   struct TALER_Amount refund_amount;
     150              :   const struct TALER_MerchantPrivateKeyP *merchant_priv;
     151              :   const struct TALER_TESTING_Command *coin_cmd;
     152              :   const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     153              : 
     154           14 :   rs->is = is;
     155           14 :   if (GNUNET_OK !=
     156           14 :       TALER_string_to_amount (rs->refund_amount,
     157              :                               &refund_amount))
     158              :   {
     159            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     160              :                 "Failed to parse amount `%s' at %s\n",
     161              :                 rs->refund_amount,
     162              :                 cmd->label);
     163            0 :     TALER_TESTING_interpreter_fail (is);
     164            0 :     return;
     165              :   }
     166           14 :   coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
     167              :                                                        rs->coin_reference);
     168           14 :   if (NULL == coin_cmd)
     169              :   {
     170            0 :     GNUNET_break (0);
     171            0 :     TALER_TESTING_interpreter_fail (is);
     172            0 :     return;
     173              :   }
     174           14 :   if (GNUNET_OK !=
     175           14 :       TALER_TESTING_get_trait_contract_terms (coin_cmd,
     176              :                                               &contract_terms))
     177              :   {
     178            0 :     GNUNET_break (0);
     179            0 :     TALER_TESTING_interpreter_fail (is);
     180            0 :     return;
     181              :   }
     182           14 :   GNUNET_assert (GNUNET_OK ==
     183              :                  TALER_JSON_contract_hash (contract_terms,
     184              :                                            &h_contract_terms));
     185              : 
     186              :   /* Hunting for a coin .. */
     187           14 :   if ( (GNUNET_OK !=
     188           14 :         TALER_TESTING_get_trait_coin_priv (coin_cmd,
     189              :                                            0,
     190           14 :                                            &coin_priv)) ||
     191              :        (GNUNET_OK !=
     192           14 :         TALER_TESTING_get_trait_denom_pub (coin_cmd,
     193              :                                            0,
     194              :                                            &denom_pub)) )
     195              : 
     196              :   {
     197            0 :     GNUNET_break (0);
     198            0 :     TALER_TESTING_interpreter_fail (is);
     199            0 :     return;
     200              :   }
     201              : 
     202           14 :   GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
     203              :                                       &rs->coin.eddsa_pub);
     204           14 :   if (GNUNET_OK !=
     205           14 :       TALER_TESTING_get_trait_merchant_priv (coin_cmd,
     206              :                                              &merchant_priv))
     207              :   {
     208            0 :     GNUNET_break (0);
     209            0 :     TALER_TESTING_interpreter_fail (is);
     210            0 :     return;
     211              :   }
     212           14 :   rs->che.type = TALER_EXCHANGE_CTT_REFUND;
     213           14 :   rs->che.details.refund.h_contract_terms = h_contract_terms;
     214           14 :   GNUNET_CRYPTO_eddsa_key_get_public (
     215           14 :     &merchant_priv->eddsa_priv,
     216              :     &rs->che.details.refund.merchant_pub.eddsa_pub);
     217           14 :   rs->che.details.refund.refund_fee = denom_pub->fees.refund;
     218           14 :   rs->che.details.refund.sig_amount = refund_amount;
     219           14 :   rs->che.details.refund.rtransaction_id = rs->refund_transaction_id;
     220           14 :   TALER_merchant_refund_sign (&rs->coin,
     221              :                               &h_contract_terms,
     222              :                               rs->refund_transaction_id,
     223              :                               &refund_amount,
     224              :                               merchant_priv,
     225              :                               &rs->che.details.refund.sig);
     226           14 :   rs->rh = TALER_EXCHANGE_post_coins_refund_create (
     227              :     TALER_TESTING_interpreter_get_context (is),
     228              :     TALER_TESTING_get_exchange_url (is),
     229              :     TALER_TESTING_get_keys (is),
     230              :     &refund_amount,
     231              :     &h_contract_terms,
     232           14 :     &rs->coin,
     233              :     rs->refund_transaction_id,
     234              :     merchant_priv);
     235           14 :   GNUNET_assert (NULL != rs->rh);
     236           14 :   GNUNET_assert (TALER_EC_NONE ==
     237              :                  TALER_EXCHANGE_post_coins_refund_start (rs->rh,
     238              :                                                          &refund_cb,
     239              :                                                          rs));
     240              : }
     241              : 
     242              : 
     243              : /**
     244              :  * Offer internal data from a "refund" CMD, to other commands.
     245              :  *
     246              :  * @param cls closure.
     247              :  * @param[out] ret result.
     248              :  * @param trait name of the trait.
     249              :  * @param index index number of the object to offer.
     250              :  * @return #GNUNET_OK on success.
     251              :  */
     252              : static enum GNUNET_GenericReturnValue
     253           36 : refund_traits (void *cls,
     254              :                const void **ret,
     255              :                const char *trait,
     256              :                unsigned int index)
     257              : {
     258           36 :   struct RefundState *rs = cls;
     259              :   struct TALER_TESTING_Trait traits[] = {
     260           36 :     TALER_TESTING_make_trait_coin_history (0,
     261           36 :                                            &rs->che),
     262           36 :     TALER_TESTING_make_trait_coin_pub (0,
     263           36 :                                        &rs->coin),
     264           36 :     TALER_TESTING_trait_end ()
     265              :   };
     266              : 
     267           36 :   return TALER_TESTING_get_trait (traits,
     268              :                                   ret,
     269              :                                   trait,
     270              :                                   index);
     271              : }
     272              : 
     273              : 
     274              : /**
     275              :  * Free the state from a "refund" CMD, and possibly cancel
     276              :  * a pending operation thereof.
     277              :  *
     278              :  * @param cls closure.
     279              :  * @param cmd the command which is being cleaned up.
     280              :  */
     281              : static void
     282           14 : refund_cleanup (void *cls,
     283              :                 const struct TALER_TESTING_Command *cmd)
     284              : {
     285           14 :   struct RefundState *rs = cls;
     286              : 
     287           14 :   if (NULL != rs->rh)
     288              :   {
     289            0 :     TALER_TESTING_command_incomplete (rs->is,
     290              :                                       cmd->label);
     291            0 :     TALER_EXCHANGE_post_coins_refund_cancel (rs->rh);
     292            0 :     rs->rh = NULL;
     293              :   }
     294           14 :   GNUNET_free (rs);
     295           14 : }
     296              : 
     297              : 
     298              : struct TALER_TESTING_Command
     299            6 : TALER_TESTING_cmd_refund (const char *label,
     300              :                           unsigned int expected_response_code,
     301              :                           const char *refund_amount,
     302              :                           const char *coin_reference)
     303              : {
     304              :   struct RefundState *rs;
     305              : 
     306            6 :   rs = GNUNET_new (struct RefundState);
     307            6 :   rs->expected_response_code = expected_response_code;
     308            6 :   rs->refund_amount = refund_amount;
     309            6 :   rs->coin_reference = coin_reference;
     310              :   {
     311            6 :     struct TALER_TESTING_Command cmd = {
     312              :       .cls = rs,
     313              :       .label = label,
     314              :       .run = &refund_run,
     315              :       .cleanup = &refund_cleanup,
     316              :       .traits = &refund_traits
     317              :     };
     318              : 
     319            6 :     return cmd;
     320              :   }
     321              : }
     322              : 
     323              : 
     324              : struct TALER_TESTING_Command
     325            8 : TALER_TESTING_cmd_refund_with_id (
     326              :   const char *label,
     327              :   unsigned int expected_response_code,
     328              :   const char *refund_amount,
     329              :   const char *coin_reference,
     330              :   uint64_t refund_transaction_id)
     331              : {
     332              :   struct RefundState *rs;
     333              : 
     334            8 :   rs = GNUNET_new (struct RefundState);
     335            8 :   rs->expected_response_code = expected_response_code;
     336            8 :   rs->refund_amount = refund_amount;
     337            8 :   rs->coin_reference = coin_reference;
     338            8 :   rs->refund_transaction_id = refund_transaction_id;
     339              :   {
     340            8 :     struct TALER_TESTING_Command cmd = {
     341              :       .cls = rs,
     342              :       .label = label,
     343              :       .run = &refund_run,
     344              :       .cleanup = &refund_cleanup,
     345              :       .traits = &refund_traits
     346              :     };
     347              : 
     348            8 :     return cmd;
     349              :   }
     350              : }
        

Generated by: LCOV version 2.0-1