merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

testing_api_cmd_post_transfers.c (12847B)


      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 transfers_cb (void *cls,
    129               const struct TALER_MERCHANT_PostTransfersResponse *ptr)
    130 {
    131   struct PostTransfersState *pts = cls;
    132 
    133   pts->pth = NULL;
    134   if (pts->http_status != ptr->hr.http_status)
    135   {
    136     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     GNUNET_break (0);
    142     TALER_TESTING_interpreter_fail (pts->is);
    143     return;
    144   }
    145   switch (ptr->hr.http_status)
    146   {
    147   case MHD_HTTP_NO_CONTENT:
    148     break;
    149   case MHD_HTTP_UNAUTHORIZED:
    150     break;
    151   case MHD_HTTP_NOT_FOUND:
    152     break;
    153   case MHD_HTTP_GATEWAY_TIMEOUT:
    154     break;
    155   default:
    156     GNUNET_break (0);
    157     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    158                 "Unhandled HTTP status %u for POST /transfers.\n",
    159                 ptr->hr.http_status);
    160   }
    161   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 post_transfers_traits (void *cls,
    177                        const void **ret,
    178                        const char *trait,
    179                        unsigned int index)
    180 {
    181   struct PostTransfersState *pts = cls;
    182   struct TALER_TESTING_Trait traits[] = {
    183     TALER_TESTING_make_trait_wtid (&pts->wtid),
    184     TALER_TESTING_make_trait_credit_payto_uri (&pts->credit_account),
    185     TALER_TESTING_make_trait_h_full_payto (&pts->h_payto),
    186     TALER_TESTING_make_trait_h_normalized_payto (&pts->h_normalized_payto),
    187     TALER_TESTING_make_trait_amount (&pts->credit_amount),
    188     TALER_TESTING_make_trait_exchange_url (pts->exchange_url),
    189     TALER_TESTING_make_trait_bank_row (&pts->serial),
    190     TALER_TESTING_trait_end (),
    191   };
    192 
    193   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 post_transfers_run2 (void *cls,
    210                      const struct TALER_TESTING_Command *cmd,
    211                      struct TALER_TESTING_Interpreter *is)
    212 {
    213   struct PostTransfersState *pts = cls;
    214 
    215   pts->is = is;
    216   pts->pth = TALER_MERCHANT_transfers_post (
    217     TALER_TESTING_interpreter_get_context (pts->is),
    218     pts->merchant_url,
    219     &pts->credit_amount,
    220     &pts->wtid,
    221     pts->credit_account,
    222     pts->exchange_url,
    223     &transfers_cb,
    224     pts);
    225   GNUNET_assert (NULL != pts->pth);
    226 }
    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 debit_cb (
    238   void *cls,
    239   const struct TALER_BANK_DebitHistoryResponse *reply)
    240 {
    241   struct PostTransfersState *pts = cls;
    242 
    243   pts->dhh = NULL;
    244   switch (reply->http_status)
    245   {
    246   case MHD_HTTP_OK:
    247     /* handled below */
    248     break;
    249   case MHD_HTTP_NO_CONTENT:
    250     GNUNET_break (0);
    251     TALER_TESTING_interpreter_fail (pts->is);
    252     return;
    253   default:
    254     GNUNET_break (0);
    255     TALER_TESTING_interpreter_fail (pts->is);
    256     return;
    257   }
    258   for (unsigned int i = 0; i<reply->details.ok.details_length; i++)
    259   {
    260     const struct TALER_BANK_DebitDetails *details
    261       = &reply->details.ok.details[i];
    262 
    263     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     if (0 != TALER_amount_cmp (&pts->credit_amount,
    268                                &details->amount))
    269       continue;
    270     pts->wtid = details->wtid;
    271     pts->credit_account.full_payto
    272       = GNUNET_strdup (details->credit_account_uri.full_payto);
    273     pts->exchange_url = GNUNET_strdup (details->exchange_base_url);
    274     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     pts->pth = TALER_MERCHANT_transfers_post (
    282       TALER_TESTING_interpreter_get_context (pts->is),
    283       pts->merchant_url,
    284       &pts->credit_amount,
    285       &pts->wtid,
    286       pts->credit_account,
    287       pts->exchange_url,
    288       &transfers_cb,
    289       pts);
    290     GNUNET_assert (NULL != pts->pth);
    291     break;
    292   }
    293   if (NULL == pts->pth)
    294   {
    295     GNUNET_break (0);
    296     TALER_TESTING_interpreter_fail (pts->is);
    297     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 post_transfers_run (void *cls,
    312                     const struct TALER_TESTING_Command *cmd,
    313                     struct TALER_TESTING_Interpreter *is)
    314 {
    315   struct PostTransfersState *pts = cls;
    316 
    317   pts->is = is;
    318   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   pts->dhh = TALER_BANK_debit_history (TALER_TESTING_interpreter_get_context (
    323                                          is),
    324                                        &pts->auth,
    325                                        UINT64_MAX,
    326                                        -INT64_MAX,
    327                                        GNUNET_TIME_UNIT_ZERO,
    328                                        &debit_cb,
    329                                        pts);
    330   GNUNET_assert (NULL != pts->dhh);
    331 }
    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 post_transfers_cleanup (void *cls,
    343                         const struct TALER_TESTING_Command *cmd)
    344 {
    345   struct PostTransfersState *pts = cls;
    346 
    347   if (NULL != pts->pth)
    348   {
    349     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    350                 "POST /transfers operation did not complete\n");
    351     TALER_MERCHANT_transfers_post_cancel (pts->pth);
    352   }
    353   if (NULL != pts->dhh)
    354   {
    355     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    356                 "GET debit history operation did not complete\n");
    357     TALER_BANK_debit_history_cancel (pts->dhh);
    358   }
    359   GNUNET_array_grow (pts->deposits,
    360                      pts->deposits_length,
    361                      0);
    362   GNUNET_free (pts->exchange_url);
    363   GNUNET_free (pts->credit_account.full_payto);
    364   GNUNET_free (pts);
    365 }
    366 
    367 
    368 struct TALER_TESTING_Command
    369 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   pts = GNUNET_new (struct PostTransfersState);
    381   pts->merchant_url = merchant_url;
    382   pts->auth = *auth;
    383   pts->payto_uri = payto_uri;
    384   TALER_full_payto_hash (payto_uri,
    385                          &pts->h_payto);
    386   TALER_full_payto_normalize_and_hash (payto_uri,
    387                                        &pts->h_normalized_payto);
    388   GNUNET_assert (GNUNET_OK ==
    389                  TALER_string_to_amount (credit_amount,
    390                                          &pts->credit_amount));
    391   pts->http_status = http_code;
    392   {
    393     const char *clabel;
    394     va_list ap;
    395 
    396     va_start (ap, http_code);
    397     while (NULL != (clabel = va_arg (ap, const char *)))
    398     {
    399       GNUNET_array_append (pts->deposits,
    400                            pts->deposits_length,
    401                            clabel);
    402     }
    403     va_end (ap);
    404   }
    405   {
    406     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     return cmd;
    415   }
    416 }
    417 
    418 
    419 struct TALER_TESTING_Command
    420 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   pts = GNUNET_new (struct PostTransfersState);
    432   pts->merchant_url = merchant_url;
    433   pts->credit_account.full_payto
    434     = GNUNET_strdup (payto_uri.full_payto);
    435   pts->exchange_url = GNUNET_strdup (exchange_url);
    436   GNUNET_assert (GNUNET_OK ==
    437                  TALER_string_to_amount (credit_amount,
    438                                          &pts->credit_amount));
    439   if (NULL == wtid)
    440   {
    441     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
    442                                 &pts->wtid,
    443                                 sizeof (pts->wtid));
    444   }
    445   else
    446   {
    447     GNUNET_assert (GNUNET_OK ==
    448                    GNUNET_STRINGS_string_to_data (wtid,
    449                                                   strlen (wtid),
    450                                                   &pts->wtid,
    451                                                   sizeof (pts->wtid)));
    452   }
    453   pts->http_status = http_code;
    454   {
    455     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     return cmd;
    464   }
    465 }
    466 
    467 
    468 void
    469 TALER_TESTING_cmd_merchant_post_transfer_set_serial (
    470   struct TALER_TESTING_Command *cmd,
    471   uint64_t serial)
    472 {
    473   struct PostTransfersState *pts = cmd->cls;
    474 
    475   GNUNET_assert (cmd->run = &post_transfers_run);
    476   pts->serial = serial;
    477 }
    478 
    479 
    480 /* end of testing_api_cmd_post_transfers.c */