LCOV - code coverage report
Current view: top level - exchangedb - test_auditors.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 76 76
Test Date: 2026-09-11 18:55:36 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_auditors.c
      18              :  * @brief tests for the exchangedb functions whose primary table is `auditors`
      19              :  * @author Christian Grothoff
      20              :  *
      21              :  * Covers #TALER_EXCHANGEDB_insert_auditor(),
      22              :  * #TALER_EXCHANGEDB_update_auditor(),
      23              :  * #TALER_EXCHANGEDB_get_auditor_status(),
      24              :  * #TALER_EXCHANGEDB_get_auditor_timestamp() and
      25              :  * #TALER_EXCHANGEDB_iterate_active_auditors().
      26              :  *
      27              :  * `auditors` has no foreign keys, so the checks need no fixtures.
      28              :  */
      29              : #include "test_common.h"
      30              : #include "exchange-database/insert_auditor.h"
      31              : #include "exchange-database/update_auditor.h"
      32              : #include "exchange-database/get_auditor_status.h"
      33              : #include "exchange-database/get_auditor_timestamp.h"
      34              : #include "exchange-database/iterate_active_auditors.h"
      35              : 
      36              : 
      37              : /**
      38              :  * Nothing is known about an auditor that was never inserted.
      39              :  *
      40              :  * @param pg the database context
      41              :  * @return 0 on success
      42              :  */
      43              : static int
      44            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
      45              : {
      46              :   struct TALER_AuditorPublicKeyP auditor_pub;
      47              :   struct GNUNET_TIME_Timestamp last_date;
      48            1 :   char *url = NULL;
      49            1 :   bool enabled = true;
      50              : 
      51            1 :   TDB_FILL (auditor_pub,
      52              :             1);
      53            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      54              :           TALER_EXCHANGEDB_get_auditor_status (pg,
      55              :                                                &auditor_pub,
      56              :                                                &url,
      57              :                                                &enabled));
      58            1 :   FAILIF (NULL != url);
      59            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      60              :           TALER_EXCHANGEDB_get_auditor_timestamp (pg,
      61              :                                                   &auditor_pub,
      62              :                                                   &last_date));
      63              :   /* updating an auditor that is not on file does not create one */
      64            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      65              :           TALER_EXCHANGEDB_update_auditor (pg,
      66              :                                            &auditor_pub,
      67              :                                            "https://auditor.example/",
      68              :                                            "Nobody",
      69              :                                            GNUNET_TIME_timestamp_get (),
      70              :                                            true));
      71            1 :   FAILIF (0 != TDB_count (pg,
      72              :                           "FROM auditors"));
      73            1 :   return 0;
      74              : }
      75              : 
      76              : 
      77              : /**
      78              :  * Closure for #count_auditors_cb().
      79              :  */
      80              : struct CountContext
      81              : {
      82              :   /**
      83              :    * Auditor we are looking for.
      84              :    */
      85              :   const struct TALER_AuditorPublicKeyP *auditor_pub;
      86              : 
      87              :   /**
      88              :    * How many auditors did the callback see in total?
      89              :    */
      90              :   unsigned int total;
      91              : 
      92              :   /**
      93              :    * How many times did we see @e auditor_pub?
      94              :    */
      95              :   unsigned int matched;
      96              : 
      97              :   /**
      98              :    * URL reported for @e auditor_pub, owned by this struct.
      99              :    */
     100              :   char *url;
     101              : 
     102              :   /**
     103              :    * Name reported for @e auditor_pub, owned by this struct.
     104              :    */
     105              :   char *name;
     106              : };
     107              : 
     108              : 
     109              : /**
     110              :  * Callback for #TALER_EXCHANGEDB_iterate_active_auditors().
     111              :  *
     112              :  * @param cls a `struct CountContext *`
     113              :  * @param auditor_pub public key of the auditor
     114              :  * @param auditor_url base URL of the auditor
     115              :  * @param auditor_name human-readable name of the auditor
     116              :  */
     117              : static void
     118            4 : count_auditors_cb (void *cls,
     119              :                    const struct TALER_AuditorPublicKeyP *auditor_pub,
     120              :                    const char *auditor_url,
     121              :                    const char *auditor_name)
     122              : {
     123            4 :   struct CountContext *ctx = cls;
     124              : 
     125            4 :   ctx->total++;
     126            4 :   if (0 != GNUNET_memcmp (auditor_pub,
     127              :                           ctx->auditor_pub))
     128            2 :     return;
     129            2 :   ctx->matched++;
     130            2 :   GNUNET_free (ctx->url);
     131            2 :   GNUNET_free (ctx->name);
     132            2 :   ctx->url = GNUNET_strdup (auditor_url);
     133            2 :   ctx->name = GNUNET_strdup (auditor_name);
     134              : }
     135              : 
     136              : 
     137              : /**
     138              :  * Insert an auditor, read it back, then disable and re-enable it.
     139              :  *
     140              :  * @param pg the database context
     141              :  * @return 0 on success
     142              :  */
     143              : static int
     144            1 : check_insert_update (struct TALER_EXCHANGEDB_PostgresContext *pg)
     145              : {
     146              :   struct TALER_AuditorPublicKeyP auditor_pub;
     147              :   struct GNUNET_TIME_Timestamp start;
     148              :   struct GNUNET_TIME_Timestamp later;
     149              :   struct GNUNET_TIME_Timestamp last_date;
     150              :   struct CountContext ctx;
     151            1 :   char *url = NULL;
     152            1 :   bool enabled = false;
     153              : 
     154            1 :   TDB_FILL (auditor_pub,
     155              :             2);
     156            1 :   start = GNUNET_TIME_timestamp_get ();
     157            1 :   later = GNUNET_TIME_absolute_to_timestamp (
     158              :     GNUNET_TIME_absolute_add (start.abs_time,
     159              :                               GNUNET_TIME_UNIT_HOURS));
     160            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     161              :           TALER_EXCHANGEDB_insert_auditor (pg,
     162              :                                            &auditor_pub,
     163              :                                            "https://auditor.example/",
     164              :                                            "The Auditor",
     165              :                                            start));
     166            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     167              :           TALER_EXCHANGEDB_get_auditor_status (pg,
     168              :                                                &auditor_pub,
     169              :                                                &url,
     170              :                                                &enabled));
     171            1 :   FAILIF (NULL == url);
     172            1 :   FAILIF_C (0 != strcmp (url,
     173              :                          "https://auditor.example/"),
     174              :             GNUNET_free (url));
     175            1 :   GNUNET_free (url);
     176              :   /* a fresh auditor is active */
     177            1 :   FAILIF (! enabled);
     178            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     179              :           TALER_EXCHANGEDB_get_auditor_timestamp (pg,
     180              :                                                   &auditor_pub,
     181              :                                                   &last_date));
     182            1 :   FAILIF (GNUNET_TIME_timestamp_cmp (last_date,
     183              :                                      !=,
     184              :                                      start));
     185              : 
     186            1 :   memset (&ctx,
     187              :           0,
     188              :           sizeof (ctx));
     189            1 :   ctx.auditor_pub = &auditor_pub;
     190            1 :   FAILIF (0 >=
     191              :           TALER_EXCHANGEDB_iterate_active_auditors (pg,
     192              :                                                     &count_auditors_cb,
     193              :                                                     &ctx));
     194            1 :   FAILIF_C (1 != ctx.matched,
     195              :             GNUNET_free (ctx.url); GNUNET_free (ctx.name));
     196            1 :   FAILIF_C (0 != strcmp (ctx.name,
     197              :                          "The Auditor"),
     198              :             GNUNET_free (ctx.url); GNUNET_free (ctx.name));
     199            1 :   GNUNET_free (ctx.url);
     200            1 :   GNUNET_free (ctx.name);
     201              : 
     202              :   /* disabling drops the auditor from the active iterator */
     203            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     204              :           TALER_EXCHANGEDB_update_auditor (pg,
     205              :                                            &auditor_pub,
     206              :                                            "https://auditor2.example/",
     207              :                                            "The Other Auditor",
     208              :                                            later,
     209              :                                            false));
     210            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     211              :           TALER_EXCHANGEDB_get_auditor_status (pg,
     212              :                                                &auditor_pub,
     213              :                                                &url,
     214              :                                                &enabled));
     215            1 :   FAILIF_C (0 != strcmp (url,
     216              :                          "https://auditor2.example/"),
     217              :             GNUNET_free (url));
     218            1 :   GNUNET_free (url);
     219            1 :   FAILIF (enabled);
     220            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     221              :           TALER_EXCHANGEDB_get_auditor_timestamp (pg,
     222              :                                                   &auditor_pub,
     223              :                                                   &last_date));
     224            1 :   FAILIF (GNUNET_TIME_timestamp_cmp (last_date,
     225              :                                      !=,
     226              :                                      later));
     227            1 :   memset (&ctx,
     228              :           0,
     229              :           sizeof (ctx));
     230            1 :   ctx.auditor_pub = &auditor_pub;
     231            1 :   FAILIF (0 >
     232              :           TALER_EXCHANGEDB_iterate_active_auditors (pg,
     233              :                                                     &count_auditors_cb,
     234              :                                                     &ctx));
     235            1 :   FAILIF (0 != ctx.matched);
     236              : 
     237              :   /* ...and re-enabling brings it back */
     238            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     239              :           TALER_EXCHANGEDB_update_auditor (pg,
     240              :                                            &auditor_pub,
     241              :                                            "https://auditor2.example/",
     242              :                                            "The Other Auditor",
     243              :                                            later,
     244              :                                            true));
     245            1 :   memset (&ctx,
     246              :           0,
     247              :           sizeof (ctx));
     248            1 :   ctx.auditor_pub = &auditor_pub;
     249            1 :   FAILIF (0 >=
     250              :           TALER_EXCHANGEDB_iterate_active_auditors (pg,
     251              :                                                     &count_auditors_cb,
     252              :                                                     &ctx));
     253            1 :   FAILIF_C (1 != ctx.matched,
     254              :             GNUNET_free (ctx.url); GNUNET_free (ctx.name));
     255            1 :   GNUNET_free (ctx.url);
     256            1 :   GNUNET_free (ctx.name);
     257            1 :   return 0;
     258              : }
     259              : 
     260              : 
     261              : /**
     262              :  * A second auditor is independent of the first, and only the active ones
     263              :  * are iterated.
     264              :  *
     265              :  * @param pg the database context
     266              :  * @return 0 on success
     267              :  */
     268              : static int
     269            1 : check_two_auditors (struct TALER_EXCHANGEDB_PostgresContext *pg)
     270              : {
     271              :   struct TALER_AuditorPublicKeyP a2;
     272              :   struct TALER_AuditorPublicKeyP a3;
     273            1 :   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
     274              :   struct CountContext ctx;
     275              : 
     276            1 :   TDB_FILL (a2,
     277              :             3);
     278            1 :   TDB_FILL (a3,
     279              :             4);
     280            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     281              :           TALER_EXCHANGEDB_insert_auditor (pg,
     282              :                                            &a2,
     283              :                                            "https://a2.example/",
     284              :                                            "A2",
     285              :                                            now));
     286            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     287              :           TALER_EXCHANGEDB_insert_auditor (pg,
     288              :                                            &a3,
     289              :                                            "https://a3.example/",
     290              :                                            "A3",
     291              :                                            now));
     292            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     293              :           TALER_EXCHANGEDB_update_auditor (pg,
     294              :                                            &a3,
     295              :                                            "https://a3.example/",
     296              :                                            "A3",
     297              :                                            now,
     298              :                                            false));
     299            1 :   memset (&ctx,
     300              :           0,
     301              :           sizeof (ctx));
     302            1 :   ctx.auditor_pub = &a3;
     303            1 :   FAILIF (0 >=
     304              :           TALER_EXCHANGEDB_iterate_active_auditors (pg,
     305              :                                                     &count_auditors_cb,
     306              :                                                     &ctx));
     307            1 :   FAILIF (0 != ctx.matched);
     308            1 :   FAILIF (ctx.total !=
     309              :           TDB_count (pg,
     310              :                      "FROM auditors WHERE is_active"));
     311            1 :   FAILIF (ctx.total ==
     312              :           TDB_count (pg,
     313              :                      "FROM auditors"));
     314            1 :   return 0;
     315              : }
     316              : 
     317              : 
     318              : /**
     319              :  * The checks to run, in order.
     320              :  */
     321              : static const struct TDB_Test tests[] = {
     322              :   { "auditors-empty",
     323              :     &check_empty },
     324              :   { "auditors-insert-update",
     325              :     &check_insert_update },
     326              :   { "auditors-two-auditors",
     327              :     &check_two_auditors },
     328              :   { NULL, NULL }
     329              : };
     330              : 
     331              : 
     332              : int
     333            1 : main (int argc,
     334              :       char *const *argv)
     335              : {
     336            1 :   return TDB_main (argc,
     337              :                    argv,
     338              :                    "test-auditors",
     339              :                    "Tests for the exchangedb `auditors' table",
     340              :                    tests);
     341              : }
     342              : 
     343              : 
     344              : /* end of test_auditors.c */
        

Generated by: LCOV version 2.0-1