LCOV - code coverage report
Current view: top level - exchangedb - test_aggregation_tracking.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 142 142
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file exchangedb/test_aggregation_tracking.c
      18              :  * @brief tests for the exchangedb functions whose primary table is
      19              :  *        `aggregation_tracking`
      20              :  * @author Christian Grothoff
      21              :  *
      22              :  * Covers #TALER_EXCHANGEDB_do_aggregate(),
      23              :  * #TALER_EXCHANGEDB_get_pending_aggregation(),
      24              :  * #TALER_EXCHANGEDB_get_transfer_by_deposit(),
      25              :  * #TALER_EXCHANGEDB_iterate_aggregation_wtids_above_serial_id(),
      26              :  * #TALER_EXCHANGEDB_iterate_aggregations_above_serial_id() and
      27              :  * #TALER_EXCHANGEDB_iterate_wire_transfers().
      28              :  *
      29              :  * `aggregation_tracking` records which deposit went into which wire
      30              :  * transfer.  do_aggregate() writes it, netting deposits against refunds and
      31              :  * charging the deposit fee only for coins that were not refunded in full --
      32              :  * the checks below pin that arithmetic down.
      33              :  */
      34              : #include "test_common.h"
      35              : #include "exchange-database/do_aggregate.h"
      36              : #include "exchange-database/do_refund.h"
      37              : #include "exchange-database/get_pending_aggregation.h"
      38              : #include "exchange-database/get_transfer_by_deposit.h"
      39              : #include "exchange-database/insert_wire_out.h"
      40              : #include "exchange-database/iterate_aggregation_wtids_above_serial_id.h"
      41              : #include "exchange-database/iterate_aggregations_above_serial_id.h"
      42              : #include "exchange-database/iterate_wire_transfers.h"
      43              : 
      44              : 
      45              : /**
      46              :  * Account the merchants of the checks are paid at.
      47              :  */
      48              : static struct TDB_Account account;
      49              : 
      50              : 
      51              : /**
      52              :  * Denomination the checks deposit.
      53              :  */
      54              : static struct TDB_Denom denom;
      55              : 
      56              : 
      57              : /**
      58              :  * Build a timestamp from a number of seconds since the epoch.
      59              :  *
      60              :  * @param secs seconds since the epoch
      61              :  * @return the timestamp
      62              :  */
      63              : static struct GNUNET_TIME_Timestamp
      64            5 : ts (uint64_t secs)
      65              : {
      66            5 :   struct GNUNET_TIME_Absolute abs = {
      67            5 :     .abs_value_us = secs * 1000LLU * 1000LLU
      68              :   };
      69              : 
      70            5 :   return GNUNET_TIME_absolute_to_timestamp (abs);
      71              : }
      72              : 
      73              : 
      74              : /**
      75              :  * Closure for #wtid_cb().
      76              :  */
      77              : struct WtidContext
      78              : {
      79              :   /**
      80              :    * How many rows did the callback see?
      81              :    */
      82              :   unsigned int total;
      83              : 
      84              :   /**
      85              :    * Wire transfer we are looking for, NULL to match nothing.
      86              :    */
      87              :   const struct TALER_WireTransferIdentifierRawP *wtid;
      88              : 
      89              :   /**
      90              :    * How many times did we see it?
      91              :    */
      92              :   unsigned int matched;
      93              : 
      94              :   /**
      95              :    * Was the last matching row reported as pending?
      96              :    */
      97              :   bool pending;
      98              : };
      99              : 
     100              : 
     101              : /**
     102              :  * Callback for
     103              :  * #TALER_EXCHANGEDB_iterate_aggregation_wtids_above_serial_id().
     104              :  *
     105              :  * @param cls a `struct WtidContext *`
     106              :  * @param rowid row of the tracking entry
     107              :  * @param wtid wire transfer the deposit was aggregated into
     108              :  * @param wire_target_h_payto where the transfer goes
     109              :  * @param pending whether the transfer has not been made yet
     110              :  * @return #GNUNET_OK
     111              :  */
     112              : static enum GNUNET_GenericReturnValue
     113            3 : wtid_cb (void *cls,
     114              :          uint64_t rowid,
     115              :          const struct TALER_WireTransferIdentifierRawP *wtid,
     116              :          const struct TALER_FullPaytoHashP *wire_target_h_payto,
     117              :          bool pending)
     118              : {
     119            3 :   struct WtidContext *ctx = cls;
     120              : 
     121              :   (void) rowid;
     122              :   (void) wire_target_h_payto;
     123            3 :   ctx->total++;
     124            3 :   if ( (NULL != ctx->wtid) &&
     125            3 :        (0 == GNUNET_memcmp (wtid,
     126              :                             ctx->wtid)) )
     127              :   {
     128            2 :     ctx->matched++;
     129            2 :     ctx->pending = pending;
     130              :   }
     131            3 :   return GNUNET_OK;
     132              : }
     133              : 
     134              : 
     135              : /**
     136              :  * Closure for #aggregation_cb() and #transfer_cb().
     137              :  */
     138              : struct SumContext
     139              : {
     140              :   /**
     141              :    * How many rows did the callback see?
     142              :    */
     143              :   unsigned int total;
     144              : 
     145              :   /**
     146              :    * Sum of the whole-unit parts of the amounts seen.
     147              :    */
     148              :   uint64_t value_sum;
     149              : 
     150              :   /**
     151              :    * Row of the first entry seen.
     152              :    */
     153              :   uint64_t first_row;
     154              : };
     155              : 
     156              : 
     157              : /**
     158              :  * Callback for #TALER_EXCHANGEDB_iterate_aggregations_above_serial_id().
     159              :  *
     160              :  * @param cls a `struct SumContext *`
     161              :  * @param amount how much was aggregated
     162              :  * @param tracking_serial_id row of the tracking entry
     163              :  * @param batch_deposit_serial_id deposit that was aggregated
     164              :  */
     165              : static void
     166            2 : aggregation_cb (void *cls,
     167              :                 const struct TALER_Amount *amount,
     168              :                 uint64_t tracking_serial_id,
     169              :                 uint64_t batch_deposit_serial_id)
     170              : {
     171            2 :   struct SumContext *ctx = cls;
     172              : 
     173              :   (void) batch_deposit_serial_id;
     174            2 :   if (0 == ctx->total++)
     175            1 :     ctx->first_row = tracking_serial_id;
     176            2 :   ctx->value_sum += amount->value;
     177            2 : }
     178              : 
     179              : 
     180              : /**
     181              :  * Callback for #TALER_EXCHANGEDB_iterate_wire_transfers().
     182              :  *
     183              :  * @param cls a `struct SumContext *`
     184              :  * @param rowid row of the tracking entry
     185              :  * @param merchant_pub merchant that was paid
     186              :  * @param account_payto_uri account of the merchant
     187              :  * @param h_payto hash of that account
     188              :  * @param exchange_payto_uri account of the exchange
     189              :  * @param exec_time when the transfer was made
     190              :  * @param h_contract_terms contract that was paid
     191              :  * @param denom_pub denomination of the coin
     192              :  * @param coin_pub the coin that was deposited
     193              :  * @param coin_value how much the coin contributed
     194              :  * @param coin_fee how much the exchange charged for it
     195              :  */
     196              : static void
     197            1 : transfer_cb (void *cls,
     198              :              uint64_t rowid,
     199              :              const struct TALER_MerchantPublicKeyP *merchant_pub,
     200              :              const struct TALER_FullPayto account_payto_uri,
     201              :              const struct TALER_FullPaytoHashP *h_payto,
     202              :              const struct TALER_FullPayto exchange_payto_uri,
     203              :              struct GNUNET_TIME_Timestamp exec_time,
     204              :              const struct TALER_PrivateContractHashP *h_contract_terms,
     205              :              const struct TALER_DenominationPublicKey *denom_pub,
     206              :              const struct TALER_CoinSpendPublicKeyP *coin_pub,
     207              :              const struct TALER_Amount *coin_value,
     208              :              const struct TALER_Amount *coin_fee)
     209              : {
     210            1 :   struct SumContext *ctx = cls;
     211              : 
     212              :   (void) merchant_pub;
     213              :   (void) account_payto_uri;
     214              :   (void) h_payto;
     215              :   (void) exchange_payto_uri;
     216              :   (void) exec_time;
     217              :   (void) h_contract_terms;
     218              :   (void) denom_pub;
     219              :   (void) coin_pub;
     220              :   (void) coin_fee;
     221            1 :   if (0 == ctx->total++)
     222            1 :     ctx->first_row = rowid;
     223            1 :   ctx->value_sum += coin_value->value;
     224            1 : }
     225              : 
     226              : 
     227              : /**
     228              :  * Nothing is reported while the table is empty, and aggregating an
     229              :  * account with no deposits comes out at zero.
     230              :  *
     231              :  * @param pg the database context
     232              :  * @return 0 on success
     233              :  */
     234              : static int
     235            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
     236              : {
     237              :   struct TALER_MerchantPublicKeyP merchant_pub;
     238              :   struct TALER_WireTransferIdentifierRawP wtid;
     239              :   struct TALER_FullPaytoHashP h_payto;
     240            1 :   struct TALER_FullPayto payto_uri = { NULL };
     241              :   struct TALER_Amount total;
     242            1 :   struct TALER_Amount zero = TDB_amount ("0");
     243              :   struct TALER_Amount deposited;
     244              :   struct TALER_Amount refunded;
     245              :   struct TALER_Amount fee;
     246            1 :   struct WtidContext ctx = { 0 };
     247            1 :   struct SumContext sctx = { 0 };
     248              : 
     249            1 :   TDB_denom (pg,
     250              :              10,
     251              :              "5",
     252              :              "0.1",
     253              :              &denom);
     254            1 :   TDB_account (pg,
     255              :                10,
     256              :                &account);
     257            1 :   TDB_FILL (merchant_pub,
     258              :             1);
     259            1 :   TDB_FILL (wtid,
     260              :             1);
     261            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     262              :           TALER_EXCHANGEDB_do_aggregate (pg,
     263              :                                          &account.h_full,
     264              :                                          &merchant_pub,
     265              :                                          &wtid,
     266              :                                          &total));
     267            1 :   FAILIF (0 != TALER_amount_cmp (&total,
     268              :                                  &zero));
     269            1 :   FAILIF (0 != TDB_count (pg,
     270              :                           "FROM aggregation_tracking"));
     271            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     272              :           TALER_EXCHANGEDB_get_pending_aggregation (pg,
     273              :                                                     &wtid,
     274              :                                                     &h_payto,
     275              :                                                     &payto_uri,
     276              :                                                     &deposited,
     277              :                                                     &refunded,
     278              :                                                     &fee));
     279            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     280              :           TALER_EXCHANGEDB_iterate_aggregation_wtids_above_serial_id (
     281              :             pg,
     282              :             0,
     283              :             &wtid_cb,
     284              :             &ctx));
     285            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     286              :           TALER_EXCHANGEDB_iterate_aggregations_above_serial_id (
     287              :             pg,
     288              :             0,
     289              :             &aggregation_cb,
     290              :             &sctx));
     291            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     292              :           TALER_EXCHANGEDB_iterate_wire_transfers (pg,
     293              :                                                    &wtid,
     294              :                                                    &transfer_cb,
     295              :                                                    &sctx));
     296            1 :   FAILIF (0 != ctx.total);
     297            1 :   FAILIF (0 != sctx.total);
     298            1 :   return 0;
     299              : }
     300              : 
     301              : 
     302              : /**
     303              :  * Aggregating a deposit records it and nets out the deposit fee.
     304              :  *
     305              :  * @param pg the database context
     306              :  * @return 0 on success
     307              :  */
     308              : static int
     309            1 : check_aggregate (struct TALER_EXCHANGEDB_PostgresContext *pg)
     310              : {
     311              :   struct TALER_CoinPublicInfo coin;
     312              :   struct TDB_Deposit dep;
     313              :   struct TALER_WireTransferIdentifierRawP wtid;
     314              :   struct TALER_FullPaytoHashP h_payto;
     315            1 :   struct TALER_FullPayto payto_uri = { NULL };
     316              :   struct TALER_Amount total;
     317              :   struct TALER_Amount deposited;
     318              :   struct TALER_Amount refunded;
     319              :   struct TALER_Amount fee;
     320            1 :   struct TALER_Amount expect_total = TDB_amount ("0.9");
     321            1 :   struct TALER_Amount expect_deposited = TDB_amount ("1");
     322            1 :   struct TALER_Amount expect_refunded = TDB_amount ("0");
     323            1 :   struct TALER_Amount expect_fee = TDB_amount ("0.1");
     324              :   struct WtidContext ctx;
     325              : 
     326            1 :   TDB_coin (pg,
     327              :             &denom,
     328              :             20,
     329              :             &coin,
     330              :             NULL);
     331            1 :   TDB_deposit (pg,
     332              :                &account,
     333              :                &coin,
     334              :                20,
     335              :                "1",
     336              :                "0.1",
     337              :                ts (1600000000),
     338              :                ts (1600000000),
     339              :                &dep);
     340            1 :   TDB_FILL (wtid,
     341              :             20);
     342            1 :   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     343              :             TALER_EXCHANGEDB_do_aggregate (pg,
     344              :                                            &account.h_full,
     345              :                                            &dep.merchant_pub,
     346              :                                            &wtid,
     347              :                                            &total),
     348              :             TDB_coin_free (&coin));
     349            1 :   FAILIF_C (0 != TALER_amount_cmp (&total,
     350              :                                    &expect_total),
     351              :             TDB_coin_free (&coin));
     352            1 :   FAILIF_C (1 != TDB_count (pg,
     353              :                             "FROM aggregation_tracking"),
     354              :             TDB_coin_free (&coin));
     355              :   /* the deposit is now marked as done */
     356            1 :   FAILIF_C (1 != TDB_count (pg,
     357              :                             "FROM batch_deposits WHERE done"),
     358              :             TDB_coin_free (&coin));
     359              : 
     360              :   /* the transfer has not been made yet, so it is pending */
     361            1 :   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     362              :             TALER_EXCHANGEDB_get_pending_aggregation (pg,
     363              :                                                       &wtid,
     364              :                                                       &h_payto,
     365              :                                                       &payto_uri,
     366              :                                                       &deposited,
     367              :                                                       &refunded,
     368              :                                                       &fee),
     369              :             TDB_coin_free (&coin));
     370            1 :   FAILIF_C (0 != GNUNET_memcmp (&h_payto,
     371              :                                 &account.h_full),
     372              :             GNUNET_free (payto_uri.full_payto); TDB_coin_free (&coin));
     373            1 :   FAILIF_C (0 != strcmp (payto_uri.full_payto,
     374              :                          account.payto.full_payto),
     375              :             GNUNET_free (payto_uri.full_payto); TDB_coin_free (&coin));
     376            1 :   GNUNET_free (payto_uri.full_payto);
     377            1 :   FAILIF_C (0 != TALER_amount_cmp (&deposited,
     378              :                                    &expect_deposited),
     379              :             TDB_coin_free (&coin));
     380            1 :   FAILIF_C (0 != TALER_amount_cmp (&refunded,
     381              :                                    &expect_refunded),
     382              :             TDB_coin_free (&coin));
     383            1 :   FAILIF_C (0 != TALER_amount_cmp (&fee,
     384              :                                    &expect_fee),
     385              :             TDB_coin_free (&coin));
     386              : 
     387            1 :   memset (&ctx,
     388              :           0,
     389              :           sizeof (ctx));
     390            1 :   ctx.wtid = &wtid;
     391            1 :   FAILIF_C (0 >=
     392              :             TALER_EXCHANGEDB_iterate_aggregation_wtids_above_serial_id (
     393              :               pg,
     394              :               0,
     395              :               &wtid_cb,
     396              :               &ctx),
     397              :             TDB_coin_free (&coin));
     398            1 :   FAILIF_C (1 != ctx.matched,
     399              :             TDB_coin_free (&coin));
     400            1 :   FAILIF_C (! ctx.pending,
     401              :             TDB_coin_free (&coin));
     402            1 :   TDB_coin_free (&coin);
     403            1 :   return 0;
     404              : }
     405              : 
     406              : 
     407              : /**
     408              :  * A deposit that was refunded in full is aggregated at zero and is not
     409              :  * charged a deposit fee.
     410              :  *
     411              :  * @param pg the database context
     412              :  * @return 0 on success
     413              :  */
     414              : static int
     415            1 : check_full_refund (struct TALER_EXCHANGEDB_PostgresContext *pg)
     416              : {
     417              :   struct TALER_CoinPublicInfo coin;
     418              :   struct TDB_Deposit dep;
     419              :   struct TALER_EXCHANGEDB_Refund refund;
     420            1 :   struct TALER_Amount deposit_fee = TDB_amount ("0.1");
     421              :   struct TALER_WireTransferIdentifierRawP wtid;
     422              :   struct TALER_Amount total;
     423            1 :   struct TALER_Amount zero = TDB_amount ("0");
     424              :   bool not_found;
     425              :   bool refund_ok;
     426              :   bool gone;
     427              :   bool conflict;
     428              : 
     429            1 :   TDB_coin (pg,
     430              :             &denom,
     431              :             21,
     432              :             &coin,
     433              :             NULL);
     434            1 :   TDB_deposit (pg,
     435              :                &account,
     436              :                &coin,
     437              :                21,
     438              :                "1",
     439              :                "0.1",
     440              :                ts (1600000000),
     441              :                ts (1600000000),
     442              :                &dep);
     443            1 :   memset (&refund,
     444              :           0,
     445              :           sizeof (refund));
     446            1 :   refund.coin = coin;
     447            1 :   refund.details.merchant_pub = dep.merchant_pub;
     448            1 :   TDB_FILL (refund.details.merchant_sig,
     449              :             21);
     450            1 :   refund.details.h_contract_terms = dep.h_contract_terms;
     451            1 :   refund.details.rtransaction_id = 1;
     452            1 :   refund.details.refund_amount = TDB_amount ("1");
     453            1 :   refund.details.refund_fee = TDB_amount ("0");
     454            1 :   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     455              :             TALER_EXCHANGEDB_do_refund (pg,
     456              :                                         &refund,
     457              :                                         &deposit_fee,
     458              :                                         0,
     459              :                                         &not_found,
     460              :                                         &refund_ok,
     461              :                                         &gone,
     462              :                                         &conflict),
     463              :             TDB_coin_free (&coin));
     464            1 :   FAILIF_C (! refund_ok,
     465              :             TDB_coin_free (&coin));
     466              : 
     467            1 :   TDB_FILL (wtid,
     468              :             21);
     469            1 :   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     470              :             TALER_EXCHANGEDB_do_aggregate (pg,
     471              :                                            &account.h_full,
     472              :                                            &dep.merchant_pub,
     473              :                                            &wtid,
     474              :                                            &total),
     475              :             TDB_coin_free (&coin));
     476              :   /* deposit EUR:1 minus refund EUR:1, and no deposit fee on a coin that
     477              :      was refunded in full */
     478            1 :   FAILIF_C (0 != TALER_amount_cmp (&total,
     479              :                                    &zero),
     480              :             TDB_coin_free (&coin));
     481            1 :   TDB_coin_free (&coin);
     482            1 :   return 0;
     483              : }
     484              : 
     485              : 
     486              : /**
     487              :  * Executing the wire transfer takes the aggregation out of "pending".
     488              :  *
     489              :  * @param pg the database context
     490              :  * @return 0 on success
     491              :  */
     492              : static int
     493            1 : check_executed (struct TALER_EXCHANGEDB_PostgresContext *pg)
     494              : {
     495              :   struct TALER_WireTransferIdentifierRawP wtid;
     496              :   struct TALER_FullPaytoHashP h_payto;
     497            1 :   struct TALER_FullPayto payto_uri = { NULL };
     498            1 :   struct TALER_FullPayto exchange_payto = {
     499              :     .full_payto = (char *) "payto://x-taler-bank/localhost/exchange"
     500              :   };
     501            1 :   struct TALER_Amount amount = TDB_amount ("0.9");
     502              :   struct TALER_Amount deposited;
     503              :   struct TALER_Amount refunded;
     504              :   struct TALER_Amount fee;
     505              :   struct WtidContext ctx;
     506              : 
     507            1 :   TDB_FILL (wtid,
     508              :             20);
     509            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     510              :           TALER_EXCHANGEDB_insert_wire_out (pg,
     511              :                                             ts (1600003600),
     512              :                                             &wtid,
     513              :                                             &account.h_full,
     514              :                                             "exchange-account-1",
     515              :                                             exchange_payto,
     516              :                                             &amount,
     517              :                                             NULL));
     518              :   /* the aggregation is no longer pending... */
     519            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     520              :           TALER_EXCHANGEDB_get_pending_aggregation (pg,
     521              :                                                     &wtid,
     522              :                                                     &h_payto,
     523              :                                                     &payto_uri,
     524              :                                                     &deposited,
     525              :                                                     &refunded,
     526              :                                                     &fee));
     527              :   /* ...and the wtid iterator says so too */
     528            1 :   memset (&ctx,
     529              :           0,
     530              :           sizeof (ctx));
     531            1 :   ctx.wtid = &wtid;
     532            1 :   FAILIF (0 >=
     533              :           TALER_EXCHANGEDB_iterate_aggregation_wtids_above_serial_id (
     534              :             pg,
     535              :             0,
     536              :             &wtid_cb,
     537              :             &ctx));
     538            1 :   FAILIF (1 != ctx.matched);
     539            1 :   FAILIF (ctx.pending);
     540            1 :   return 0;
     541              : }
     542              : 
     543              : 
     544              : /**
     545              :  * The deposit can be traced to the wire transfer it went into, and the
     546              :  * transfer back to the deposits it paid.
     547              :  *
     548              :  * @param pg the database context
     549              :  * @return 0 on success
     550              :  */
     551              : static int
     552            1 : check_transfer_by_deposit (struct TALER_EXCHANGEDB_PostgresContext *pg)
     553              : {
     554              :   struct TALER_CoinSpendPublicKeyP coin_pub;
     555              :   struct TDB_Deposit dep;
     556              :   struct TALER_WireTransferIdentifierRawP wtid;
     557              :   struct TALER_WireTransferIdentifierRawP got_wtid;
     558              :   struct GNUNET_TIME_Timestamp exec_time;
     559              :   struct TALER_Amount amount_with_fee;
     560              :   struct TALER_Amount deposit_fee;
     561            1 :   struct TALER_Amount expect_amount = TDB_amount ("1");
     562              :   struct TALER_EXCHANGEDB_KycStatus kyc;
     563              :   union TALER_AccountPublicKeyP account_pub;
     564              :   struct SumContext sctx;
     565            1 :   bool pending = true;
     566              : 
     567              :   /* the deposit of check_aggregate() */
     568            1 :   TDB_FILL (coin_pub,
     569              :             20);
     570            1 :   TDB_FILL (wtid,
     571              :             20);
     572            1 :   memset (&dep,
     573              :           0,
     574              :           sizeof (dep));
     575            1 :   TDB_FILL (dep.merchant_pub,
     576              :             20);
     577            1 :   TDB_FILL (dep.h_contract_terms,
     578              :             20);
     579            1 :   TDB_FILL (dep.wire_salt,
     580              :             20);
     581            1 :   TALER_merchant_wire_signature_hash (account.payto,
     582              :                                       &dep.wire_salt,
     583              :                                       &dep.h_wire);
     584            1 :   memset (&kyc,
     585              :           0,
     586              :           sizeof (kyc));
     587            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     588              :           TALER_EXCHANGEDB_get_transfer_by_deposit (pg,
     589              :                                                     &dep.h_contract_terms,
     590              :                                                     &dep.h_wire,
     591              :                                                     &coin_pub,
     592              :                                                     &dep.merchant_pub,
     593              :                                                     &pending,
     594              :                                                     &got_wtid,
     595              :                                                     &exec_time,
     596              :                                                     &amount_with_fee,
     597              :                                                     &deposit_fee,
     598              :                                                     &kyc,
     599              :                                                     &account_pub));
     600            1 :   FAILIF (pending);
     601            1 :   FAILIF (0 != GNUNET_memcmp (&got_wtid,
     602              :                               &wtid));
     603            1 :   FAILIF (0 != TALER_amount_cmp (&amount_with_fee,
     604              :                                  &expect_amount));
     605              : 
     606              :   /* a contract nobody deposited is not found */
     607              :   {
     608              :     struct TALER_PrivateContractHashP other;
     609              : 
     610            1 :     TDB_FILL (other,
     611              :               97);
     612            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     613              :             TALER_EXCHANGEDB_get_transfer_by_deposit (pg,
     614              :                                                       &other,
     615              :                                                       &dep.h_wire,
     616              :                                                       &coin_pub,
     617              :                                                       &dep.merchant_pub,
     618              :                                                       &pending,
     619              :                                                       &got_wtid,
     620              :                                                       &exec_time,
     621              :                                                       &amount_with_fee,
     622              :                                                       &deposit_fee,
     623              :                                                       &kyc,
     624              :                                                       &account_pub));
     625              :   }
     626              : 
     627              :   /* and the transfer lists the coins it paid for */
     628            1 :   memset (&sctx,
     629              :           0,
     630              :           sizeof (sctx));
     631            1 :   FAILIF (0 >=
     632              :           TALER_EXCHANGEDB_iterate_wire_transfers (pg,
     633              :                                                    &wtid,
     634              :                                                    &transfer_cb,
     635              :                                                    &sctx));
     636            1 :   FAILIF (1 != sctx.total);
     637            1 :   FAILIF (1 != sctx.value_sum);
     638              :   {
     639              :     struct TALER_WireTransferIdentifierRawP other;
     640              : 
     641            1 :     TDB_FILL (other,
     642              :               96);
     643            1 :     memset (&sctx,
     644              :             0,
     645              :             sizeof (sctx));
     646            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     647              :             TALER_EXCHANGEDB_iterate_wire_transfers (pg,
     648              :                                                      &other,
     649              :                                                      &transfer_cb,
     650              :                                                      &sctx));
     651            1 :     FAILIF (0 != sctx.total);
     652              :   }
     653            1 :   return 0;
     654              : }
     655              : 
     656              : 
     657              : /**
     658              :  * The aggregation iterator walks the table by serial.
     659              :  *
     660              :  * @param pg the database context
     661              :  * @return 0 on success
     662              :  */
     663              : static int
     664            1 : check_iterate_aggregations (struct TALER_EXCHANGEDB_PostgresContext *pg)
     665              : {
     666              :   struct SumContext ctx;
     667              : 
     668            1 :   memset (&ctx,
     669              :           0,
     670              :           sizeof (ctx));
     671            1 :   FAILIF (2 !=
     672              :           TALER_EXCHANGEDB_iterate_aggregations_above_serial_id (
     673              :             pg,
     674              :             0,
     675              :             &aggregation_cb,
     676              :             &ctx));
     677            1 :   FAILIF (2 != ctx.total);
     678            1 :   memset (&ctx,
     679              :           0,
     680              :           sizeof (ctx));
     681            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     682              :           TALER_EXCHANGEDB_iterate_aggregations_above_serial_id (
     683              :             pg,
     684              :             1000,
     685              :             &aggregation_cb,
     686              :             &ctx));
     687            1 :   FAILIF (0 != ctx.total);
     688            1 :   return 0;
     689              : }
     690              : 
     691              : 
     692              : /**
     693              :  * The checks to run, in order.
     694              :  */
     695              : static const struct TDB_Test tests[] = {
     696              :   { "aggregation-tracking-empty",
     697              :     &check_empty },
     698              :   { "aggregation-tracking-aggregate",
     699              :     &check_aggregate },
     700              :   { "aggregation-tracking-full-refund",
     701              :     &check_full_refund },
     702              :   { "aggregation-tracking-executed",
     703              :     &check_executed },
     704              :   { "aggregation-tracking-transfer-by-deposit",
     705              :     &check_transfer_by_deposit },
     706              :   { "aggregation-tracking-iterate-aggregations",
     707              :     &check_iterate_aggregations },
     708              :   { NULL, NULL }
     709              : };
     710              : 
     711              : 
     712              : int
     713            1 : main (int argc,
     714              :       char *const *argv)
     715              : {
     716              :   int ret;
     717              : 
     718            1 :   ret = TDB_main (argc,
     719              :                   argv,
     720              :                   "test-aggregation-tracking",
     721              :                   "Tests for the exchangedb `aggregation_tracking' table",
     722              :                   tests);
     723            1 :   TDB_account_free (&account);
     724            1 :   TDB_denom_free (&denom);
     725            1 :   return ret;
     726              : }
     727              : 
     728              : 
     729              : /* end of test_aggregation_tracking.c */
        

Generated by: LCOV version 2.0-1