LCOV - code coverage report
Current view: top level - exchangedb - test_aggregation_transient.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 67 67
Test Date: 2026-10-29 19:05:17 Functions: 100.0 % 5 5

            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_transient.c
      18              :  * @brief tests for the exchangedb functions whose primary table is
      19              :  *        `aggregation_transient`
      20              :  * @author Christian Grothoff
      21              :  *
      22              :  * Covers #TALER_EXCHANGEDB_insert_aggregation_transient(),
      23              :  * #TALER_EXCHANGEDB_update_aggregation_transient(),
      24              :  * #TALER_EXCHANGEDB_delete_aggregation_transient(),
      25              :  * #TALER_EXCHANGEDB_get_aggregation_transient(),
      26              :  * #TALER_EXCHANGEDB_get_aggregation_transient_by_wtid() and
      27              :  * #TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto().
      28              :  *
      29              :  * The table holds what the aggregator decided to hold back for later; it
      30              :  * is updated in place and deleted on payout, so it has no serial ID.  It
      31              :  * references `wire_targets`, which TDB_account() creates.  The three
      32              :  * lookups reach the row by three different keys, which is what the checks
      33              :  * exercise.
      34              :  */
      35              : #include "test_common.h"
      36              : #include "exchange-database/delete_aggregation_transient.h"
      37              : #include "exchange-database/get_aggregation_transient.h"
      38              : #include "exchange-database/get_aggregation_transient_by_normalized_payto.h"
      39              : #include "exchange-database/get_aggregation_transient_by_wtid.h"
      40              : #include "exchange-database/insert_aggregation_transient.h"
      41              : #include "exchange-database/update_aggregation_transient.h"
      42              : 
      43              : 
      44              : /**
      45              :  * Exchange bank account the checks aggregate for.
      46              :  */
      47              : #define SECTION "exchange-account-1"
      48              : 
      49              : 
      50              : /**
      51              :  * Account the merchants of the checks are paid at.
      52              :  */
      53              : static struct TDB_Account account;
      54              : 
      55              : 
      56              : /**
      57              :  * Nothing is found while the table is empty, and updating or deleting a
      58              :  * row that is not there does nothing.
      59              :  *
      60              :  * @param pg the database context
      61              :  * @return 0 on success
      62              :  */
      63              : static int
      64            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
      65              : {
      66              :   struct TALER_MerchantPublicKeyP merchant_pub;
      67              :   struct TALER_WireTransferIdentifierRawP wtid;
      68              :   struct TALER_Amount total;
      69            1 :   struct TALER_Amount one = TDB_amount ("1");
      70            1 :   struct TALER_FullPayto payto_uri = { NULL };
      71              :   uint64_t requirement_row;
      72              : 
      73            1 :   TDB_account (pg,
      74              :                10,
      75              :                &account);
      76            1 :   TDB_FILL (merchant_pub,
      77              :             1);
      78            1 :   TDB_FILL (wtid,
      79              :             1);
      80            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      81              :           TALER_EXCHANGEDB_get_aggregation_transient (pg,
      82              :                                                       &account.h_full,
      83              :                                                       &merchant_pub,
      84              :                                                       SECTION,
      85              :                                                       &wtid,
      86              :                                                       &requirement_row,
      87              :                                                       &total));
      88            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      89              :           TALER_EXCHANGEDB_get_aggregation_transient_by_wtid (
      90              :             pg,
      91              :             &account.h_full,
      92              :             &wtid,
      93              :             &total,
      94              :             &requirement_row));
      95            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      96              :           TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto (
      97              :             pg,
      98              :             &account.h_normalized,
      99              :             &payto_uri,
     100              :             &wtid,
     101              :             &merchant_pub,
     102              :             &total));
     103            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     104              :           TALER_EXCHANGEDB_update_aggregation_transient (pg,
     105              :                                                          &account.h_full,
     106              :                                                          &wtid,
     107              :                                                          0,
     108              :                                                          &one));
     109            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     110              :           TALER_EXCHANGEDB_delete_aggregation_transient (pg,
     111              :                                                          &account.h_full,
     112              :                                                          &wtid));
     113            1 :   FAILIF (0 != TDB_count (pg,
     114              :                           "FROM aggregation_transient"));
     115            1 :   return 0;
     116              : }
     117              : 
     118              : 
     119              : /**
     120              :  * An inserted row is found by all three lookups.
     121              :  *
     122              :  * @param pg the database context
     123              :  * @return 0 on success
     124              :  */
     125              : static int
     126            1 : check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg)
     127              : {
     128              :   struct TALER_MerchantPublicKeyP merchant_pub;
     129              :   struct TALER_MerchantPublicKeyP got_merchant;
     130              :   struct TALER_WireTransferIdentifierRawP wtid;
     131              :   struct TALER_WireTransferIdentifierRawP got_wtid;
     132            1 :   struct TALER_Amount total = TDB_amount ("3");
     133              :   struct TALER_Amount got;
     134            1 :   struct TALER_FullPayto payto_uri = { NULL };
     135            1 :   uint64_t requirement_row = 42;
     136              : 
     137            1 :   TDB_FILL (merchant_pub,
     138              :             10);
     139            1 :   TDB_FILL (wtid,
     140              :             10);
     141            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     142              :           TALER_EXCHANGEDB_insert_aggregation_transient (pg,
     143              :                                                          &account.h_full,
     144              :                                                          SECTION,
     145              :                                                          &merchant_pub,
     146              :                                                          &wtid,
     147              :                                                          0,
     148              :                                                          &total));
     149            1 :   FAILIF (1 != TDB_count (pg,
     150              :                           "FROM aggregation_transient"));
     151              : 
     152              :   /* by (account, merchant, exchange account) */
     153            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     154              :           TALER_EXCHANGEDB_get_aggregation_transient (pg,
     155              :                                                       &account.h_full,
     156              :                                                       &merchant_pub,
     157              :                                                       SECTION,
     158              :                                                       &got_wtid,
     159              :                                                       &requirement_row,
     160              :                                                       &got));
     161            1 :   FAILIF (0 != GNUNET_memcmp (&got_wtid,
     162              :                               &wtid));
     163            1 :   FAILIF (0 != TALER_amount_cmp (&got,
     164              :                                  &total));
     165              :   /* no legitimization reason was recorded */
     166            1 :   FAILIF (0 != requirement_row);
     167              : 
     168              :   /* by (account, wtid) */
     169            1 :   requirement_row = 42;
     170            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     171              :           TALER_EXCHANGEDB_get_aggregation_transient_by_wtid (
     172              :             pg,
     173              :             &account.h_full,
     174              :             &wtid,
     175              :             &got,
     176              :             &requirement_row));
     177            1 :   FAILIF (0 != TALER_amount_cmp (&got,
     178              :                                  &total));
     179              :   /* no legitimization reason was recorded */
     180            1 :   FAILIF (0 != requirement_row);
     181              : 
     182              :   /* by normalized account */
     183            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     184              :           TALER_EXCHANGEDB_get_aggregation_transient_by_normalized_payto (
     185              :             pg,
     186              :             &account.h_normalized,
     187              :             &payto_uri,
     188              :             &got_wtid,
     189              :             &got_merchant,
     190              :             &got));
     191            1 :   FAILIF_C (0 != strcmp (payto_uri.full_payto,
     192              :                          account.payto.full_payto),
     193              :             GNUNET_free (payto_uri.full_payto));
     194            1 :   GNUNET_free (payto_uri.full_payto);
     195            1 :   FAILIF (0 != GNUNET_memcmp (&got_merchant,
     196              :                               &merchant_pub));
     197            1 :   FAILIF (0 != GNUNET_memcmp (&got_wtid,
     198              :                               &wtid));
     199              : 
     200              :   /* a different merchant on the same account has nothing */
     201              :   {
     202              :     struct TALER_MerchantPublicKeyP other;
     203              : 
     204            1 :     TDB_FILL (other,
     205              :               99);
     206            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     207              :             TALER_EXCHANGEDB_get_aggregation_transient (pg,
     208              :                                                         &account.h_full,
     209              :                                                         &other,
     210              :                                                         SECTION,
     211              :                                                         &got_wtid,
     212              :                                                         &requirement_row,
     213              :                                                         &got));
     214              :   }
     215              :   /* and neither does a different exchange bank account */
     216            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     217              :           TALER_EXCHANGEDB_get_aggregation_transient (pg,
     218              :                                                       &account.h_full,
     219              :                                                       &merchant_pub,
     220              :                                                       "exchange-account-2",
     221              :                                                       &got_wtid,
     222              :                                                       &requirement_row,
     223              :                                                       &got));
     224            1 :   return 0;
     225              : }
     226              : 
     227              : 
     228              : /**
     229              :  * Updating a row changes the amount and the legitimization reason.
     230              :  *
     231              :  * @param pg the database context
     232              :  * @return 0 on success
     233              :  */
     234              : static int
     235            1 : check_update (struct TALER_EXCHANGEDB_PostgresContext *pg)
     236              : {
     237              :   struct TALER_MerchantPublicKeyP merchant_pub;
     238              :   struct TALER_WireTransferIdentifierRawP wtid;
     239              :   struct TALER_WireTransferIdentifierRawP got_wtid;
     240            1 :   struct TALER_Amount total = TDB_amount ("7");
     241              :   struct TALER_Amount got;
     242            1 :   uint64_t requirement_row = 0;
     243              : 
     244            1 :   TDB_FILL (merchant_pub,
     245              :             10);
     246            1 :   TDB_FILL (wtid,
     247              :             10);
     248            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     249              :           TALER_EXCHANGEDB_update_aggregation_transient (pg,
     250              :                                                          &account.h_full,
     251              :                                                          &wtid,
     252              :                                                          5,
     253              :                                                          &total));
     254            1 :   FAILIF (1 != TDB_count (pg,
     255              :                           "FROM aggregation_transient"));
     256            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     257              :           TALER_EXCHANGEDB_get_aggregation_transient (pg,
     258              :                                                       &account.h_full,
     259              :                                                       &merchant_pub,
     260              :                                                       SECTION,
     261              :                                                       &got_wtid,
     262              :                                                       &requirement_row,
     263              :                                                       &got));
     264            1 :   FAILIF (0 != TALER_amount_cmp (&got,
     265              :                                  &total));
     266              :   /* the legitimization reason is read back, so re-parking keeps it */
     267            1 :   FAILIF (5 != requirement_row);
     268            1 :   requirement_row = 0;
     269            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     270              :           TALER_EXCHANGEDB_get_aggregation_transient_by_wtid (
     271              :             pg,
     272              :             &account.h_full,
     273              :             &wtid,
     274              :             &got,
     275              :             &requirement_row));
     276            1 :   FAILIF (5 != requirement_row);
     277              : 
     278              :   /* a wire transfer identifier that is not on file is not created */
     279              :   {
     280              :     struct TALER_WireTransferIdentifierRawP other;
     281              : 
     282            1 :     TDB_FILL (other,
     283              :               98);
     284            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     285              :             TALER_EXCHANGEDB_update_aggregation_transient (pg,
     286              :                                                            &account.h_full,
     287              :                                                            &other,
     288              :                                                            0,
     289              :                                                            &total));
     290            1 :     FAILIF (1 != TDB_count (pg,
     291              :                             "FROM aggregation_transient"));
     292              :   }
     293            1 :   return 0;
     294              : }
     295              : 
     296              : 
     297              : /**
     298              :  * Deleting a row removes it, and a second delete does nothing.
     299              :  *
     300              :  * @param pg the database context
     301              :  * @return 0 on success
     302              :  */
     303              : static int
     304            1 : check_delete (struct TALER_EXCHANGEDB_PostgresContext *pg)
     305              : {
     306              :   struct TALER_MerchantPublicKeyP merchant_pub;
     307              :   struct TALER_WireTransferIdentifierRawP wtid;
     308              :   struct TALER_Amount got;
     309              :   uint64_t requirement_row;
     310              : 
     311            1 :   TDB_FILL (merchant_pub,
     312              :             10);
     313            1 :   TDB_FILL (wtid,
     314              :             10);
     315            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     316              :           TALER_EXCHANGEDB_delete_aggregation_transient (pg,
     317              :                                                          &account.h_full,
     318              :                                                          &wtid));
     319            1 :   FAILIF (0 != TDB_count (pg,
     320              :                           "FROM aggregation_transient"));
     321            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     322              :           TALER_EXCHANGEDB_delete_aggregation_transient (pg,
     323              :                                                          &account.h_full,
     324              :                                                          &wtid));
     325            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     326              :           TALER_EXCHANGEDB_get_aggregation_transient (pg,
     327              :                                                       &account.h_full,
     328              :                                                       &merchant_pub,
     329              :                                                       SECTION,
     330              :                                                       &wtid,
     331              :                                                       &requirement_row,
     332              :                                                       &got));
     333            1 :   return 0;
     334              : }
     335              : 
     336              : 
     337              : /**
     338              :  * The checks to run, in order.
     339              :  */
     340              : static const struct TDB_Test tests[] = {
     341              :   { "aggregation-transient-empty",
     342              :     &check_empty },
     343              :   { "aggregation-transient-insert-and-lookup",
     344              :     &check_insert_and_lookup },
     345              :   { "aggregation-transient-update",
     346              :     &check_update },
     347              :   { "aggregation-transient-delete",
     348              :     &check_delete },
     349              :   { NULL, NULL }
     350              : };
     351              : 
     352              : 
     353              : int
     354            1 : main (int argc,
     355              :       char *const *argv)
     356              : {
     357              :   int ret;
     358              : 
     359            1 :   ret = TDB_main (argc,
     360              :                   argv,
     361              :                   "test-aggregation-transient",
     362              :                   "Tests for the exchangedb `aggregation_transient' table",
     363              :                   tests);
     364            1 :   TDB_account_free (&account);
     365            1 :   return ret;
     366              : }
     367              : 
     368              : 
     369              : /* end of test_aggregation_transient.c */
        

Generated by: LCOV version 2.0-1