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: 2026-04-14 15:39:31 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/backoff.h"
      26              : #include "taler/taler_json_lib.h"
      27              : #include <gnunet/gnunet_curl_lib.h>
      28              : #include "taler/taler_bank_service.h"
      29              : #include "taler/taler_fakebank_lib.h"
      30              : #include "taler/taler_signatures.h"
      31              : #include "taler/taler_testing_lib.h"
      32              : 
      33              : 
      34              : /**
      35              :  * How often do we retry before giving up?
      36              :  */
      37              : #define NUM_RETRIES 5
      38              : 
      39              : 
      40              : /**
      41              :  * State for a "transfer" CMD.
      42              :  */
      43              : struct TransferState
      44              : {
      45              : 
      46              :   /**
      47              :    * Wire transfer amount.
      48              :    */
      49              :   struct TALER_Amount amount;
      50              : 
      51              :   /**
      52              :    * Base URL of the debit account.
      53              :    */
      54              :   const char *account_debit_url;
      55              : 
      56              :   /**
      57              :    * Money receiver payto URL.
      58              :    */
      59              :   struct TALER_FullPayto payto_debit_account;
      60              : 
      61              :   /**
      62              :    * Money receiver account URL.
      63              :    */
      64              :   struct TALER_FullPayto payto_credit_account;
      65              : 
      66              :   /**
      67              :    * Username to use for authentication.
      68              :    */
      69              :   struct TALER_BANK_AuthenticationData auth;
      70              : 
      71              :   /**
      72              :    * Base URL of the exchange.
      73              :    */
      74              :   const char *exchange_base_url;
      75              : 
      76              :   /**
      77              :    * Wire transfer identifier to use.
      78              :    */
      79              :   struct TALER_WireTransferIdentifierRawP wtid;
      80              : 
      81              :   /**
      82              :    * Handle to the pending request at the fakebank.
      83              :    */
      84              :   struct TALER_BANK_TransferHandle *weh;
      85              : 
      86              :   /**
      87              :    * Interpreter state.
      88              :    */
      89              :   struct TALER_TESTING_Interpreter *is;
      90              : 
      91              :   /**
      92              :    * Set to the wire transfer's unique ID.
      93              :    */
      94              :   uint64_t serial_id;
      95              : 
      96              :   /**
      97              :    * Timestamp of the transaction (as returned from the bank).
      98              :    */
      99              :   struct GNUNET_TIME_Timestamp timestamp;
     100              : 
     101              :   /**
     102              :    * Configuration filename.  Used to get the tip reserve key
     103              :    * filename (used to obtain a public key to write in the
     104              :    * transfer subject).
     105              :    */
     106              :   const char *config_filename;
     107              : 
     108              :   /**
     109              :    * Task scheduled to try later.
     110              :    */
     111              :   struct GNUNET_SCHEDULER_Task *retry_task;
     112              : 
     113              :   /**
     114              :    * How long do we wait until we retry?
     115              :    */
     116              :   struct GNUNET_TIME_Relative backoff;
     117              : 
     118              :   /**
     119              :    * Was this command modified via
     120              :    * #TALER_TESTING_cmd_admin_add_incoming_with_retry to
     121              :    * enable retries? If so, how often should we still retry?
     122              :    */
     123              :   unsigned int do_retry;
     124              : };
     125              : 
     126              : 
     127              : /**
     128              :  * Run the "transfer" CMD.
     129              :  *
     130              :  * @param cls closure.
     131              :  * @param cmd CMD being run.
     132              :  * @param is interpreter state.
     133              :  */
     134              : static void
     135              : transfer_run (void *cls,
     136              :               const struct TALER_TESTING_Command *cmd,
     137              :               struct TALER_TESTING_Interpreter *is);
     138              : 
     139              : 
     140              : /**
     141              :  * Task scheduled to re-try #transfer_run.
     142              :  *
     143              :  * @param cls a `struct TransferState`
     144              :  */
     145              : static void
     146            0 : do_retry (void *cls)
     147              : {
     148            0 :   struct TransferState *fts = cls;
     149              : 
     150            0 :   fts->retry_task = NULL;
     151            0 :   TALER_TESTING_touch_cmd (fts->is);
     152            0 :   transfer_run (fts,
     153              :                 NULL,
     154              :                 fts->is);
     155            0 : }
     156              : 
     157              : 
     158              : /**
     159              :  * This callback will process the fakebank response to the wire
     160              :  * transfer.  It just checks whether the HTTP response code is
     161              :  * acceptable.
     162              :  *
     163              :  * @param cls closure with the interpreter state
     164              :  * @param tr response details
     165              :  */
     166              : static void
     167            2 : confirmation_cb (void *cls,
     168              :                  const struct TALER_BANK_TransferResponse *tr)
     169              : {
     170            2 :   struct TransferState *fts = cls;
     171            2 :   struct TALER_TESTING_Interpreter *is = fts->is;
     172              : 
     173            2 :   fts->weh = NULL;
     174            2 :   if (MHD_HTTP_OK != tr->http_status)
     175              :   {
     176            0 :     if (0 != fts->do_retry)
     177              :     {
     178            0 :       fts->do_retry--;
     179            0 :       if ( (0 == tr->http_status) ||
     180            0 :            (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec) ||
     181            0 :            (MHD_HTTP_INTERNAL_SERVER_ERROR == tr->http_status) )
     182              :       {
     183            0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     184              :                     "Retrying transfer failed with %u/%d\n",
     185              :                     tr->http_status,
     186              :                     (int) tr->ec);
     187              :         /* on DB conflicts, do not use backoff */
     188            0 :         if (TALER_EC_GENERIC_DB_SOFT_FAILURE == tr->ec)
     189            0 :           fts->backoff = GNUNET_TIME_UNIT_ZERO;
     190              :         else
     191            0 :           fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
     192            0 :         TALER_TESTING_inc_tries (fts->is);
     193              :         fts->retry_task
     194            0 :           = GNUNET_SCHEDULER_add_delayed (fts->backoff,
     195              :                                           &do_retry,
     196              :                                           fts);
     197            0 :         return;
     198              :       }
     199              :     }
     200            0 :     TALER_TESTING_unexpected_status (is,
     201              :                                      tr->http_status,
     202              :                                      MHD_HTTP_OK);
     203            0 :     return;
     204              :   }
     205              : 
     206            2 :   fts->serial_id = tr->details.ok.row_id;
     207            2 :   fts->timestamp = tr->details.ok.timestamp;
     208            2 :   TALER_TESTING_interpreter_next (is);
     209              : }
     210              : 
     211              : 
     212              : /**
     213              :  * Run the "transfer" CMD.
     214              :  *
     215              :  * @param cls closure.
     216              :  * @param cmd CMD being run.
     217              :  * @param is interpreter state.
     218              :  */
     219              : static void
     220            2 : transfer_run (void *cls,
     221              :               const struct TALER_TESTING_Command *cmd,
     222              :               struct TALER_TESTING_Interpreter *is)
     223              : {
     224            2 :   struct TransferState *fts = cls;
     225              :   void *buf;
     226              :   size_t buf_size;
     227              : 
     228              :   (void) cmd;
     229            2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     230              :               "Transfer of %s from %s to %s\n",
     231              :               TALER_amount2s (&fts->amount),
     232              :               fts->account_debit_url,
     233              :               fts->payto_credit_account.full_payto);
     234            2 :   TALER_BANK_prepare_transfer (fts->payto_credit_account,
     235            2 :                                &fts->amount,
     236              :                                fts->exchange_base_url,
     237            2 :                                &fts->wtid,
     238              :                                NULL, /* no additional meta data */
     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