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

            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_kyc_alerts.c
      18              :  * @brief tests for the exchangedb functions whose primary table is
      19              :  *        `kyc_alerts`
      20              :  * @author Christian Grothoff
      21              :  *
      22              :  * Covers #TALER_EXCHANGEDB_do_drain_kyc_alert(), and that the table keeps
      23              :  * one alert per account and trigger type.
      24              :  *
      25              :  * `kyc_alerts` is a work queue: the stored procedures that change the KYC
      26              :  * state of an account append a row, and taler-exchange-aggregator drains
      27              :  * it one row at a time.  Nothing exported writes to it directly, so the
      28              :  * rows here are produced through
      29              :  * #TALER_EXCHANGEDB_insert_aml_program_failure(), the cheapest of the
      30              :  * three producers.
      31              :  */
      32              : #include "test_common.h"
      33              : #include "exchange-database/do_drain_kyc_alert.h"
      34              : #include "exchange-database/insert_aml_program_failure.h"
      35              : 
      36              : 
      37              : /**
      38              :  * Trigger type the aggregator drains, and the only one any stored
      39              :  * procedure ever writes.
      40              :  */
      41              : #define AGGREGATOR_TRIGGER 1
      42              : 
      43              : /**
      44              :  * Trigger type of a (hypothetical) second receiver of alerts.
      45              :  */
      46              : #define OTHER_TRIGGER 2
      47              : 
      48              : 
      49              : /**
      50              :  * The two accounts we raise alerts for.
      51              :  */
      52              : static struct TDB_Account account[2];
      53              : 
      54              : 
      55              : /**
      56              :  * Nothing to drain while the queue is empty.
      57              :  *
      58              :  * @param pg the database context
      59              :  * @return 0 on success
      60              :  */
      61              : static int
      62            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
      63              : {
      64              :   struct TALER_NormalizedPaytoHashP h_payto;
      65              : 
      66            3 :   for (unsigned int i = 0; i < 2; i++)
      67            2 :     TDB_account (pg,
      68              :                  10 + i,
      69              :                  &account[i]);
      70            1 :   memset (&h_payto,
      71              :           0,
      72              :           sizeof (h_payto));
      73            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      74              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
      75              :                                                AGGREGATOR_TRIGGER,
      76              :                                                &h_payto));
      77            1 :   return 0;
      78              : }
      79              : 
      80              : 
      81              : /**
      82              :  * A KYC state change queues exactly one alert per account.
      83              :  *
      84              :  * @param pg the database context
      85              :  * @return 0 on success
      86              :  */
      87              : static int
      88            1 : check_raise (struct TALER_EXCHANGEDB_PostgresContext *pg)
      89              : {
      90            3 :   for (unsigned int i = 0; i < 2; i++)
      91            2 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
      92              :             TALER_EXCHANGEDB_insert_aml_program_failure (
      93              :               pg,
      94              :               0,
      95              :               &account[i].h_normalized,
      96              :               "no such AML program",
      97              :               TALER_EC_EXCHANGE_GENERIC_KYC_FAILED));
      98            1 :   FAILIF (2 != TDB_count (pg,
      99              :                           "FROM kyc_alerts"
     100              :                           " WHERE trigger_type=%d",
     101              :                           AGGREGATOR_TRIGGER));
     102              : 
     103              :   /* a second state change on an account that is already queued does not
     104              :      queue it twice */
     105            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     106              :           TALER_EXCHANGEDB_insert_aml_program_failure (
     107              :             pg,
     108              :             0,
     109              :             &account[0].h_normalized,
     110              :             "still no such AML program",
     111              :             TALER_EC_EXCHANGE_GENERIC_KYC_FAILED));
     112            1 :   FAILIF (2 != TDB_count (pg,
     113              :                           "FROM kyc_alerts"));
     114            1 :   return 0;
     115              : }
     116              : 
     117              : 
     118              : /**
     119              :  * Draining returns the queued accounts one by one and removes them.
     120              :  *
     121              :  * @param pg the database context
     122              :  * @return 0 on success
     123              :  */
     124              : static int
     125            1 : check_drain (struct TALER_EXCHANGEDB_PostgresContext *pg)
     126              : {
     127              :   struct TALER_NormalizedPaytoHashP first;
     128              :   struct TALER_NormalizedPaytoHashP second;
     129              : 
     130              :   /* nobody listens for this trigger type, so the queue looks empty */
     131            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     132              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     133              :                                                AGGREGATOR_TRIGGER + 1,
     134              :                                                &first));
     135            1 :   FAILIF (2 != TDB_count (pg,
     136              :                           "FROM kyc_alerts"));
     137              : 
     138            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     139              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     140              :                                                AGGREGATOR_TRIGGER,
     141              :                                                &first));
     142            1 :   FAILIF (1 != TDB_count (pg,
     143              :                           "FROM kyc_alerts"));
     144            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     145              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     146              :                                                AGGREGATOR_TRIGGER,
     147              :                                                &second));
     148            1 :   FAILIF (0 != TDB_count (pg,
     149              :                           "FROM kyc_alerts"));
     150              : 
     151              :   /* both of our accounts came back, each exactly once */
     152            1 :   FAILIF (0 == GNUNET_memcmp (&first,
     153              :                               &second));
     154            3 :   for (unsigned int i = 0; i < 2; i++)
     155              :   {
     156            2 :     unsigned int seen = 0;
     157              : 
     158            2 :     if (0 == GNUNET_memcmp (&first,
     159              :                             &account[i].h_normalized))
     160            1 :       seen++;
     161            2 :     if (0 == GNUNET_memcmp (&second,
     162              :                             &account[i].h_normalized))
     163            1 :       seen++;
     164            2 :     FAILIF (1 != seen);
     165              :   }
     166              : 
     167              :   /* and the queue is empty again */
     168            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     169              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     170              :                                                AGGREGATOR_TRIGGER,
     171              :                                                &first));
     172            1 :   return 0;
     173              : }
     174              : 
     175              : 
     176              : /**
     177              :  * An account that was drained can be queued again.
     178              :  *
     179              :  * @param pg the database context
     180              :  * @return 0 on success
     181              :  */
     182              : static int
     183            1 : check_requeue (struct TALER_EXCHANGEDB_PostgresContext *pg)
     184              : {
     185              :   struct TALER_NormalizedPaytoHashP h_payto;
     186              : 
     187            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     188              :           TALER_EXCHANGEDB_insert_aml_program_failure (
     189              :             pg,
     190              :             0,
     191              :             &account[1].h_normalized,
     192              :             "and again",
     193              :             TALER_EC_EXCHANGE_GENERIC_KYC_FAILED));
     194            1 :   FAILIF (1 != TDB_count (pg,
     195              :                           "FROM kyc_alerts"));
     196            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     197              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     198              :                                                AGGREGATOR_TRIGGER,
     199              :                                                &h_payto));
     200            1 :   FAILIF (0 != GNUNET_memcmp (&h_payto,
     201              :                               &account[1].h_normalized));
     202            1 :   FAILIF (0 != TDB_count (pg,
     203              :                           "FROM kyc_alerts"));
     204            1 :   return 0;
     205              : }
     206              : 
     207              : 
     208              : /**
     209              :  * Each receiver has its own queue: an account can be queued for two
     210              :  * receivers at once, and draining it for one leaves it queued for the
     211              :  * other.
     212              :  *
     213              :  * @param pg the database context
     214              :  * @return 0 on success
     215              :  */
     216              : static int
     217            1 : check_per_trigger (struct TALER_EXCHANGEDB_PostgresContext *pg)
     218              : {
     219              :   struct TALER_NormalizedPaytoHashP h_payto;
     220              :   char *hex;
     221              : 
     222              :   /* no producer writes another trigger type yet, so do it by hand */
     223            1 :   hex = TDB_hex (&account[0].h_normalized,
     224              :                  sizeof (account[0].h_normalized));
     225            1 :   FAILIF_C (GNUNET_OK !=
     226              :             TDB_exec (pg,
     227              :                       "INSERT INTO kyc_alerts"
     228              :                       " (h_payto,trigger_type)"
     229              :                       " VALUES (decode('%s','hex'),%d);",
     230              :                       hex,
     231              :                       OTHER_TRIGGER),
     232              :             GNUNET_free (hex));
     233            1 :   GNUNET_free (hex);
     234            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     235              :           TALER_EXCHANGEDB_insert_aml_program_failure (
     236              :             pg,
     237              :             0,
     238              :             &account[0].h_normalized,
     239              :             "for the aggregator",
     240              :             TALER_EC_EXCHANGE_GENERIC_KYC_FAILED));
     241              :   /* both alerts for the same account are queued */
     242            1 :   FAILIF (2 != TDB_count (pg,
     243              :                           "FROM kyc_alerts"));
     244            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     245              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     246              :                                                AGGREGATOR_TRIGGER,
     247              :                                                &h_payto));
     248            1 :   FAILIF (0 != GNUNET_memcmp (&h_payto,
     249              :                               &account[0].h_normalized));
     250              :   /* draining it for the aggregator leaves the other receiver's alert */
     251            1 :   FAILIF (1 != TDB_count (pg,
     252              :                           "FROM kyc_alerts"
     253              :                           " WHERE trigger_type=%d",
     254              :                           OTHER_TRIGGER));
     255            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     256              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     257              :                                                AGGREGATOR_TRIGGER,
     258              :                                                &h_payto));
     259            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     260              :           TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
     261              :                                                OTHER_TRIGGER,
     262              :                                                &h_payto));
     263            1 :   FAILIF (0 != GNUNET_memcmp (&h_payto,
     264              :                               &account[0].h_normalized));
     265            1 :   FAILIF (0 != TDB_count (pg,
     266              :                           "FROM kyc_alerts"));
     267            1 :   return 0;
     268              : }
     269              : 
     270              : 
     271              : /**
     272              :  * The checks to run, in order.
     273              :  */
     274              : static const struct TDB_Test tests[] = {
     275              :   { "kyc-alerts-empty",
     276              :     &check_empty },
     277              :   { "kyc-alerts-raise",
     278              :     &check_raise },
     279              :   { "kyc-alerts-drain",
     280              :     &check_drain },
     281              :   { "kyc-alerts-requeue",
     282              :     &check_requeue },
     283              :   { "kyc-alerts-per-trigger",
     284              :     &check_per_trigger },
     285              :   { NULL, NULL }
     286              : };
     287              : 
     288              : 
     289              : int
     290            1 : main (int argc,
     291              :       char *const *argv)
     292              : {
     293              :   int ret;
     294              : 
     295            1 :   ret = TDB_main (argc,
     296              :                   argv,
     297              :                   "test-kyc-alerts",
     298              :                   "Tests for the exchangedb `kyc_alerts' table",
     299              :                   tests);
     300            3 :   for (unsigned int i = 0; i < 2; i++)
     301            2 :     TDB_account_free (&account[i]);
     302            1 :   return ret;
     303              : }
     304              : 
     305              : 
     306              : /* end of test_kyc_alerts.c */
        

Generated by: LCOV version 2.0-1