LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_bank_transfer.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 58.8 % 85 50
Test Date: 2025-12-22 22:38:17 Functions: 71.4 % 7 5

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2018-2021 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it
       6              :   under the terms of the GNU General Public License as published by
       7              :   the Free Software Foundation; either version 3, or (at your
       8              :   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 GNU
      13              :   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_bank_transfer.c
      21              :  * @brief implementation of a bank /transfer command
      22              :  * @author Christian Grothoff
      23              :  * @author Marcello Stanisci
      24              :  */
      25              : #include "taler/platform.h"
      26              : #include "taler/backoff.h"
      27              : #include "taler/taler_json_lib.h"
      28              : #include <gnunet/gnunet_curl_lib.h>
      29              : #include "taler/taler_bank_service.h"
      30              : #include "taler/taler_fakebank_lib.h"
      31              : #include "taler/taler_signatures.h"
      32              : #include "taler/taler_testing_lib.h"
      33              : 
      34              : 
      35              : /**
      36              :  * How often do we retry before giving up?
      37              :  */
      38              : #define NUM_RETRIES 5
      39              : 
      40              : 
      41              : /**
      42              :  * State for a "transfer" CMD.
      43              :  */
      44              : struct TransferState
      45              : {
      46              : 
      47              :   /**
      48              :    * Wire transfer amount.
      49              :    */
      50              :   struct TALER_Amount amount;
      51              : 
      52              :   /**
      53              :    * Base URL of the debit account.
      54              :    */
      55              :   const char *account_debit_url;
      56              : 
      57              :   /**
      58              :    * Money receiver payto URL.
      59              :    */
      60              :   struct TALER_FullPayto payto_debit_account;
      61              : 
      62              :   /**
      63              :    * Money receiver account URL.
      64              :    */
      65              :   struct TALER_FullPayto payto_credit_account;
      66              : 
      67              :   /**
      68              :    * Username to use for authentication.
      69              :    */
      70              :   struct TALER_BANK_AuthenticationData auth;
      71              : 
      72              :   /**
      73              :    * Base URL of the exchange.
      74              :    */
      75              :   const char *exchange_base_url;
      76              : 
      77              :   /**
      78              :    * Wire transfer identifier to use.
      79              :    */
      80              :   struct TALER_WireTransferIdentifierRawP wtid;
      81              : 
      82              :   /**
      83              :    * Handle to the pending request at the fakebank.
      84              :    */
      85              :   struct TALER_BANK_TransferHandle *weh;
      86              : 
      87              :   /**
      88              :    * Interpreter state.
      89              :    */
      90              :   struct TALER_TESTING_Interpreter *is;
      91              : 
      92              :   /**
      93              :    * Set to the wire transfer's unique ID.
      94              :    */
      95              :   uint64_t serial_id;
      96              : 
      97              :   /**
      98              :    * Timestamp of the transaction (as returned from the bank).
      99              :    */
     100              :   struct GNUNET_TIME_Timestamp timestamp;
     101              : 
     102              :   /**
     103              :    * Configuration filename.  Used to get the tip reserve key
     104              :    * filename (used to obtain a public key to write in the
     105              :    * transfer subject).
     106              :    */
     107              :   const char *config_filename;
     108              : 
     109              :   /**
     110              :    * Task scheduled to try later.
     111              :    */
     112              :   struct GNUNET_SCHEDULER_Task *retry_task;
     113              : 
     114              :   /**
     115              :    * How long do we wait until we retry?
     116              :    */
     117              :   struct GNUNET_TIME_Relative backoff;
     118              : 
     119              :   /**
     120              :    * Was this command modified via
     121              :    * #TALER_TESTING_cmd_admin_add_incoming_with_retry to
     122              :    * enable retries? If so, how often should we still retry?
     123              :    */
     124              :   unsigned int do_retry;
     125              : };
     126              : 
     127              : 
     128              : /**
     129              :  * Run the "transfer" CMD.
     130              :  *
     131              :  * @param cls closure.
     132              :  * @param cmd CMD being run.
     133              :  * @param is interpreter state.
     134              :  */
     135              : static void
     136              : transfer_run (void *cls,
     137              :               const struct TALER_TESTING_Command *cmd,
     138              :               struct TALER_TESTING_Interpreter *is);
     139              : 
     140              : 
     141              : /**
     142              :  * Task scheduled to re-try #transfer_run.
     143              :  *
     144              :  * @param cls a `struct TransferState`
     145              :  */
     146              : static void
     147            0 : do_retry (void *cls)
     148              : {
     149            0 :   struct TransferState *fts = cls;
     150              : 
     151            0 :   fts->retry_task = NULL;
     152            0 :   TALER_TESTING_touch_cmd (fts->is);
     153            0 :   transfer_run (fts,
     154              :                 NULL,
     155              :                 fts->is);
     156            0 : }
     157              : 
     158              : 
     159              : /**
     160              :  * This callback will process the fakebank response to the wire
     161              :  * transfer.  It just checks whether the HTTP response code is
     162              :  * acceptable.
     163              :  *
     164              :  * @param cls closure with the interpreter state
     165              :  * @param tr response details
     166              :  */
     167              : static void
     168            2 : confirmation_cb (void *cls,
     169              :                  const struct TALER_BANK_TransferResponse *tr)
     170              : {
     171            2 :   struct TransferState *fts = cls;
     172            2 :   struct TALER_TESTING_Interpreter *is = fts->is;
     173              : 
     174            2 :   fts->weh = NULL;
     175            2 :   if (MHD_HTTP_OK != tr->http_status)
     176              :   {
     177            0 :     if (0 != fts->do_retry)
     178              :     {
     179            0 :       fts->do_retry--;
     180            0 :       if ( (0 == tr->http_status) ||
     181            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec) ||
     182            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == tr->http_status) )
     183              :       {
     184            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     185              :                     "Retrying transfer failed with %u/%d\n",
     186              :                     tr->http_status,
     187              :                     (int) tr->ec);
     188              :         /* on DB conflicts, do not use backoff */
     189            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec)
     190            0 :           fts->backoff = GNUNET_TIME_UNIT_ZERO;
     191              :         else
     192            0 :           fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
     193            0 :         TALER_TESTING_inc_tries (fts->is);
     194              :         fts->retry_task
     195            0 :           = GNUNET_SCHEDULER_add_delayed (fts->backoff,
     196              :                                           &do_retry,
     197              :                                           fts);
     198            0 :         return;
     199              :       }
     200              :     }
     201            0 :     TALER_TESTING_unexpected_status (is,
     202              :                                      tr->http_status,
     203              :                                      MHD_HTTP_OK);
     204            0 :     return;
     205              :   }
     206              : 
     207            2 :   fts->serial_id = tr->details.ok.row_id;
     208            2 :   fts->timestamp = tr->details.ok.timestamp;
     209            2 :   TALER_TESTING_interpreter_next (is);
     210              : }
     211              : 
     212              : 
     213              : /**
     214              :  * Run the "transfer" CMD.
     215              :  *
     216              :  * @param cls closure.
     217              :  * @param cmd CMD being run.
     218              :  * @param is interpreter state.
     219              :  */
     220              : static void
     221            2 : transfer_run (void *cls,
     222              :               const struct TALER_TESTING_Command *cmd,
     223              :               struct TALER_TESTING_Interpreter *is)
     224              : {
     225            2 :   struct TransferState *fts = cls;
     226              :   void *buf;
     227              :   size_t buf_size;
     228              : 
     229              :   (void) cmd;
     230            2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     231              :               "Transfer of %s from %s to %s\n",
     232              :               TALER_amount2s (&fts->amount),
     233              :               fts->account_debit_url,
     234              :               fts->payto_credit_account.full_payto);
     235            2 :   TALER_BANK_prepare_transfer (fts->payto_credit_account,
     236            2 :                                &fts->amount,
     237              :                                fts->exchange_base_url,
     238            2 :                                &fts->wtid,
     239              :                                &buf,
     240              :                                &buf_size);
     241            2 :   fts->is = is;
     242              :   fts->weh
     243            2 :     = TALER_BANK_transfer (
     244              :         TALER_TESTING_interpreter_get_context (is),
     245            2 :         &fts->auth,
     246              :         buf,
     247              :         buf_size,
     248              :         &confirmation_cb,
     249              :         fts);
     250            2 :   GNUNET_free (buf);
     251            2 :   if (NULL == fts->weh)
     252              :   {
     253            0 :     GNUNET_break (0);
     254            0 :     TALER_TESTING_interpreter_fail (is);
     255            0 :     return;
     256              :   }
     257              : }
     258              : 
     259              : 
     260              : /**
     261              :  * Free the state of a "fakebank transfer" CMD, and possibly
     262              :  * cancel a pending operation thereof.
     263              :  *
     264              :  * @param cls closure
     265              :  * @param cmd current CMD being cleaned up.
     266              :  */
     267              : static void
     268            2 : transfer_cleanup (void *cls,
     269              :                   const struct TALER_TESTING_Command *cmd)
     270              : {
     271            2 :   struct TransferState *fts = cls;
     272              : 
     273            2 :   if (NULL != fts->weh)
     274              :   {
     275            0 :     TALER_TESTING_command_incomplete (fts->is,
     276              :                                       cmd->label);
     277            0 :     TALER_BANK_transfer_cancel (fts->weh);
     278            0 :     fts->weh = NULL;
     279              :   }
     280            2 :   if (NULL != fts->retry_task)
     281              :   {
     282            0 :     GNUNET_SCHEDULER_cancel (fts->retry_task);
     283            0 :     fts->retry_task = NULL;
     284              :   }
     285            2 :   GNUNET_free (fts);
     286            2 : }
     287              : 
     288              : 
     289              : /**
     290              :  * Offer internal data from a "fakebank transfer" CMD to other
     291              :  * commands.
     292              :  *
     293              :  * @param cls closure.
     294              :  * @param[out] ret result
     295              :  * @param trait name of the trait.
     296              :  * @param index index number of the object to offer.
     297              :  * @return #GNUNET_OK on success.
     298              :  */
     299              : static enum GNUNET_GenericReturnValue
     300           12 : transfer_traits (void *cls,
     301              :                  const void **ret,
     302              :                  const char *trait,
     303              :                  unsigned int index)
     304              : {
     305           12 :   struct TransferState *fts = cls;
     306              :   struct TALER_TESTING_Trait traits[] = {
     307           12 :     TALER_TESTING_make_trait_exchange_url (
     308              :       fts->exchange_base_url),
     309           12 :     TALER_TESTING_make_trait_bank_row (&fts->serial_id),
     310           12 :     TALER_TESTING_make_trait_credit_payto_uri (
     311           12 :       &fts->payto_credit_account),
     312           12 :     TALER_TESTING_make_trait_debit_payto_uri (
     313           12 :       &fts->payto_debit_account),
     314           12 :     TALER_TESTING_make_trait_amount (&fts->amount),
     315           12 :     TALER_TESTING_make_trait_timestamp (0, &fts->timestamp),
     316           12 :     TALER_TESTING_make_trait_wtid (&fts->wtid),
     317           12 :     TALER_TESTING_trait_end ()
     318              :   };
     319              : 
     320           12 :   return TALER_TESTING_get_trait (traits,
     321              :                                   ret,
     322              :                                   trait,
     323              :                                   index);
     324              : }
     325              : 
     326              : 
     327              : struct TALER_TESTING_Command
     328            2 : TALER_TESTING_cmd_transfer (const char *label,
     329              :                             const char *amount,
     330              :                             const struct TALER_BANK_AuthenticationData *auth,
     331              :                             struct TALER_FullPayto payto_debit_account,
     332              :                             struct TALER_FullPayto payto_credit_account,
     333              :                             const struct TALER_WireTransferIdentifierRawP *wtid,
     334              :                             const char *exchange_base_url)
     335              : {
     336              :   struct TransferState *fts;
     337              : 
     338            2 :   fts = GNUNET_new (struct TransferState);
     339            2 :   fts->account_debit_url = auth->wire_gateway_url;
     340            2 :   fts->exchange_base_url = exchange_base_url;
     341            2 :   fts->payto_debit_account = payto_debit_account;
     342            2 :   fts->payto_credit_account = payto_credit_account;
     343            2 :   fts->auth = *auth;
     344            2 :   fts->wtid = *wtid;
     345            2 :   if (GNUNET_OK !=
     346            2 :       TALER_string_to_amount (amount,
     347              :                               &fts->amount))
     348              :   {
     349            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     350              :                 "Failed to parse amount `%s' at %s\n",
     351              :                 amount,
     352              :                 label);
     353            0 :     GNUNET_assert (0);
     354              :   }
     355              : 
     356              :   {
     357            2 :     struct TALER_TESTING_Command cmd = {
     358              :       .cls = fts,
     359              :       .label = label,
     360              :       .run = &transfer_run,
     361              :       .cleanup = &transfer_cleanup,
     362              :       .traits = &transfer_traits
     363              :     };
     364              : 
     365            2 :     return cmd;
     366              :   }
     367              : }
     368              : 
     369              : 
     370              : struct TALER_TESTING_Command
     371            0 : TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd)
     372              : {
     373              :   struct TransferState *fts;
     374              : 
     375            0 :   GNUNET_assert (&transfer_run == cmd.run);
     376            0 :   fts = cmd.cls;
     377            0 :   fts->do_retry = NUM_RETRIES;
     378            0 :   return cmd;
     379              : }
     380              : 
     381              : 
     382              : /* end of testing_api_cmd_bank_transfer.c */
        

Generated by: LCOV version 2.0-1