LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_bank_history_credit.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 117 211 55.5 %
Date: 2025-06-05 21:03:14 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2018-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/testing_api_cmd_bank_history_credit.c
      21             :  * @brief command to check the /history/incoming API from the bank.
      22             :  * @author Marcello Stanisci
      23             :  */
      24             : #include "platform.h"
      25             : #include "taler_json_lib.h"
      26             : #include <gnunet/gnunet_curl_lib.h>
      27             : #include "taler_exchange_service.h"
      28             : #include "taler_testing_lib.h"
      29             : #include "taler_fakebank_lib.h"
      30             : #include "taler_bank_service.h"
      31             : #include "taler_fakebank_lib.h"
      32             : 
      33             : 
      34             : /**
      35             :  * Item in the transaction history, as reconstructed from the
      36             :  * command history.
      37             :  */
      38             : struct History
      39             : {
      40             : 
      41             :   /**
      42             :    * Wire details.
      43             :    */
      44             :   struct TALER_BANK_CreditDetails credit_details;
      45             : 
      46             :   /**
      47             :    * Serial ID of the wire transfer.
      48             :    */
      49             :   uint64_t row_id;
      50             : 
      51             :   /**
      52             :    * URL to free.
      53             :    */
      54             :   char *url;
      55             : };
      56             : 
      57             : 
      58             : /**
      59             :  * State for a "history" CMD.
      60             :  */
      61             : struct HistoryState
      62             : {
      63             :   /**
      64             :    * Base URL of the account offering the "history" operation.
      65             :    */
      66             :   char *account_url;
      67             : 
      68             :   /**
      69             :    * Reference to command defining the
      70             :    * first row number we want in the result.
      71             :    */
      72             :   const char *start_row_reference;
      73             : 
      74             :   /**
      75             :    * How many rows we want in the result, _at most_,
      76             :    * and ascending/descending.
      77             :    */
      78             :   long long num_results;
      79             : 
      80             :   /**
      81             :    * Handle to a pending "history" operation.
      82             :    */
      83             :   struct TALER_BANK_CreditHistoryHandle *hh;
      84             : 
      85             :   /**
      86             :    * The interpreter.
      87             :    */
      88             :   struct TALER_TESTING_Interpreter *is;
      89             : 
      90             :   /**
      91             :    * Authentication data for the operation.
      92             :    */
      93             :   struct TALER_BANK_AuthenticationData auth;
      94             : 
      95             :   /**
      96             :    * Expected number of results (= rows).
      97             :    */
      98             :   uint64_t results_obtained;
      99             : 
     100             :   /**
     101             :    * Set to true if the callback detects something
     102             :    * unexpected.
     103             :    */
     104             :   bool failed;
     105             : 
     106             :   /**
     107             :    * Expected history.
     108             :    */
     109             :   struct History *h;
     110             : 
     111             :   /**
     112             :    * Length of @e h
     113             :    */
     114             :   unsigned int total;
     115             : 
     116             : };
     117             : 
     118             : 
     119             : /**
     120             :  * Log which history we expected.  Called when an error occurs.
     121             :  *
     122             :  * @param h what we expected.
     123             :  * @param h_len number of entries in @a h.
     124             :  * @param off position of the mismatch.
     125             :  */
     126             : static void
     127           0 : print_expected (struct History *h,
     128             :                 unsigned int h_len,
     129             :                 unsigned int off)
     130             : {
     131           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     132             :               "Transaction history (credit) mismatch at position %u/%u\n",
     133             :               off,
     134             :               h_len);
     135           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     136             :               "Expected history:\n");
     137           0 :   for (unsigned int i = 0; i<h_len; i++)
     138             :   {
     139           0 :     const struct TALER_BANK_CreditDetails *cd
     140           0 :       = &h[i].credit_details;
     141             : 
     142           0 :     switch (cd->type)
     143             :     {
     144           0 :     case TALER_BANK_CT_RESERVE:
     145           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     146             :                   "H(%u): %s (serial: %llu, RES: %s,"
     147             :                   " counterpart: %s)\n",
     148             :                   i,
     149             :                   TALER_amount2s (&cd->amount),
     150             :                   (unsigned long long) h[i].row_id,
     151             :                   TALER_B2S (&cd->details.reserve.reserve_pub),
     152             :                   cd->debit_account_uri.full_payto);
     153           0 :       break;
     154           0 :     case TALER_BANK_CT_KYCAUTH:
     155           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     156             :                   "H(%u): %s (serial: %llu, KYC: %s,"
     157             :                   " counterpart: %s)\n",
     158             :                   i,
     159             :                   TALER_amount2s (&cd->amount),
     160             :                   (unsigned long long) h[i].row_id,
     161             :                   TALER_B2S (&cd->details.kycauth.account_pub),
     162             :                   cd->debit_account_uri.full_payto);
     163           0 :       break;
     164           0 :     case TALER_BANK_CT_WAD:
     165           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     166             :                   "H(%u): %s (serial: %llu, WAD: %s-%s,"
     167             :                   " counterpart: %s)\n",
     168             :                   i,
     169             :                   TALER_amount2s (&cd->amount),
     170             :                   (unsigned long long) h[i].row_id,
     171             :                   TALER_B2S (&cd->details.wad.wad_id),
     172             :                   cd->details.wad.origin_exchange_url,
     173             :                   cd->debit_account_uri.full_payto);
     174           0 :       break;
     175             :     }
     176             :   }
     177           0 : }
     178             : 
     179             : 
     180             : /**
     181             :  * Closure for command_cb().
     182             :  */
     183             : struct IteratorContext
     184             : {
     185             :   /**
     186             :    * Array of history items to return.
     187             :    */
     188             :   struct History *h;
     189             : 
     190             :   /**
     191             :    * Set to the row ID from where on we should actually process history items,
     192             :    * or NULL if we should process all of them.
     193             :    */
     194             :   const uint64_t *row_id_start;
     195             : 
     196             :   /**
     197             :    * History state we are working on.
     198             :    */
     199             :   struct HistoryState *hs;
     200             : 
     201             :   /**
     202             :    * Current length of the @e h array.
     203             :    */
     204             :   unsigned int total;
     205             : 
     206             :   /**
     207             :    * Current write position in @e h array.
     208             :    */
     209             :   unsigned int pos;
     210             : 
     211             :   /**
     212             :    * Ok equals True whenever a starting row_id was provided AND was found
     213             :    * among the CMDs, OR no starting row was given in the first place.
     214             :    */
     215             :   bool ok;
     216             : 
     217             : };
     218             : 
     219             : 
     220             : /**
     221             :  * Helper function of build_history() that expands
     222             :  * the history for each relevant command encountered.
     223             :  *
     224             :  * @param[in,out] cls our `struct IteratorContext`
     225             :  * @param cmd a command to process
     226             :  */
     227             : static void
     228          14 : command_cb (void *cls,
     229             :             const struct TALER_TESTING_Command *cmd)
     230             : {
     231          14 :   struct IteratorContext *ic = cls;
     232          14 :   struct HistoryState *hs = ic->hs;
     233             :   const uint64_t *row_id;
     234             :   const struct TALER_FullPayto *credit_account;
     235             :   const struct TALER_FullPayto *debit_account;
     236             :   const struct TALER_Amount *amount;
     237             :   const struct TALER_ReservePublicKeyP *reserve_pub;
     238             :   const char *exchange_credit_url;
     239             : 
     240             :   /**
     241             :    * The following command allows us to skip over those CMDs
     242             :    * that do not offer a "row_id" trait.  Such skipped CMDs are
     243             :    * not interesting for building a history.
     244             :    */
     245          14 :   if ( (GNUNET_OK !=
     246          14 :         TALER_TESTING_get_trait_bank_row (cmd,
     247           2 :                                           &row_id)) ||
     248             :        (GNUNET_OK !=
     249           2 :         TALER_TESTING_get_trait_credit_payto_uri (cmd,
     250           2 :                                                   &credit_account)) ||
     251             :        (GNUNET_OK !=
     252           2 :         TALER_TESTING_get_trait_debit_payto_uri (cmd,
     253           2 :                                                  &debit_account)) ||
     254             :        (GNUNET_OK !=
     255           2 :         TALER_TESTING_get_trait_amount (cmd,
     256           2 :                                         &amount)) ||
     257             :        (GNUNET_OK !=
     258           2 :         TALER_TESTING_get_trait_reserve_pub (cmd,
     259           2 :                                              &reserve_pub)) ||
     260             :        (GNUNET_OK !=
     261           2 :         TALER_TESTING_get_trait_exchange_bank_account_url (
     262             :           cmd,
     263             :           &exchange_credit_url)) )
     264          12 :     return;   // Not an interesting event
     265             :   // FIXME: support KYCAUTH transfer events!
     266             :   // FIXME-#7271: support WAD transfer events!
     267             : 
     268             :   /**
     269             :    * Is the interesting event a match with regard to
     270             :    * the row_id value?  If yes, store this condition
     271             :    * to the state and analyze the next CMDs.
     272             :    */
     273           2 :   if ( (NULL != ic->row_id_start) &&
     274           0 :        (*(ic->row_id_start) == *row_id) &&
     275           0 :        (! ic->ok) )
     276             :   {
     277           0 :     ic->ok = true;
     278           0 :     return;
     279             :   }
     280             :   /**
     281             :    * The interesting event didn't match the wanted
     282             :    * row_id value, analyze the next CMDs.  Note: this
     283             :    * branch is relevant only when row_id WAS given.
     284             :    */
     285           2 :   if (! ic->ok)
     286           0 :     return;
     287           2 :   if (0 != strcasecmp (hs->account_url,
     288             :                        exchange_credit_url))
     289           0 :     return;   // Account mismatch
     290           2 :   if (ic->total >= GNUNET_MAX (hs->num_results,
     291             :                                -hs->num_results) )
     292             :   {
     293           0 :     TALER_LOG_DEBUG ("Hit history limit\n");
     294           0 :     return;
     295             :   }
     296           2 :   TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
     297             :                   debit_account->full_payto,
     298             :                   credit_account->full_payto,
     299             :                   hs->account_url);
     300             :   /* found matching record, make sure we have room */
     301           2 :   if (ic->pos == ic->total)
     302           0 :     GNUNET_array_grow (ic->h,
     303             :                        ic->total,
     304             :                        ic->pos * 2);
     305           2 :   ic->h[ic->pos].url
     306           2 :     = GNUNET_strdup (debit_account->full_payto);
     307           2 :   ic->h[ic->pos].row_id
     308           2 :     = *row_id;
     309           2 :   ic->h[ic->pos].credit_details.type
     310           2 :     = TALER_BANK_CT_RESERVE;
     311           2 :   ic->h[ic->pos].credit_details.debit_account_uri.full_payto
     312           2 :     = ic->h[ic->pos].url;
     313           2 :   ic->h[ic->pos].credit_details.amount
     314           2 :     = *amount;
     315           2 :   ic->h[ic->pos].credit_details.details.reserve.reserve_pub
     316           2 :     = *reserve_pub;
     317           2 :   ic->pos++;
     318             : }
     319             : 
     320             : 
     321             : /**
     322             :  * This function constructs the list of history elements that
     323             :  * interest the account number of the caller.  It has two main
     324             :  * loops: the first to figure out how many history elements have
     325             :  * to be allocated, and the second to actually populate every
     326             :  * element.
     327             :  *
     328             :  * @param hs history state
     329             :  * @param[out] rh history array to initialize.
     330             :  * @return number of entries in @a rh.
     331             :  */
     332             : static unsigned int
     333           4 : build_history (struct HistoryState *hs,
     334             :                struct History **rh)
     335             : {
     336           4 :   struct TALER_TESTING_Interpreter *is = hs->is;
     337           4 :   struct IteratorContext ic = {
     338             :     .hs = hs
     339             :   };
     340             : 
     341           4 :   if (NULL != hs->start_row_reference)
     342             :   {
     343             :     const struct TALER_TESTING_Command *add_incoming_cmd;
     344             : 
     345           0 :     TALER_LOG_INFO ("`%s': start row given via reference `%s'\n",
     346             :                     TALER_TESTING_interpreter_get_current_label (is),
     347             :                     hs->start_row_reference);
     348             :     add_incoming_cmd
     349           0 :       = TALER_TESTING_interpreter_lookup_command (is,
     350             :                                                   hs->start_row_reference);
     351           0 :     GNUNET_assert (NULL != add_incoming_cmd);
     352           0 :     GNUNET_assert (GNUNET_OK ==
     353             :                    TALER_TESTING_get_trait_row (add_incoming_cmd,
     354             :                                                 &ic.row_id_start));
     355             :   }
     356             : 
     357           4 :   ic.ok = false;
     358           4 :   if (NULL == ic.row_id_start)
     359           4 :     ic.ok = true;
     360           4 :   GNUNET_array_grow (ic.h,
     361             :                      ic.total,
     362             :                      4);
     363           4 :   GNUNET_assert (0 != hs->num_results);
     364           4 :   TALER_TESTING_iterate (is,
     365           4 :                          hs->num_results > 0,
     366             :                          &command_cb,
     367             :                          &ic);
     368           4 :   GNUNET_assert (ic.ok);
     369           4 :   GNUNET_array_grow (ic.h,
     370             :                      ic.total,
     371             :                      ic.pos);
     372           4 :   if (0 == ic.pos)
     373           2 :     TALER_LOG_DEBUG ("Empty credit history computed\n");
     374           4 :   *rh = ic.h;
     375           4 :   return ic.pos;
     376             : }
     377             : 
     378             : 
     379             : /**
     380             :  * Check that the "/history/incoming" response matches the
     381             :  * CMD whose offset in the list of CMDs is @a off.
     382             :  *
     383             :  * @param h expected history (array)
     384             :  * @param total length of @a h
     385             :  * @param off the offset (of the CMD list) where the command
     386             :  *        to check is.
     387             :  * @param credit_details the expected transaction details.
     388             :  * @return #GNUNET_OK if the transaction is what we expect.
     389             :  */
     390             : static enum GNUNET_GenericReturnValue
     391           2 : check_result (struct History *h,
     392             :               unsigned int total,
     393             :               unsigned int off,
     394             :               const struct TALER_BANK_CreditDetails *credit_details)
     395             : {
     396           2 :   if (off >= total)
     397             :   {
     398           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     399             :                 "Test says history has at most %u"
     400             :                 " results, but got result #%u to check\n",
     401             :                 total,
     402             :                 off);
     403           0 :     print_expected (h,
     404             :                     total,
     405             :                     off);
     406           0 :     return GNUNET_SYSERR;
     407             :   }
     408           2 :   if ( (h[off].credit_details.type !=
     409           4 :         credit_details->type) ||
     410           2 :        (0 != TALER_amount_cmp (&h[off].credit_details.amount,
     411           2 :                                &credit_details->amount)) ||
     412           2 :        (0 != TALER_full_payto_normalize_and_cmp (
     413           2 :           h[off].credit_details.debit_account_uri,
     414             :           credit_details->debit_account_uri)) )
     415             :   {
     416           0 :     GNUNET_break (0);
     417           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     418             :                 "expected debit_account_uri: %s with %s\n",
     419             :                 h[off].credit_details.debit_account_uri.full_payto,
     420             :                 TALER_amount2s (&h[off].credit_details.amount));
     421           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     422             :                 "actual debit_account_uri: %s with %s\n",
     423             :                 credit_details->debit_account_uri.full_payto,
     424             :                 TALER_amount2s (&credit_details->amount));
     425           0 :     print_expected (h,
     426             :                     total,
     427             :                     off);
     428           0 :     return GNUNET_SYSERR;
     429             :   }
     430           2 :   switch (credit_details->type)
     431             :   {
     432           2 :   case TALER_BANK_CT_RESERVE:
     433           2 :     if (0 !=
     434           2 :         GNUNET_memcmp (&h[off].credit_details.details.reserve.reserve_pub,
     435             :                        &credit_details->details.reserve.reserve_pub))
     436             :     {
     437           0 :       GNUNET_break (0);
     438           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     439             :                   "expected debit_account_uri: %s with %s for %s\n",
     440             :                   h[off].credit_details.debit_account_uri.full_payto,
     441             :                   TALER_amount2s (&h[off].credit_details.amount),
     442             :                   TALER_B2S (&h[off].credit_details.details.reserve.reserve_pub)
     443             :                   );
     444           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     445             :                   "actual debit_account_uri: %s with %s for %s\n",
     446             :                   credit_details->debit_account_uri.full_payto,
     447             :                   TALER_amount2s (&credit_details->amount),
     448             :                   TALER_B2S (&credit_details->details.reserve.reserve_pub));
     449           0 :       print_expected (h,
     450             :                       total,
     451             :                       off);
     452           0 :       return GNUNET_SYSERR;
     453             :     }
     454           2 :     break;
     455           0 :   case TALER_BANK_CT_KYCAUTH:
     456           0 :     if (0 != GNUNET_memcmp (&h[off].credit_details.details.kycauth.account_pub,
     457             :                             &credit_details->details.kycauth.account_pub))
     458             :     {
     459           0 :       GNUNET_break (0);
     460           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     461             :                   "expected debit_account_uri: %s with %s for %s\n",
     462             :                   h[off].credit_details.debit_account_uri.full_payto,
     463             :                   TALER_amount2s (&h[off].credit_details.amount),
     464             :                   TALER_B2S (&h[off].credit_details.details.kycauth.account_pub)
     465             :                   );
     466           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     467             :                   "actual debit_account_uri: %s with %s for %s\n",
     468             :                   credit_details->debit_account_uri.full_payto,
     469             :                   TALER_amount2s (&credit_details->amount),
     470             :                   TALER_B2S (&credit_details->details.kycauth.account_pub));
     471           0 :       print_expected (h,
     472             :                       total,
     473             :                       off);
     474           0 :       return GNUNET_SYSERR;
     475             :     }
     476           0 :     break;
     477           0 :   case TALER_BANK_CT_WAD:
     478           0 :     if ( (0 != GNUNET_memcmp (&h[off].credit_details.details.wad.wad_id,
     479           0 :                               &credit_details->details.wad.wad_id)) ||
     480           0 :          (0 != strcmp (h[off].credit_details.details.wad.origin_exchange_url,
     481           0 :                        credit_details->details.wad.origin_exchange_url)) )
     482             :     {
     483           0 :       GNUNET_break (0);
     484           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     485             :                   "expected debit_account_uri: %s with %s for %s-%s\n",
     486             :                   h[off].credit_details.debit_account_uri.full_payto,
     487             :                   TALER_amount2s (&h[off].credit_details.amount),
     488             :                   h[off].credit_details.details.wad.origin_exchange_url,
     489             :                   TALER_B2S (&h[off].credit_details.details.wad.wad_id));
     490           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     491             :                   "actual debit_account_uri: %s with %s for %s-%s\n",
     492             :                   credit_details->debit_account_uri.full_payto,
     493             :                   TALER_amount2s (&credit_details->amount),
     494             :                   credit_details->details.wad.origin_exchange_url,
     495             :                   TALER_B2S (&credit_details->details.wad.wad_id));
     496           0 :       print_expected (h,
     497             :                       total,
     498             :                       off);
     499           0 :       return GNUNET_SYSERR;
     500             :     }
     501           0 :     break;
     502             :   }
     503           2 :   return GNUNET_OK;
     504             : }
     505             : 
     506             : 
     507             : /**
     508             :  * This callback will (1) check that the HTTP response code
     509             :  * is acceptable and (2) that the history is consistent.  The
     510             :  * consistency is checked by going through all the past CMDs,
     511             :  * reconstructing then the expected history as of those, and
     512             :  * finally check it against what the bank returned.
     513             :  *
     514             :  * @param cls closure.
     515             :  * @param chr http response details
     516             :  */
     517             : static void
     518           4 : history_cb (void *cls,
     519             :             const struct TALER_BANK_CreditHistoryResponse *chr)
     520             : {
     521           4 :   struct HistoryState *hs = cls;
     522           4 :   struct TALER_TESTING_Interpreter *is = hs->is;
     523             : 
     524           4 :   hs->hh = NULL;
     525           4 :   switch (chr->http_status)
     526             :   {
     527           0 :   case 0:
     528           0 :     GNUNET_break (0);
     529           0 :     goto error;
     530           2 :   case MHD_HTTP_OK:
     531           4 :     for (unsigned int i = 0; i<chr->details.ok.details_length; i++)
     532             :     {
     533           2 :       const struct TALER_BANK_CreditDetails *cd =
     534           2 :         &chr->details.ok.details[i];
     535             : 
     536             :       /* check current element */
     537           2 :       if (GNUNET_OK !=
     538           2 :           check_result (hs->h,
     539             :                         hs->total,
     540           2 :                         hs->results_obtained,
     541             :                         cd))
     542             :       {
     543           0 :         GNUNET_break (0);
     544           0 :         json_dumpf (chr->response,
     545             :                     stderr,
     546             :                     JSON_COMPACT);
     547           0 :         hs->failed = true;
     548           0 :         hs->hh = NULL;
     549           0 :         TALER_TESTING_interpreter_fail (is);
     550           0 :         return;
     551             :       }
     552           2 :       hs->results_obtained++;
     553             :     }
     554           2 :     TALER_TESTING_interpreter_next (is);
     555           2 :     return;
     556           1 :   case MHD_HTTP_NO_CONTENT:
     557           1 :     if (0 == hs->total)
     558             :     {
     559             :       /* not found is OK for empty history */
     560           1 :       TALER_TESTING_interpreter_next (is);
     561           1 :       return;
     562             :     }
     563           0 :     GNUNET_break (0);
     564           0 :     goto error;
     565           1 :   case MHD_HTTP_NOT_FOUND:
     566           1 :     if (0 == hs->total)
     567             :     {
     568             :       /* not found is OK for empty history */
     569           1 :       TALER_TESTING_interpreter_next (is);
     570           1 :       return;
     571             :     }
     572           0 :     GNUNET_break (0);
     573           0 :     goto error;
     574           0 :   default:
     575           0 :     hs->hh = NULL;
     576           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     577             :                 "Unwanted response code from /history/incoming: %u\n",
     578             :                 chr->http_status);
     579           0 :     TALER_TESTING_interpreter_fail (is);
     580           0 :     return;
     581             :   }
     582           0 : error:
     583           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     584             :               "Expected history of length %u, got %llu;"
     585             :               " HTTP status code: %u/%d, failed: %d\n",
     586             :               hs->total,
     587             :               (unsigned long long) hs->results_obtained,
     588             :               chr->http_status,
     589             :               (int) chr->ec,
     590             :               hs->failed ? 1 : 0);
     591           0 :   print_expected (hs->h,
     592             :                   hs->total,
     593             :                   UINT_MAX);
     594           0 :   TALER_TESTING_interpreter_fail (is);
     595             : }
     596             : 
     597             : 
     598             : /**
     599             :  * Run the command.
     600             :  *
     601             :  * @param cls closure.
     602             :  * @param cmd the command to execute.
     603             :  * @param is the interpreter state.
     604             :  */
     605             : static void
     606           4 : history_run (void *cls,
     607             :              const struct TALER_TESTING_Command *cmd,
     608             :              struct TALER_TESTING_Interpreter *is)
     609             : {
     610           4 :   struct HistoryState *hs = cls;
     611           4 :   uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
     612             :   const uint64_t *row_ptr;
     613             : 
     614             :   (void) cmd;
     615           4 :   hs->is = is;
     616             :   /* Get row_id from trait. */
     617           4 :   if (NULL != hs->start_row_reference)
     618             :   {
     619             :     const struct TALER_TESTING_Command *history_cmd;
     620             : 
     621           0 :     history_cmd = TALER_TESTING_interpreter_lookup_command (
     622             :       is,
     623             :       hs->start_row_reference);
     624           0 :     if (NULL == history_cmd)
     625           0 :       TALER_TESTING_FAIL (is);
     626             : 
     627           0 :     if (GNUNET_OK !=
     628           0 :         TALER_TESTING_get_trait_row (history_cmd,
     629             :                                      &row_ptr))
     630           0 :       TALER_TESTING_FAIL (is);
     631             :     else
     632           0 :       row_id = *row_ptr;
     633           0 :     TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
     634             :                      (unsigned long long) row_id);
     635             :   }
     636           4 :   hs->total = build_history (hs,
     637             :                              &hs->h);
     638           4 :   hs->hh = TALER_BANK_credit_history (
     639             :     TALER_TESTING_interpreter_get_context (is),
     640           4 :     &hs->auth,
     641             :     row_id,
     642           4 :     hs->num_results,
     643           4 :     GNUNET_TIME_UNIT_ZERO,
     644             :     &history_cb,
     645             :     hs);
     646           4 :   GNUNET_assert (NULL != hs->hh);
     647             : }
     648             : 
     649             : 
     650             : /**
     651             :  * Free the state from a "history" CMD, and possibly cancel
     652             :  * a pending operation thereof.
     653             :  *
     654             :  * @param cls closure.
     655             :  * @param cmd the command which is being cleaned up.
     656             :  */
     657             : static void
     658           4 : history_cleanup (void *cls,
     659             :                  const struct TALER_TESTING_Command *cmd)
     660             : {
     661           4 :   struct HistoryState *hs = cls;
     662             : 
     663             :   (void) cmd;
     664           4 :   if (NULL != hs->hh)
     665             :   {
     666           0 :     TALER_TESTING_command_incomplete (hs->is,
     667             :                                       cmd->label);
     668           0 :     TALER_BANK_credit_history_cancel (hs->hh);
     669             :   }
     670           4 :   GNUNET_free (hs->account_url);
     671           6 :   for (unsigned int off = 0; off<hs->total; off++)
     672           2 :     GNUNET_free (hs->h[off].url);
     673           4 :   GNUNET_free (hs->h);
     674           4 :   GNUNET_free (hs);
     675           4 : }
     676             : 
     677             : 
     678             : struct TALER_TESTING_Command
     679           4 : TALER_TESTING_cmd_bank_credits (
     680             :   const char *label,
     681             :   const struct TALER_BANK_AuthenticationData *auth,
     682             :   const char *start_row_reference,
     683             :   long long num_results)
     684             : {
     685             :   struct HistoryState *hs;
     686             : 
     687           4 :   hs = GNUNET_new (struct HistoryState);
     688           4 :   hs->account_url = GNUNET_strdup (auth->wire_gateway_url);
     689           4 :   hs->start_row_reference = start_row_reference;
     690           4 :   hs->num_results = num_results;
     691           4 :   hs->auth = *auth;
     692             :   {
     693           4 :     struct TALER_TESTING_Command cmd = {
     694             :       .label = label,
     695             :       .cls = hs,
     696             :       .run = &history_run,
     697             :       .cleanup = &history_cleanup
     698             :     };
     699             : 
     700           4 :     return cmd;
     701             :   }
     702             : }
     703             : 
     704             : 
     705             : /* end of testing_api_cmd_credit_history.c */

Generated by: LCOV version 1.16