LCOV - code coverage report
Current view: top level - exchangedb - test_misc.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.3 % 142 141
Test Date: 2026-10-10 21:00:14 Functions: 100.0 % 16 16

            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_misc.c
      18              :  * @brief tests for the exchangedb functions that have no table of their own
      19              :  * @author Christian Grothoff
      20              :  *
      21              :  * Covers #TALER_EXCHANGEDB_start(), #TALER_EXCHANGEDB_start_read_only(),
      22              :  * #TALER_EXCHANGEDB_start_read_committed(),
      23              :  * #TALER_EXCHANGEDB_start_deferred_wire_out(), #TALER_EXCHANGEDB_commit(),
      24              :  * #TALER_EXCHANGEDB_rollback(), #TALER_EXCHANGEDB_preflight(),
      25              :  * #TALER_EXCHANGEDB_compute_shard(),
      26              :  * #TALER_EXCHANGEDB_calculate_transaction_list_totals(),
      27              :  * #TALER_EXCHANGEDB_free_coin_transaction_list(),
      28              :  * #TALER_EXCHANGEDB_free_reserve_history(),
      29              :  * #TALER_EXCHANGEDB_event_listen(),
      30              :  * #TALER_EXCHANGEDB_event_listen_cancel(),
      31              :  * #TALER_EXCHANGEDB_event_notify(), #TALER_EXCHANGEDB_enable_rules(),
      32              :  * #TALER_EXCHANGEDB_disable_rules(),
      33              :  * #TALER_EXCHANGEDB_inject_auditor_triggers(),
      34              :  * #TALER_EXCHANGEDB_drop_tables() and #TALER_EXCHANGEDB_create_tables().
      35              :  *
      36              :  * These are the connection-level functions: transactions, notifications,
      37              :  * schema management and the two list destructors.  The schema checks come
      38              :  * last on purpose -- they take the tables away and put them back, so
      39              :  * nothing may run after them.
      40              :  */
      41              : #include "test_common.h"
      42              : #include "taler/taler_dbevents.h"
      43              : #include "exchange-database/commit.h"
      44              : #include "exchange-database/compute_shard.h"
      45              : #include "exchange-database/create_tables.h"
      46              : #include "exchange-database/disable_rules.h"
      47              : #include "exchange-database/drop_tables.h"
      48              : #include "exchange-database/enable_rules.h"
      49              : #include "exchange-database/event_listen.h"
      50              : #include "exchange-database/event_listen_cancel.h"
      51              : #include "exchange-database/event_notify.h"
      52              : #include "exchange-database/free_coin_transaction_list.h"
      53              : #include "exchange-database/free_reserve_history.h"
      54              : #include "exchange-database/get_coin_transactions.h"
      55              : #include "exchange-database/get_reserve_history.h"
      56              : #include "exchange-database/inject_auditor_triggers.h"
      57              : #include "exchange-database/preflight.h"
      58              : #include "exchange-database/rollback.h"
      59              : #include "exchange-database/start.h"
      60              : #include "exchange-database/start_deferred_wire_out.h"
      61              : #include "exchange-database/start_read_committed.h"
      62              : #include "exchange-database/start_read_only.h"
      63              : 
      64              : 
      65              : /**
      66              :  * Account the checks fund their reserves from.
      67              :  */
      68              : static struct TDB_Account account;
      69              : 
      70              : 
      71              : /**
      72              :  * Denomination the checks use.
      73              :  */
      74              : static struct TDB_Denom denom;
      75              : 
      76              : 
      77              : /**
      78              :  * The four ways to start a transaction.
      79              :  *
      80              :  * @param pg the database context
      81              :  * @param name name of the transaction
      82              :  * @return #GNUNET_OK on success
      83              :  */
      84              : static enum GNUNET_GenericReturnValue
      85            2 : start_serializable (struct TALER_EXCHANGEDB_PostgresContext *pg,
      86              :                     const char *name)
      87              : {
      88            2 :   return TALER_EXCHANGEDB_start (pg,
      89              :                                  name);
      90              : }
      91              : 
      92              : 
      93              : /**
      94              :  * Start a read-only transaction.
      95              :  *
      96              :  * @param pg the database context
      97              :  * @param name name of the transaction
      98              :  * @return #GNUNET_OK on success
      99              :  */
     100              : static enum GNUNET_GenericReturnValue
     101            2 : start_read_only (struct TALER_EXCHANGEDB_PostgresContext *pg,
     102              :                  const char *name)
     103              : {
     104            2 :   return TALER_EXCHANGEDB_start_read_only (pg,
     105              :                                            name);
     106              : }
     107              : 
     108              : 
     109              : /**
     110              :  * Start a read-committed transaction.
     111              :  *
     112              :  * @param pg the database context
     113              :  * @param name name of the transaction
     114              :  * @return #GNUNET_OK on success
     115              :  */
     116              : static enum GNUNET_GenericReturnValue
     117            2 : start_read_committed (struct TALER_EXCHANGEDB_PostgresContext *pg,
     118              :                       const char *name)
     119              : {
     120            2 :   return TALER_EXCHANGEDB_start_read_committed (pg,
     121              :                                                 name);
     122              : }
     123              : 
     124              : 
     125              : /**
     126              :  * Start a transaction with deferred wire-out constraints.
     127              :  *
     128              :  * @param pg the database context
     129              :  * @param name name of the transaction
     130              :  * @return #GNUNET_OK on success
     131              :  */
     132              : static enum GNUNET_GenericReturnValue
     133            2 : start_deferred (struct TALER_EXCHANGEDB_PostgresContext *pg,
     134              :                 const char *name)
     135              : {
     136              :   (void) name;
     137            2 :   return TALER_EXCHANGEDB_start_deferred_wire_out (pg);
     138              : }
     139              : 
     140              : 
     141              : /**
     142              :  * All four transaction starters behave the same way as far as the
     143              :  * connection's bookkeeping is concerned.
     144              :  *
     145              :  * @param pg the database context
     146              :  * @return 0 on success
     147              :  */
     148              : static int
     149            1 : check_transactions (struct TALER_EXCHANGEDB_PostgresContext *pg)
     150              : {
     151              :   static enum GNUNET_GenericReturnValue (*const starters[])(
     152              :     struct TALER_EXCHANGEDB_PostgresContext *,
     153              :     const char *) = {
     154              :     &start_serializable,
     155              :     &start_read_only,
     156              :     &start_read_committed,
     157              :     &start_deferred
     158              :   };
     159              : 
     160            1 :   FAILIF (NULL != pg->transaction_name);
     161            5 :   for (unsigned int i = 0; i < 4; i++)
     162              :   {
     163              :     /* commit ends the transaction ... */
     164            4 :     FAILIF (GNUNET_OK !=
     165              :             starters[i](pg,
     166              :                         "misc-commit"));
     167            4 :     FAILIF (NULL == pg->transaction_name);
     168            4 :     FAILIF (0 > TALER_EXCHANGEDB_commit (pg));
     169            4 :     FAILIF (NULL != pg->transaction_name);
     170              : 
     171              :     /* ... and so does a rollback */
     172            4 :     FAILIF (GNUNET_OK !=
     173              :             starters[i](pg,
     174              :                         "misc-rollback"));
     175            4 :     FAILIF (NULL == pg->transaction_name);
     176            4 :     TALER_EXCHANGEDB_rollback (pg);
     177            4 :     FAILIF (NULL != pg->transaction_name);
     178              :   }
     179              : 
     180              :   /* rolling back when nothing is open is a no-op */
     181            1 :   TALER_EXCHANGEDB_rollback (pg);
     182            1 :   FAILIF (NULL != pg->transaction_name);
     183            1 :   return 0;
     184              : }
     185              : 
     186              : 
     187              : /**
     188              :  * A transaction really isolates: what it wrote is gone after a rollback
     189              :  * and there after a commit.
     190              :  *
     191              :  * @param pg the database context
     192              :  * @return 0 on success
     193              :  */
     194              : static int
     195            1 : check_isolation (struct TALER_EXCHANGEDB_PostgresContext *pg)
     196              : {
     197            1 :   FAILIF (GNUNET_OK !=
     198              :           TALER_EXCHANGEDB_start (pg,
     199              :                                   "misc-isolation"));
     200            1 :   TDB_account (pg,
     201              :                10,
     202              :                &account);
     203            1 :   FAILIF (1 != TDB_count (pg,
     204              :                           "FROM wire_targets"));
     205            1 :   TALER_EXCHANGEDB_rollback (pg);
     206            1 :   FAILIF (0 != TDB_count (pg,
     207              :                           "FROM wire_targets"));
     208            1 :   TDB_account_free (&account);
     209              : 
     210            1 :   FAILIF (GNUNET_OK !=
     211              :           TALER_EXCHANGEDB_start (pg,
     212              :                                   "misc-isolation"));
     213            1 :   TDB_account (pg,
     214              :                10,
     215              :                &account);
     216            1 :   FAILIF (0 > TALER_EXCHANGEDB_commit (pg));
     217            1 :   FAILIF (1 != TDB_count (pg,
     218              :                           "FROM wire_targets"));
     219            1 :   return 0;
     220              : }
     221              : 
     222              : 
     223              : /**
     224              :  * Preflight is happy on an idle connection and cleans up after a caller
     225              :  * that forgot to end its transaction.
     226              :  *
     227              :  * @param pg the database context
     228              :  * @return 0 on success
     229              :  */
     230              : static int
     231            1 : check_preflight (struct TALER_EXCHANGEDB_PostgresContext *pg)
     232              : {
     233            1 :   FAILIF (GNUNET_OK !=
     234              :           TALER_EXCHANGEDB_preflight (pg));
     235              : 
     236              :   /* a forgotten transaction is rolled back, and preflight says so */
     237            1 :   FAILIF (GNUNET_OK !=
     238              :           TALER_EXCHANGEDB_start (pg,
     239              :                                   "misc-leak"));
     240            1 :   FAILIF (GNUNET_NO !=
     241              :           TALER_EXCHANGEDB_preflight (pg));
     242            1 :   FAILIF (NULL != pg->transaction_name);
     243            1 :   FAILIF (GNUNET_OK !=
     244              :           TALER_EXCHANGEDB_preflight (pg));
     245              : 
     246              :   /* which is also what start() does for us */
     247            1 :   FAILIF (GNUNET_OK !=
     248              :           TALER_EXCHANGEDB_start (pg,
     249              :                                   "misc-leak"));
     250            1 :   FAILIF (GNUNET_OK !=
     251              :           TALER_EXCHANGEDB_start (pg,
     252              :                                   "misc-after-leak"));
     253            1 :   TALER_EXCHANGEDB_rollback (pg);
     254            1 :   return 0;
     255              : }
     256              : 
     257              : 
     258              : /**
     259              :  * The shard of a merchant key is deterministic and stays in range.
     260              :  *
     261              :  * @param pg the database context
     262              :  * @return 0 on success
     263              :  */
     264              : static int
     265            1 : check_compute_shard (struct TALER_EXCHANGEDB_PostgresContext *pg)
     266              : {
     267              :   struct TALER_MerchantPublicKeyP m1;
     268              :   struct TALER_MerchantPublicKeyP m2;
     269              :   uint64_t s1;
     270              :   uint64_t s2;
     271              : 
     272              :   (void) pg;
     273            1 :   TDB_FILL (m1,
     274              :             1);
     275            1 :   TDB_FILL (m2,
     276              :             2);
     277            1 :   s1 = TALER_EXCHANGEDB_compute_shard (&m1);
     278            1 :   s2 = TALER_EXCHANGEDB_compute_shard (&m2);
     279            1 :   FAILIF (s1 > INT32_MAX);
     280            1 :   FAILIF (s2 > INT32_MAX);
     281            1 :   FAILIF (s1 == s2);
     282              :   /* the same key always maps to the same shard, otherwise the shard
     283              :      locks of the aggregator would not partition the work */
     284            1 :   FAILIF (s1 != TALER_EXCHANGEDB_compute_shard (&m1));
     285            1 :   FAILIF (s2 != TALER_EXCHANGEDB_compute_shard (&m2));
     286            1 :   return 0;
     287              : }
     288              : 
     289              : 
     290              : /**
     291              :  * The coin transaction list adds up and can be released.
     292              :  *
     293              :  * @param pg the database context
     294              :  * @return 0 on success
     295              :  */
     296              : static int
     297            1 : check_coin_list (struct TALER_EXCHANGEDB_PostgresContext *pg)
     298              : {
     299            1 :   struct TALER_EXCHANGEDB_TransactionList *tl = NULL;
     300              :   struct TALER_CoinPublicInfo coin;
     301              :   struct TDB_Deposit dep;
     302              :   struct TALER_Amount balance;
     303              :   struct TALER_Amount total;
     304            1 :   struct TALER_Amount zero = TDB_amount ("0");
     305            1 :   struct TALER_Amount one = TDB_amount ("1");
     306            1 :   struct TALER_Amount two = TDB_amount ("2");
     307              :   struct TALER_DenominationHashP h_denom_pub;
     308            1 :   uint64_t etag = 0;
     309              : 
     310              :   /* an empty list is worth the offset it started from */
     311            1 :   FAILIF (GNUNET_OK !=
     312              :           TALER_EXCHANGEDB_calculate_transaction_list_totals (NULL,
     313              :                                                               &one,
     314              :                                                               &total));
     315            1 :   FAILIF (0 != TALER_amount_cmp (&total,
     316              :                                  &one));
     317              :   /* and freeing it is a no-op */
     318            1 :   TALER_EXCHANGEDB_free_coin_transaction_list (NULL);
     319              : 
     320            1 :   TDB_denom (pg,
     321              :              10,
     322              :              "5",
     323              :              "0.1",
     324              :              &denom);
     325            1 :   TDB_coin (pg,
     326              :             &denom,
     327              :             20,
     328              :             &coin,
     329              :             NULL);
     330            1 :   TDB_deposit (pg,
     331              :                &account,
     332              :                &coin,
     333              :                30,
     334              :                "1",
     335              :                "0.1",
     336              :                GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS),
     337              :                GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS),
     338              :                &dep);
     339            1 :   FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     340              :             TALER_EXCHANGEDB_get_coin_transactions (pg,
     341              :                                                     true,
     342              :                                                     &coin.coin_pub,
     343              :                                                     0,
     344              :                                                     0,
     345              :                                                     &etag,
     346              :                                                     &balance,
     347              :                                                     &h_denom_pub,
     348              :                                                     &tl),
     349              :             TDB_coin_free (&coin));
     350            1 :   TDB_coin_free (&coin);
     351            1 :   FAILIF (NULL == tl);
     352            1 :   FAILIF_C (GNUNET_OK !=
     353              :             TALER_EXCHANGEDB_calculate_transaction_list_totals (tl,
     354              :                                                                 &zero,
     355              :                                                                 &total),
     356              :             TALER_EXCHANGEDB_free_coin_transaction_list (tl));
     357            1 :   FAILIF_C (0 != TALER_amount_cmp (&total,
     358              :                                    &one),
     359              :             TALER_EXCHANGEDB_free_coin_transaction_list (tl));
     360              :   /* the offset is added on top */
     361            1 :   FAILIF_C (GNUNET_OK !=
     362              :             TALER_EXCHANGEDB_calculate_transaction_list_totals (tl,
     363              :                                                                 &one,
     364              :                                                                 &total),
     365              :             TALER_EXCHANGEDB_free_coin_transaction_list (tl));
     366            1 :   FAILIF_C (0 != TALER_amount_cmp (&total,
     367              :                                    &two),
     368              :             TALER_EXCHANGEDB_free_coin_transaction_list (tl));
     369            1 :   TALER_EXCHANGEDB_free_coin_transaction_list (tl);
     370            1 :   return 0;
     371              : }
     372              : 
     373              : 
     374              : /**
     375              :  * The reserve history can be released.
     376              :  *
     377              :  * @param pg the database context
     378              :  * @return 0 on success
     379              :  */
     380              : static int
     381            1 : check_reserve_history (struct TALER_EXCHANGEDB_PostgresContext *pg)
     382              : {
     383            1 :   struct TALER_EXCHANGEDB_ReserveHistory *rh = NULL;
     384              :   struct TALER_ReservePublicKeyP reserve_pub;
     385              :   struct TALER_Amount balance;
     386            1 :   uint64_t etag = 0;
     387            1 :   unsigned int cnt = 0;
     388              : 
     389              :   /* freeing nothing is a no-op */
     390            1 :   TALER_EXCHANGEDB_free_reserve_history (NULL);
     391              : 
     392            1 :   TDB_reserve_in (pg,
     393              :                   &account,
     394              :                   11,
     395              :                   "10",
     396              :                   &reserve_pub);
     397            1 :   (void) TDB_withdraw (pg,
     398              :                        &denom,
     399              :                        &reserve_pub,
     400              :                        11,
     401              :                        "5");
     402            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     403              :           TALER_EXCHANGEDB_get_reserve_history (pg,
     404              :                                                 &reserve_pub,
     405              :                                                 0,
     406              :                                                 0,
     407              :                                                 &etag,
     408              :                                                 &balance,
     409              :                                                 &rh));
     410            1 :   FAILIF (NULL == rh);
     411            1 :   for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
     412            3 :        NULL != pos;
     413            2 :        pos = pos->next)
     414            2 :     cnt++;
     415            1 :   FAILIF_C (2 != cnt,
     416              :             TALER_EXCHANGEDB_free_reserve_history (rh));
     417            1 :   TALER_EXCHANGEDB_free_reserve_history (rh);
     418            1 :   return 0;
     419              : }
     420              : 
     421              : 
     422              : /**
     423              :  * State of the event check.
     424              :  */
     425              : struct EventState
     426              : {
     427              :   /**
     428              :    * How often did the callback fire with a payload?
     429              :    */
     430              :   unsigned int fired;
     431              : 
     432              :   /**
     433              :    * Payload of the last notification.
     434              :    */
     435              :   char payload[16];
     436              : 
     437              :   /**
     438              :    * Number of bytes in @e payload.
     439              :    */
     440              :   size_t payload_len;
     441              : };
     442              : 
     443              : 
     444              : /**
     445              :  * Payload of the notification.
     446              :  */
     447              : #define PAYLOAD "hello"
     448              : 
     449              : 
     450              : /**
     451              :  * Called when the notification arrives (or the listener times out).
     452              :  *
     453              :  * @param cls a `struct EventState *`
     454              :  * @param extra the payload, NULL on timeout
     455              :  * @param extra_size number of bytes in @a extra
     456              :  */
     457              : static void
     458            1 : event_cb (void *cls,
     459              :           const void *extra,
     460              :           size_t extra_size)
     461              : {
     462            1 :   struct EventState *st = cls;
     463              : 
     464            1 :   if (NULL == extra)
     465            0 :     return; /* timeout event, not what we are after */
     466            1 :   st->fired++;
     467            1 :   st->payload_len = GNUNET_MIN (extra_size,
     468              :                                 sizeof (st->payload));
     469            1 :   memcpy (st->payload,
     470              :           extra,
     471              :           st->payload_len);
     472              : }
     473              : 
     474              : 
     475              : /**
     476              :  * A notification sent on the connection reaches a listener registered on
     477              :  * it, and stops reaching it once the listener is cancelled.
     478              :  *
     479              :  * @param pg the database context
     480              :  * @return 0 on success
     481              :  */
     482              : static int
     483            1 : check_events (struct TALER_EXCHANGEDB_PostgresContext *pg)
     484              : {
     485            1 :   struct GNUNET_DB_EventHeaderP es = {
     486            1 :     .size = htons (sizeof (es)),
     487            1 :     .type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED)
     488              :   };
     489              :   struct GNUNET_DB_EventHandler *eh;
     490            1 :   struct EventState st = { 0 };
     491              : 
     492            1 :   eh = TALER_EXCHANGEDB_event_listen (pg,
     493              :                                       GNUNET_TIME_UNIT_MINUTES,
     494              :                                       &es,
     495              :                                       &event_cb,
     496              :                                       &st);
     497            1 :   FAILIF (NULL == eh);
     498            1 :   TALER_EXCHANGEDB_event_notify (pg,
     499              :                                  &es,
     500              :                                  PAYLOAD,
     501              :                                  strlen (PAYLOAD));
     502              :   /* the scheduler task that would pick this up does not get to run while
     503              :      the checks are executing, so poll for it ourselves -- which is also
     504              :      what the exchange does after every notifying transaction */
     505            1 :   GNUNET_PQ_event_do_poll (pg->conn);
     506            1 :   FAILIF_C (1 != st.fired,
     507              :             TALER_EXCHANGEDB_event_listen_cancel (pg, eh));
     508            1 :   FAILIF_C (strlen (PAYLOAD) != st.payload_len,
     509              :             TALER_EXCHANGEDB_event_listen_cancel (pg, eh));
     510            1 :   FAILIF_C (0 != memcmp (st.payload,
     511              :                          PAYLOAD,
     512              :                          st.payload_len),
     513              :             TALER_EXCHANGEDB_event_listen_cancel (pg, eh));
     514              : 
     515              :   /* an unrelated event does not wake us */
     516              :   {
     517            1 :     struct GNUNET_DB_EventHeaderP other = {
     518            1 :       .size = htons (sizeof (other)),
     519            1 :       .type = htons (TALER_DBEVENT_EXCHANGE_NEW_KYC_ATTRIBUTES)
     520              :     };
     521              : 
     522            1 :     TALER_EXCHANGEDB_event_notify (pg,
     523              :                                    &other,
     524              :                                    PAYLOAD,
     525              :                                    strlen (PAYLOAD));
     526            1 :     GNUNET_PQ_event_do_poll (pg->conn);
     527            1 :     FAILIF_C (1 != st.fired,
     528              :               TALER_EXCHANGEDB_event_listen_cancel (pg, eh));
     529              :   }
     530              : 
     531              :   /* and after cancelling, neither does the one we listened for */
     532            1 :   TALER_EXCHANGEDB_event_listen_cancel (pg,
     533              :                                         eh);
     534            1 :   TALER_EXCHANGEDB_event_notify (pg,
     535              :                                  &es,
     536              :                                  PAYLOAD,
     537              :                                  strlen (PAYLOAD));
     538            1 :   GNUNET_PQ_event_do_poll (pg->conn);
     539            1 :   FAILIF (1 != st.fired);
     540            1 :   return 0;
     541              : }
     542              : 
     543              : 
     544              : /**
     545              :  * Customization rules that were never deployed cannot be dropped.
     546              :  *
     547              :  * @param pg the database context
     548              :  * @return 0 on success
     549              :  */
     550              : static int
     551            1 : check_rules (struct TALER_EXCHANGEDB_PostgresContext *pg)
     552              : {
     553            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     554              :           TALER_EXCHANGEDB_disable_rules (pg,
     555              :                                           "no-such-customization"));
     556              :   /* and a schema without SQL files on disk cannot be deployed; the
     557              :      search_path must be back to `exchange' afterwards either way */
     558            1 :   FAILIF (GNUNET_SYSERR ==
     559              :           TALER_EXCHANGEDB_enable_rules (pg,
     560              :                                          "no-such-customization"));
     561              :   /* the search_path is back to `exchange', so an unqualified query
     562              :      still finds the exchange's own tables */
     563            1 :   FAILIF (1 != TDB_count (pg,
     564              :                           "FROM wire_targets"));
     565            1 :   return 0;
     566              : }
     567              : 
     568              : 
     569              : /**
     570              :  * The auditor triggers can be injected into an existing schema.
     571              :  *
     572              :  * @param pg the database context
     573              :  * @return 0 on success
     574              :  */
     575              : static int
     576            1 : check_auditor_triggers (struct TALER_EXCHANGEDB_PostgresContext *pg)
     577              : {
     578            1 :   FAILIF (GNUNET_OK !=
     579              :           TALER_EXCHANGEDB_inject_auditor_triggers (pg));
     580            1 :   return 0;
     581              : }
     582              : 
     583              : 
     584              : /**
     585              :  * Dropping and re-creating the schema leaves an empty but usable
     586              :  * database.  Nothing may run after this check.
     587              :  *
     588              :  * @param pg the database context
     589              :  * @return 0 on success
     590              :  */
     591              : static int
     592            1 : check_schema (struct TALER_EXCHANGEDB_PostgresContext *pg)
     593              : {
     594            1 :   FAILIF (0 == TDB_count (pg,
     595              :                           "FROM wire_targets"));
     596            1 :   FAILIF (GNUNET_OK !=
     597              :           TALER_EXCHANGEDB_drop_tables (pg));
     598              :   /* dropping twice fails: drop.sql says `DROP SCHEMA exchange CASCADE'
     599              :      without IF EXISTS, so there is nothing left to drop the second time */
     600            1 :   FAILIF (GNUNET_OK ==
     601              :           TALER_EXCHANGEDB_drop_tables (pg));
     602            1 :   FAILIF (GNUNET_OK !=
     603              :           TALER_EXCHANGEDB_create_tables (pg,
     604              :                                           false,
     605              :                                           0));
     606            1 :   FAILIF (0 != TDB_count (pg,
     607              :                           "FROM wire_targets"));
     608            1 :   return 0;
     609              : }
     610              : 
     611              : 
     612              : /**
     613              :  * The checks to run, in order.
     614              :  */
     615              : static const struct TDB_Test tests[] = {
     616              :   { "misc-transactions",
     617              :     &check_transactions },
     618              :   { "misc-isolation",
     619              :     &check_isolation },
     620              :   { "misc-preflight",
     621              :     &check_preflight },
     622              :   { "misc-compute-shard",
     623              :     &check_compute_shard },
     624              :   { "misc-coin-list",
     625              :     &check_coin_list },
     626              :   { "misc-reserve-history",
     627              :     &check_reserve_history },
     628              :   { "misc-events",
     629              :     &check_events },
     630              :   { "misc-rules",
     631              :     &check_rules },
     632              :   { "misc-auditor-triggers",
     633              :     &check_auditor_triggers },
     634              :   { "misc-schema",
     635              :     &check_schema },
     636              :   { NULL, NULL }
     637              : };
     638              : 
     639              : 
     640              : int
     641            1 : main (int argc,
     642              :       char *const *argv)
     643              : {
     644              :   int ret;
     645              : 
     646            1 :   ret = TDB_main (argc,
     647              :                   argv,
     648              :                   "test-misc",
     649              :                   "Tests for the exchangedb functions without a table",
     650              :                   tests);
     651            1 :   TDB_denom_free (&denom);
     652            1 :   TDB_account_free (&account);
     653            1 :   return ret;
     654              : }
     655              : 
     656              : 
     657              : /* end of test_misc.c */
        

Generated by: LCOV version 2.0-1