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

Generated by: LCOV version 2.0-1