LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_post_transfers.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 76.9 % 130 100
Test Date: 2025-11-06 19:31:41 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020, 2023, 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_post_transfers.c
      21              :  * @brief command to test POST /transfers
      22              :  * @author Christian Grothoff
      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 of a "POST /transfers" CMD.
      33              :  */
      34              : struct PostTransfersState
      35              : {
      36              : 
      37              :   /**
      38              :    * Handle for a "POST /transfers" request.
      39              :    */
      40              :   struct TALER_MERCHANT_PostTransfersHandle *pth;
      41              : 
      42              :   /**
      43              :    * Handle for a "GET" bank account history request.
      44              :    */
      45              :   struct TALER_BANK_DebitHistoryHandle *dhh;
      46              : 
      47              :   /**
      48              :    * The interpreter state.
      49              :    */
      50              :   struct TALER_TESTING_Interpreter *is;
      51              : 
      52              :   /**
      53              :    * Base URL of the merchant serving the request.
      54              :    */
      55              :   const char *merchant_url;
      56              : 
      57              :   /**
      58              :    * URL of the bank to run history on.
      59              :    */
      60              :   char *exchange_url;
      61              : 
      62              :   /**
      63              :    * Credit account of the merchant.
      64              :    */
      65              :   struct TALER_FullPayto credit_account;
      66              : 
      67              :   /**
      68              :    * Payto URI to filter on.
      69              :    */
      70              :   struct TALER_FullPayto payto_uri;
      71              : 
      72              :   /**
      73              :    * Set to the hash of the @e payto_uri.
      74              :    */
      75              :   struct TALER_FullPaytoHashP h_payto;
      76              : 
      77              :   /**
      78              :    * Set to the hash of the normalized @e payto_uri.
      79              :    */
      80              :   struct TALER_NormalizedPaytoHashP h_normalized_payto;
      81              : 
      82              :   /**
      83              :    * Authentication details to authenticate to the bank.
      84              :    */
      85              :   struct TALER_BANK_AuthenticationData auth;
      86              : 
      87              :   /**
      88              :    * Set once we discovered the WTID.
      89              :    */
      90              :   struct TALER_WireTransferIdentifierRawP wtid;
      91              : 
      92              :   /**
      93              :    * the credit amount to look for at @e bank_url.
      94              :    */
      95              :   struct TALER_Amount credit_amount;
      96              : 
      97              :   /**
      98              :    * Expected HTTP response code.
      99              :    */
     100              :   unsigned int http_status;
     101              : 
     102              :   /**
     103              :    * Array of deposit command labels we expect to see aggregated.
     104              :    */
     105              :   const char **deposits;
     106              : 
     107              :   /**
     108              :    * Serial number of the wire transfer in the merchant backend,
     109              :    * set by #TALER_TESTING_cmd_merchant_get_transfers(). 0 if unknown.
     110              :    */
     111              :   uint64_t serial;
     112              : 
     113              :   /**
     114              :    * Length of @e deposits.
     115              :    */
     116              :   unsigned int deposits_length;
     117              : 
     118              : };
     119              : 
     120              : 
     121              : /**
     122              :  * Callback for a POST /transfers operation.
     123              :  *
     124              :  * @param cls closure for this function
     125              :  * @param ptr response details
     126              :  */
     127              : static void
     128            7 : transfers_cb (void *cls,
     129              :               const struct TALER_MERCHANT_PostTransfersResponse *ptr)
     130              : {
     131            7 :   struct PostTransfersState *pts = cls;
     132              : 
     133            7 :   pts->pth = NULL;
     134            7 :   if (pts->http_status != ptr->hr.http_status)
     135              :   {
     136            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     137              :                 "Unexpected response code %u (%d) to command %s\n",
     138              :                 ptr->hr.http_status,
     139              :                 (int) ptr->hr.ec,
     140              :                 TALER_TESTING_interpreter_get_current_label (pts->is));
     141            0 :     GNUNET_break (0);
     142            0 :     TALER_TESTING_interpreter_fail (pts->is);
     143            0 :     return;
     144              :   }
     145            7 :   switch (ptr->hr.http_status)
     146              :   {
     147            7 :   case MHD_HTTP_NO_CONTENT:
     148            7 :     break;
     149            0 :   case MHD_HTTP_UNAUTHORIZED:
     150            0 :     break;
     151            0 :   case MHD_HTTP_NOT_FOUND:
     152            0 :     break;
     153            0 :   case MHD_HTTP_GATEWAY_TIMEOUT:
     154            0 :     break;
     155            0 :   default:
     156            0 :     GNUNET_break (0);
     157            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     158              :                 "Unhandled HTTP status %u for POST /transfers.\n",
     159              :                 ptr->hr.http_status);
     160              :   }
     161            7 :   TALER_TESTING_interpreter_next (pts->is);
     162              : }
     163              : 
     164              : 
     165              : /**
     166              :  * Offers information from the POST /transfers CMD state to other
     167              :  * commands.
     168              :  *
     169              :  * @param cls closure
     170              :  * @param[out] ret result (could be anything)
     171              :  * @param trait name of the trait
     172              :  * @param index index number of the object to extract.
     173              :  * @return #GNUNET_OK on success
     174              :  */
     175              : static enum GNUNET_GenericReturnValue
     176           50 : post_transfers_traits (void *cls,
     177              :                        const void **ret,
     178              :                        const char *trait,
     179              :                        unsigned int index)
     180              : {
     181           50 :   struct PostTransfersState *pts = cls;
     182              :   struct TALER_TESTING_Trait traits[] = {
     183           50 :     TALER_TESTING_make_trait_wtid (&pts->wtid),
     184           50 :     TALER_TESTING_make_trait_credit_payto_uri (&pts->credit_account),
     185           50 :     TALER_TESTING_make_trait_h_full_payto (&pts->h_payto),
     186           50 :     TALER_TESTING_make_trait_h_normalized_payto (&pts->h_normalized_payto),
     187           50 :     TALER_TESTING_make_trait_amount (&pts->credit_amount),
     188           50 :     TALER_TESTING_make_trait_exchange_url (pts->exchange_url),
     189           50 :     TALER_TESTING_make_trait_bank_row (&pts->serial),
     190           50 :     TALER_TESTING_trait_end (),
     191              :   };
     192              : 
     193           50 :   return TALER_TESTING_get_trait (traits,
     194              :                                   ret,
     195              :                                   trait,
     196              :                                   index);
     197              : }
     198              : 
     199              : 
     200              : /**
     201              :  * Run the "POST /transfers" CMD. First, get the bank history to find
     202              :  * the wtid.
     203              :  *
     204              :  * @param cls closure.
     205              :  * @param cmd command being run now.
     206              :  * @param is interpreter state.
     207              :  */
     208              : static void
     209            2 : post_transfers_run2 (void *cls,
     210              :                      const struct TALER_TESTING_Command *cmd,
     211              :                      struct TALER_TESTING_Interpreter *is)
     212              : {
     213            2 :   struct PostTransfersState *pts = cls;
     214              : 
     215            2 :   pts->is = is;
     216            2 :   pts->pth = TALER_MERCHANT_transfers_post (
     217              :     TALER_TESTING_interpreter_get_context (pts->is),
     218              :     pts->merchant_url,
     219            2 :     &pts->credit_amount,
     220            2 :     &pts->wtid,
     221              :     pts->credit_account,
     222            2 :     pts->exchange_url,
     223              :     &transfers_cb,
     224              :     pts);
     225            2 :   GNUNET_assert (NULL != pts->pth);
     226            2 : }
     227              : 
     228              : 
     229              : /**
     230              :  * Callbacks of this type are used to serve the result of asking
     231              :  * the bank for the debit transaction history.
     232              :  *
     233              :  * @param cls closure with a `struct PostTransfersState *`
     234              :  * @param reply details from the HTTP response code
     235              :  */
     236              : static void
     237            5 : debit_cb (
     238              :   void *cls,
     239              :   const struct TALER_BANK_DebitHistoryResponse *reply)
     240              : {
     241            5 :   struct PostTransfersState *pts = cls;
     242              : 
     243            5 :   pts->dhh = NULL;
     244            5 :   switch (reply->http_status)
     245              :   {
     246            5 :   case MHD_HTTP_OK:
     247              :     /* handled below */
     248            5 :     break;
     249            0 :   case MHD_HTTP_NO_CONTENT:
     250            0 :     GNUNET_break (0);
     251            0 :     TALER_TESTING_interpreter_fail (pts->is);
     252            0 :     return;
     253            0 :   default:
     254            0 :     GNUNET_break (0);
     255            0 :     TALER_TESTING_interpreter_fail (pts->is);
     256            0 :     return;
     257              :   }
     258            5 :   for (unsigned int i = 0; i<reply->details.ok.details_length; i++)
     259              :   {
     260            5 :     const struct TALER_BANK_DebitDetails *details
     261            5 :       = &reply->details.ok.details[i];
     262              : 
     263            5 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     264              :                 "Bank reports transfer of %s to %s\n",
     265              :                 TALER_amount2s (&details->amount),
     266              :                 details->credit_account_uri.full_payto);
     267            5 :     if (0 != TALER_amount_cmp (&pts->credit_amount,
     268              :                                &details->amount))
     269            0 :       continue;
     270            5 :     pts->wtid = details->wtid;
     271              :     pts->credit_account.full_payto
     272            5 :       = GNUNET_strdup (details->credit_account_uri.full_payto);
     273            5 :     pts->exchange_url = GNUNET_strdup (details->exchange_base_url);
     274            5 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     275              :                 "Bank transfer found, checking with merchant backend at %s about %s from %s to %s with %s\n",
     276              :                 pts->merchant_url,
     277              :                 TALER_amount2s (&pts->credit_amount),
     278              :                 pts->payto_uri.full_payto,
     279              :                 pts->exchange_url,
     280              :                 TALER_B2S (&pts->wtid));
     281            5 :     pts->pth = TALER_MERCHANT_transfers_post (
     282              :       TALER_TESTING_interpreter_get_context (pts->is),
     283              :       pts->merchant_url,
     284            5 :       &pts->credit_amount,
     285            5 :       &pts->wtid,
     286              :       pts->credit_account,
     287            5 :       pts->exchange_url,
     288              :       &transfers_cb,
     289              :       pts);
     290            5 :     GNUNET_assert (NULL != pts->pth);
     291            5 :     break;
     292              :   }
     293            5 :   if (NULL == pts->pth)
     294              :   {
     295            0 :     GNUNET_break (0);
     296            0 :     TALER_TESTING_interpreter_fail (pts->is);
     297            0 :     return;
     298              :   }
     299              : }
     300              : 
     301              : 
     302              : /**
     303              :  * Run the "POST /transfers" CMD. First, get the bank history to find
     304              :  * the wtid.
     305              :  *
     306              :  * @param cls closure.
     307              :  * @param cmd command being run now.
     308              :  * @param is interpreter state.
     309              :  */
     310              : static void
     311            5 : post_transfers_run (void *cls,
     312              :                     const struct TALER_TESTING_Command *cmd,
     313              :                     struct TALER_TESTING_Interpreter *is)
     314              : {
     315            5 :   struct PostTransfersState *pts = cls;
     316              : 
     317            5 :   pts->is = is;
     318            5 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     319              :               "Looking for transfer of %s from %s at bank\n",
     320              :               TALER_amount2s (&pts->credit_amount),
     321              :               pts->payto_uri.full_payto);
     322            5 :   pts->dhh = TALER_BANK_debit_history (TALER_TESTING_interpreter_get_context (
     323              :                                          is),
     324            5 :                                        &pts->auth,
     325              :                                        UINT64_MAX,
     326              :                                        -INT64_MAX,
     327            5 :                                        GNUNET_TIME_UNIT_ZERO,
     328              :                                        &debit_cb,
     329              :                                        pts);
     330            5 :   GNUNET_assert (NULL != pts->dhh);
     331            5 : }
     332              : 
     333              : 
     334              : /**
     335              :  * Free the state of a "POST product" CMD, and possibly
     336              :  * cancel a pending operation thereof.
     337              :  *
     338              :  * @param cls closure.
     339              :  * @param cmd command being run.
     340              :  */
     341              : static void
     342            7 : post_transfers_cleanup (void *cls,
     343              :                         const struct TALER_TESTING_Command *cmd)
     344              : {
     345            7 :   struct PostTransfersState *pts = cls;
     346              : 
     347            7 :   if (NULL != pts->pth)
     348              :   {
     349            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     350              :                 "POST /transfers operation did not complete\n");
     351            0 :     TALER_MERCHANT_transfers_post_cancel (pts->pth);
     352              :   }
     353            7 :   if (NULL != pts->dhh)
     354              :   {
     355            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     356              :                 "GET debit history operation did not complete\n");
     357            0 :     TALER_BANK_debit_history_cancel (pts->dhh);
     358              :   }
     359            7 :   GNUNET_array_grow (pts->deposits,
     360              :                      pts->deposits_length,
     361              :                      0);
     362            7 :   GNUNET_free (pts->exchange_url);
     363            7 :   GNUNET_free (pts->credit_account.full_payto);
     364            7 :   GNUNET_free (pts);
     365            7 : }
     366              : 
     367              : 
     368              : struct TALER_TESTING_Command
     369            5 : TALER_TESTING_cmd_merchant_post_transfer (
     370              :   const char *label,
     371              :   const struct TALER_BANK_AuthenticationData *auth,
     372              :   struct TALER_FullPayto payto_uri,
     373              :   const char *merchant_url,
     374              :   const char *credit_amount,
     375              :   unsigned int http_code,
     376              :   ...)
     377              : {
     378              :   struct PostTransfersState *pts;
     379              : 
     380            5 :   pts = GNUNET_new (struct PostTransfersState);
     381            5 :   pts->merchant_url = merchant_url;
     382            5 :   pts->auth = *auth;
     383            5 :   pts->payto_uri = payto_uri;
     384            5 :   TALER_full_payto_hash (payto_uri,
     385              :                          &pts->h_payto);
     386            5 :   TALER_full_payto_normalize_and_hash (payto_uri,
     387              :                                        &pts->h_normalized_payto);
     388            5 :   GNUNET_assert (GNUNET_OK ==
     389              :                  TALER_string_to_amount (credit_amount,
     390              :                                          &pts->credit_amount));
     391            5 :   pts->http_status = http_code;
     392              :   {
     393              :     const char *clabel;
     394              :     va_list ap;
     395              : 
     396            5 :     va_start (ap, http_code);
     397           10 :     while (NULL != (clabel = va_arg (ap, const char *)))
     398              :     {
     399            5 :       GNUNET_array_append (pts->deposits,
     400              :                            pts->deposits_length,
     401              :                            clabel);
     402              :     }
     403            5 :     va_end (ap);
     404              :   }
     405              :   {
     406            5 :     struct TALER_TESTING_Command cmd = {
     407              :       .cls = pts,
     408              :       .label = label,
     409              :       .run = &post_transfers_run,
     410              :       .cleanup = &post_transfers_cleanup,
     411              :       .traits = &post_transfers_traits
     412              :     };
     413              : 
     414            5 :     return cmd;
     415              :   }
     416              : }
     417              : 
     418              : 
     419              : struct TALER_TESTING_Command
     420            2 : TALER_TESTING_cmd_merchant_post_transfer2 (
     421              :   const char *label,
     422              :   const char *merchant_url,
     423              :   struct TALER_FullPayto payto_uri,
     424              :   const char *credit_amount,
     425              :   const char *wtid,
     426              :   const char *exchange_url,
     427              :   unsigned int http_code)
     428              : {
     429              :   struct PostTransfersState *pts;
     430              : 
     431            2 :   pts = GNUNET_new (struct PostTransfersState);
     432            2 :   pts->merchant_url = merchant_url;
     433              :   pts->credit_account.full_payto
     434            2 :     = GNUNET_strdup (payto_uri.full_payto);
     435            2 :   pts->exchange_url = GNUNET_strdup (exchange_url);
     436            2 :   GNUNET_assert (GNUNET_OK ==
     437              :                  TALER_string_to_amount (credit_amount,
     438              :                                          &pts->credit_amount));
     439            2 :   if (NULL == wtid)
     440              :   {
     441            2 :     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
     442            2 :                                 &pts->wtid,
     443              :                                 sizeof (pts->wtid));
     444              :   }
     445              :   else
     446              :   {
     447            0 :     GNUNET_assert (GNUNET_OK ==
     448              :                    GNUNET_STRINGS_string_to_data (wtid,
     449              :                                                   strlen (wtid),
     450              :                                                   &pts->wtid,
     451              :                                                   sizeof (pts->wtid)));
     452              :   }
     453            2 :   pts->http_status = http_code;
     454              :   {
     455            2 :     struct TALER_TESTING_Command cmd = {
     456              :       .cls = pts,
     457              :       .label = label,
     458              :       .run = &post_transfers_run2,
     459              :       .cleanup = &post_transfers_cleanup,
     460              :       .traits = &post_transfers_traits
     461              :     };
     462              : 
     463            2 :     return cmd;
     464              :   }
     465              : }
     466              : 
     467              : 
     468              : void
     469            7 : TALER_TESTING_cmd_merchant_post_transfer_set_serial (
     470              :   struct TALER_TESTING_Command *cmd,
     471              :   uint64_t serial)
     472              : {
     473            7 :   struct PostTransfersState *pts = cmd->cls;
     474              : 
     475            7 :   GNUNET_assert (cmd->run = &post_transfers_run);
     476            7 :   pts->serial = serial;
     477            7 : }
     478              : 
     479              : 
     480              : /* end of testing_api_cmd_post_transfers.c */
        

Generated by: LCOV version 2.0-1