LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_bank_history_credit.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 55.5 % 211 117
Test Date: 2025-12-26 23:00:34 Functions: 87.5 % 8 7

            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 "taler/platform.h"
      25              : #include "taler/taler_json_lib.h"
      26              : #include <gnunet/gnunet_curl_lib.h>
      27              : #include "taler/taler_exchange_service.h"
      28              : #include "taler/taler_testing_lib.h"
      29              : #include "taler/taler_fakebank_lib.h"
      30              : #include "taler/taler_bank_service.h"
      31              : #include "taler/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 2.0-1