LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_post_transfers.c (source / functions) Hit Total Coverage
Test: GNU Taler coverage report Lines: 0 88 0.0 %
Date: 2020-08-15 06:12:35 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2020 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 lib/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 (set once @e found is set).
      59             :    */
      60             :   char *exchange_url;
      61             : 
      62             :   /**
      63             :    * Payto URI to filter on.
      64             :    */
      65             :   const char *payto_uri;
      66             : 
      67             :   /**
      68             :    * Authentication details to authenticate to the bank.
      69             :    */
      70             :   struct TALER_BANK_AuthenticationData auth;
      71             : 
      72             :   /**
      73             :    * Set once we discovered the WTID and thus @e found is true.
      74             :    */
      75             :   struct TALER_WireTransferIdentifierRawP wtid;
      76             : 
      77             :   /**
      78             :    * the credit amount to look for at @e bank_url.
      79             :    */
      80             :   struct TALER_Amount credit_amount;
      81             : 
      82             :   /**
      83             :    * The fee incurred on the wire transfer.
      84             :    */
      85             :   struct TALER_Amount wire_fee;
      86             : 
      87             :   /**
      88             :    * Expected HTTP response code.
      89             :    */
      90             :   unsigned int http_status;
      91             : 
      92             :   /**
      93             :    * Array of deposit command labels we expect to see aggregated.
      94             :    */
      95             :   const char **deposits;
      96             : 
      97             :   /**
      98             :    * Length of @e deposits.
      99             :    */
     100             :   unsigned int deposits_length;
     101             : 
     102             :   /**
     103             :    * Set to true once @e wtid and @e exchange_url are initialized.
     104             :    */
     105             :   bool found;
     106             : 
     107             :   /**
     108             :    * When the exchange executed the transfer.
     109             :    */
     110             :   struct GNUNET_TIME_Absolute execution_time;
     111             : };
     112             : 
     113             : 
     114             : /**
     115             :  * Callback for a POST /transfers operation.
     116             :  *
     117             :  * @param cls closure for this function
     118             :  * @param hr HTTP response details
     119             :  * @param execution_time when did the transfer happen (according to the exchange),
     120             :  *          #GNUNET_TIME_UNIT_FOREVER_ABS if the transfer did not yet happen or if
     121             :  *          we have no data from the exchange about it
     122             :  * @param total_amount total amount of the wire transfer, or NULL if the exchange did
     123             :  *             not provide any details
     124             :  * @param wire_fee how much did the exchange charge in terms of wire fees, or NULL
     125             :  *             if the exchange did not provide any details
     126             :  * @param details_length length of the @a details array
     127             :  * @param details array with details about the combined transactions
     128             :  */
     129             : static void
     130           0 : transfers_cb (void *cls,
     131             :               const struct TALER_MERCHANT_HttpResponse *hr,
     132             :               struct GNUNET_TIME_Absolute execution_time,
     133             :               const struct TALER_Amount *total_amount,
     134             :               const struct TALER_Amount *wire_fee,
     135             :               unsigned int details_length,
     136             :               const struct TALER_MERCHANT_TrackTransferDetail details[])
     137             : {
     138           0 :   struct PostTransfersState *pts = cls;
     139             : 
     140           0 :   pts->pth = NULL;
     141           0 :   if (pts->http_status != hr->http_status)
     142             :   {
     143           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     144             :                 "Unexpected response code %u (%d) to command %s\n",
     145             :                 hr->http_status,
     146             :                 (int) hr->ec,
     147             :                 TALER_TESTING_interpreter_get_current_label (pts->is));
     148           0 :     TALER_TESTING_interpreter_fail (pts->is);
     149           0 :     return;
     150             :   }
     151           0 :   switch (hr->http_status)
     152             :   {
     153           0 :   case MHD_HTTP_OK:
     154             :     {
     155             :       // struct TALER_Amount total;
     156             : 
     157           0 :       pts->execution_time = execution_time;
     158           0 :       pts->wire_fee = *wire_fee;
     159             :       /*
     160             :       if (0 >
     161             :           TALER_amount_subtract (&total,
     162             :                                  total_amount,
     163             :                                  wire_fee))
     164             :       {
     165             :         GNUNET_break (0);
     166             :         TALER_TESTING_interpreter_fail (pts->is);
     167             :         return;
     168             :       }
     169             :       if (0 !=
     170             :           TALER_amount_cmp (&total,
     171             :                             &pts->credit_amount))
     172             :       {
     173             :         GNUNET_break (0);
     174             :         TALER_TESTING_interpreter_fail (pts->is);
     175             :         return;
     176             :       }
     177             :       TALER_amount_get_zero (total.currency,
     178             :                              &total);
     179             :       for (unsigned int i = 0; i<details_length; i++)
     180             :       {
     181             :         const struct TALER_MERCHANT_TrackTransferDetail *tdd = &details[i];
     182             :         struct TALER_Amount sum;
     183             :         struct TALER_Amount fees;
     184             : 
     185             :         TALER_amount_get_zero (tdd->deposit_value.currency,
     186             :                                &sum);
     187             :         TALER_amount_get_zero (tdd->deposit_fee.currency,
     188             :                                &fees);
     189             :         for (unsigned int j = 0; j<pts->deposits_length; j++)
     190             :         {
     191             :           const char *label = pts->deposits[j];
     192             :           const struct TALER_TESTING_Command *cmd;
     193             :           const json_t *contract_terms;
     194             :           const struct TALER_Amount *deposit_value;
     195             :           const struct TALER_Amount *deposit_fee;
     196             :           const char *order_id;
     197             : 
     198             :           cmd = TALER_TESTING_interpreter_lookup_command (pts->is,
     199             :                                                           label);
     200             :           if (NULL == cmd)
     201             :           {
     202             :             GNUNET_break (0);
     203             :             TALER_TESTING_interpreter_fail (pts->is);
     204             :             return;
     205             :           }
     206             :           if ( (GNUNET_OK !=
     207             :                 TALER_TESTING_get_trait_contract_terms (cmd,
     208             :                                                         0,
     209             :                                                         &contract_terms)) ||
     210             :                (GNUNET_OK !=
     211             :                 TALER_TESTING_get_trait_amount_obj (cmd,
     212             :                                                     TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_VALUE,
     213             :                                                     &deposit_value)) ||
     214             :                (GNUNET_OK !=
     215             :                 TALER_TESTING_get_trait_amount_obj (cmd,
     216             :                                                     TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_FEE,
     217             :                                                     &deposit_fee)) )
     218             :           {
     219             :             GNUNET_break (0);
     220             :             TALER_TESTING_interpreter_fail (pts->is);
     221             :             return;
     222             :           }
     223             :           order_id = json_string_value (json_object_get (contract_terms,
     224             :                                                          "order_id"));
     225             :           if (NULL == order_id)
     226             :           {
     227             :             GNUNET_break (0);
     228             :             TALER_TESTING_interpreter_fail (pts->is);
     229             :             return;
     230             :           }
     231             :           if (0 != strcmp (tdd->order_id,
     232             :                            order_id))
     233             :             continue;
     234             :           if (0 >
     235             :               TALER_amount_add (&sum,
     236             :                                 &sum,
     237             :                                 deposit_value))
     238             :           {
     239             :             GNUNET_break (0);
     240             :             TALER_TESTING_interpreter_fail (pts->is);
     241             :             return;
     242             :           }
     243             :           if (0 >
     244             :               TALER_amount_add (&fees,
     245             :                                 &fees,
     246             :                                 deposit_fee))
     247             :           {
     248             :             GNUNET_break (0);
     249             :             TALER_TESTING_interpreter_fail (pts->is);
     250             :             return;
     251             :           }
     252             :         }
     253             :         if (0 !=
     254             :             TALER_amount_cmp (&sum,
     255             :                               &tdd->deposit_value))
     256             :         {
     257             :           GNUNET_break (0);
     258             :           TALER_TESTING_interpreter_fail (pts->is);
     259             :           return;
     260             :         }
     261             :         if (0 !=
     262             :             TALER_amount_cmp (&fees,
     263             :                               &tdd->deposit_fee))
     264             :         {
     265             :           GNUNET_break (0);
     266             :           TALER_TESTING_interpreter_fail (pts->is);
     267             :           return;
     268             :         }
     269             :         GNUNET_assert (0 <=
     270             :                        TALER_amount_add (&total,
     271             :                                          &total,
     272             :                                          &tdd->deposit_value));
     273             :         GNUNET_assert (0 <=
     274             :                        TALER_amount_subtract (&total,
     275             :                                               &total,
     276             :                                               &tdd->deposit_fee));
     277             :       }
     278             :       if (0 !=
     279             :           TALER_amount_cmp (&total,
     280             :                             &pts->credit_amount))
     281             :       {
     282             :         GNUNET_break (0);
     283             :         TALER_TESTING_interpreter_fail (pts->is);
     284             :         return;
     285             :       }
     286           0 :       */break;
     287             :     }
     288           0 :   default:
     289           0 :     GNUNET_break (0);
     290           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     291             :                 "Unhandled HTTP status.\n");
     292             :   }
     293           0 :   TALER_TESTING_interpreter_next (pts->is);
     294             : }
     295             : 
     296             : 
     297             : /**
     298             :  * Offers information from the POST /transfers CMD state to other
     299             :  * commands.
     300             :  *
     301             :  * @param cls closure
     302             :  * @param ret[out] result (could be anything)
     303             :  * @param trait name of the trait
     304             :  * @param index index number of the object to extract.
     305             :  * @return #GNUNET_OK on success
     306             :  */
     307             : static int
     308           0 : post_transfers_traits (void *cls,
     309             :                        const void **ret,
     310             :                        const char *trait,
     311             :                        unsigned int index)
     312             : {
     313           0 :   struct PostTransfersState *pts = cls;
     314             :   struct TALER_TESTING_Trait traits[] = {
     315           0 :     TALER_TESTING_make_trait_wtid (0, &pts->wtid),
     316           0 :     TALER_TESTING_make_trait_string (0, pts->payto_uri),
     317           0 :     TALER_TESTING_make_trait_amount_obj (0, &pts->credit_amount),
     318           0 :     TALER_TESTING_make_trait_amount_obj (1, &pts->wire_fee),
     319           0 :     TALER_TESTING_make_trait_string (1, pts->exchange_url),
     320           0 :     TALER_TESTING_make_trait_absolute_time (0, &pts->execution_time),
     321           0 :     TALER_TESTING_trait_end (),
     322             :   };
     323             : 
     324           0 :   return TALER_TESTING_get_trait (traits,
     325             :                                   ret,
     326             :                                   trait,
     327             :                                   index);
     328             : }
     329             : 
     330             : 
     331             : /**
     332             :  * Callbacks of this type are used to serve the result of asking
     333             :  * the bank for the debit transaction history.
     334             :  *
     335             :  * @param cls closure with a `struct PostTransfersState *`
     336             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
     337             :  *                    0 if the bank's reply is bogus (fails to follow the protocol),
     338             :  *                    #MHD_HTTP_NO_CONTENT if there are no more results; on success the
     339             :  *                    last callback is always of this status (even if `abs(num_results)` were
     340             :  *                    already returned).
     341             :  * @param ec detailed error code
     342             :  * @param serial_id monotonically increasing counter corresponding to the transaction
     343             :  * @param details details about the wire transfer
     344             :  * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
     345             :  * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
     346             :  */
     347             : static int
     348           0 : debit_cb (
     349             :   void *cls,
     350             :   unsigned int http_status,
     351             :   enum TALER_ErrorCode ec,
     352             :   uint64_t serial_id,
     353             :   const struct TALER_BANK_DebitDetails *details,
     354             :   const json_t *json)
     355             : {
     356           0 :   struct PostTransfersState *pts = cls;
     357             : 
     358           0 :   if (MHD_HTTP_NO_CONTENT == http_status)
     359             :   {
     360           0 :     pts->dhh = NULL;
     361           0 :     if (! pts->found)
     362             :     {
     363           0 :       GNUNET_break (0);
     364           0 :       TALER_TESTING_interpreter_fail (pts->is);
     365           0 :       return GNUNET_OK;
     366             :     }
     367           0 :     GNUNET_assert (NULL != pts->exchange_url);
     368           0 :     pts->pth = TALER_MERCHANT_transfers_post (pts->is->ctx,
     369             :                                               pts->merchant_url,
     370           0 :                                               &pts->credit_amount,
     371           0 :                                               &pts->wtid,
     372             :                                               pts->payto_uri,
     373           0 :                                               pts->exchange_url,
     374             :                                               &transfers_cb,
     375             :                                               pts);
     376           0 :     return GNUNET_OK;
     377             :   }
     378           0 :   if (MHD_HTTP_OK != http_status)
     379             :   {
     380           0 :     GNUNET_break (0);
     381           0 :     TALER_TESTING_interpreter_fail (pts->is);
     382           0 :     pts->dhh = NULL;
     383           0 :     return GNUNET_SYSERR;
     384             :   }
     385           0 :   if (pts->found)
     386           0 :     return GNUNET_OK;
     387           0 :   if (0 != TALER_amount_cmp (&pts->credit_amount,
     388             :                              &details->amount))
     389           0 :     return GNUNET_OK;
     390           0 :   if ( (NULL != pts->payto_uri) &&
     391           0 :        (0 != strcasecmp (pts->payto_uri,
     392             :                          details->credit_account_url)) )
     393           0 :     return GNUNET_OK;
     394           0 :   pts->found = true;
     395           0 :   pts->wtid = details->wtid;
     396           0 :   pts->exchange_url = GNUNET_strdup (details->exchange_base_url);
     397           0 :   return GNUNET_OK;
     398             : }
     399             : 
     400             : 
     401             : /**
     402             :  * Run the "POST /transfers" CMD. First, get the bank history to find
     403             :  * the wtid.
     404             :  *
     405             :  * @param cls closure.
     406             :  * @param cmd command being run now.
     407             :  * @param is interpreter state.
     408             :  */
     409             : static void
     410           0 : post_transfers_run (void *cls,
     411             :                     const struct TALER_TESTING_Command *cmd,
     412             :                     struct TALER_TESTING_Interpreter *is)
     413             : {
     414           0 :   struct PostTransfersState *pts = cls;
     415             : 
     416           0 :   pts->is = is;
     417           0 :   pts->dhh = TALER_BANK_debit_history (is->ctx,
     418           0 :                                        &pts->auth,
     419             :                                        UINT64_MAX,
     420             :                                        -INT64_MAX,
     421             :                                        &debit_cb,
     422             :                                        pts);
     423           0 :   GNUNET_assert (NULL != pts->dhh);
     424           0 : }
     425             : 
     426             : 
     427             : /**
     428             :  * Free the state of a "POST product" CMD, and possibly
     429             :  * cancel a pending operation thereof.
     430             :  *
     431             :  * @param cls closure.
     432             :  * @param cmd command being run.
     433             :  */
     434             : static void
     435           0 : post_transfers_cleanup (void *cls,
     436             :                         const struct TALER_TESTING_Command *cmd)
     437             : {
     438           0 :   struct PostTransfersState *pts = cls;
     439             : 
     440           0 :   if (NULL != pts->pth)
     441             :   {
     442           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     443             :                 "POST /transfers operation did not complete\n");
     444           0 :     TALER_MERCHANT_transfers_post_cancel (pts->pth);
     445             :   }
     446           0 :   if (NULL != pts->dhh)
     447             :   {
     448           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     449             :                 "GET debit history operation did not complete\n");
     450           0 :     TALER_BANK_debit_history_cancel (pts->dhh);
     451             :   }
     452           0 :   GNUNET_array_grow (pts->deposits,
     453             :                      pts->deposits_length,
     454             :                      0);
     455           0 :   GNUNET_free (pts->exchange_url);
     456           0 :   GNUNET_free (pts);
     457           0 : }
     458             : 
     459             : 
     460             : /**
     461             :  * Define a POST /transfers CMD.  Details like the WTID and
     462             :  * other required parameters will be extracted from the bank
     463             :  * history, using the latest transfer of the specified
     464             :  * @a credit_amount to the @a merchant_url.
     465             :  *
     466             :  * @param label command label.
     467             :  * @param merchant_url base URL of the backend serving the
     468             :  *        "refund increase" request.
     469             :  * @param auth credentials to access the exchange's bank account
     470             :  * @param payto_rui URL of the exchange's bank account
     471             :  * @param credit_amount amount credited
     472             :  * @param http_code expected HTTP response code
     473             :  * @param ... NULL-terminated list of labels (const char *) of
     474             :  *        deposit (commands) we expect to be aggregated in the transfer
     475             :  *        (assuming @a http_code is #MHD_HTTP_OK)
     476             :  * @return the command.
     477             :  */
     478             : struct TALER_TESTING_Command
     479           0 : TALER_TESTING_cmd_merchant_post_transfer (
     480             :   const char *label,
     481             :   const struct TALER_BANK_AuthenticationData *auth,
     482             :   const char *payto_uri,
     483             :   const char *merchant_url,
     484             :   const char *credit_amount,
     485             :   unsigned int http_code,
     486             :   ...)
     487             : {
     488             :   struct PostTransfersState *pts;
     489             : 
     490           0 :   pts = GNUNET_new (struct PostTransfersState);
     491           0 :   pts->merchant_url = merchant_url;
     492           0 :   pts->auth = *auth;
     493           0 :   pts->payto_uri = payto_uri;
     494           0 :   GNUNET_assert (GNUNET_OK ==
     495             :                  TALER_string_to_amount (credit_amount,
     496             :                                          &pts->credit_amount));
     497           0 :   pts->http_status = http_code;
     498             :   {
     499             :     const char *clabel;
     500             :     va_list ap;
     501             : 
     502           0 :     va_start (ap, http_code);
     503           0 :     while (NULL != (clabel = va_arg (ap, const char *)))
     504             :     {
     505           0 :       GNUNET_array_append (pts->deposits,
     506             :                            pts->deposits_length,
     507             :                            clabel);
     508             :     }
     509           0 :     va_end (ap);
     510             :   }
     511             :   {
     512           0 :     struct TALER_TESTING_Command cmd = {
     513             :       .cls = pts,
     514             :       .label = label,
     515             :       .run = &post_transfers_run,
     516             :       .cleanup = &post_transfers_cleanup,
     517             :       .traits = &post_transfers_traits
     518             :     };
     519             : 
     520           0 :     return cmd;
     521             :   }
     522             : }
     523             : 
     524             : 
     525             : /* end of testing_api_cmd_post_transfers.c */

Generated by: LCOV version 1.14