test_kyc_alerts.c (7040B)
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(). 23 * 24 * `kyc_alerts` is a work queue: the stored procedures that change the KYC 25 * state of an account append a row, and taler-exchange-aggregator drains 26 * it one row at a time. Nothing exported writes to it directly, so the 27 * rows here are produced through 28 * #TALER_EXCHANGEDB_insert_aml_program_failure(), the cheapest of the 29 * three producers. 30 */ 31 #include "test_common.h" 32 #include "exchange-database/do_drain_kyc_alert.h" 33 #include "exchange-database/insert_aml_program_failure.h" 34 35 36 /** 37 * Trigger type the aggregator drains, and the only one any stored 38 * procedure ever writes. 39 */ 40 #define AGGREGATOR_TRIGGER 1 41 42 43 /** 44 * The two accounts we raise alerts for. 45 */ 46 static struct TDB_Account account[2]; 47 48 49 /** 50 * Nothing to drain while the queue is empty. 51 * 52 * @param pg the database context 53 * @return 0 on success 54 */ 55 static int 56 check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg) 57 { 58 struct TALER_NormalizedPaytoHashP h_payto; 59 60 for (unsigned int i = 0; i < 2; i++) 61 TDB_account (pg, 62 10 + i, 63 &account[i]); 64 memset (&h_payto, 65 0, 66 sizeof (h_payto)); 67 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 68 TALER_EXCHANGEDB_do_drain_kyc_alert (pg, 69 AGGREGATOR_TRIGGER, 70 &h_payto)); 71 return 0; 72 } 73 74 75 /** 76 * A KYC state change queues exactly one alert per account. 77 * 78 * @param pg the database context 79 * @return 0 on success 80 */ 81 static int 82 check_raise (struct TALER_EXCHANGEDB_PostgresContext *pg) 83 { 84 for (unsigned int i = 0; i < 2; i++) 85 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 86 TALER_EXCHANGEDB_insert_aml_program_failure ( 87 pg, 88 0, 89 &account[i].h_normalized, 90 "no such AML program", 91 TALER_EC_EXCHANGE_GENERIC_KYC_FAILED)); 92 FAILIF (2 != TDB_count (pg, 93 "FROM kyc_alerts" 94 " WHERE trigger_type=%d", 95 AGGREGATOR_TRIGGER)); 96 97 /* a second state change on an account that is already queued does not 98 queue it twice */ 99 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 100 TALER_EXCHANGEDB_insert_aml_program_failure ( 101 pg, 102 0, 103 &account[0].h_normalized, 104 "still no such AML program", 105 TALER_EC_EXCHANGE_GENERIC_KYC_FAILED)); 106 FAILIF (2 != TDB_count (pg, 107 "FROM kyc_alerts")); 108 return 0; 109 } 110 111 112 /** 113 * Draining returns the queued accounts one by one and removes them. 114 * 115 * @param pg the database context 116 * @return 0 on success 117 */ 118 static int 119 check_drain (struct TALER_EXCHANGEDB_PostgresContext *pg) 120 { 121 struct TALER_NormalizedPaytoHashP first; 122 struct TALER_NormalizedPaytoHashP second; 123 124 /* nobody listens for this trigger type, so the queue looks empty */ 125 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 126 TALER_EXCHANGEDB_do_drain_kyc_alert (pg, 127 AGGREGATOR_TRIGGER + 1, 128 &first)); 129 FAILIF (2 != TDB_count (pg, 130 "FROM kyc_alerts")); 131 132 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 133 TALER_EXCHANGEDB_do_drain_kyc_alert (pg, 134 AGGREGATOR_TRIGGER, 135 &first)); 136 FAILIF (1 != TDB_count (pg, 137 "FROM kyc_alerts")); 138 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 139 TALER_EXCHANGEDB_do_drain_kyc_alert (pg, 140 AGGREGATOR_TRIGGER, 141 &second)); 142 FAILIF (0 != TDB_count (pg, 143 "FROM kyc_alerts")); 144 145 /* both of our accounts came back, each exactly once */ 146 FAILIF (0 == GNUNET_memcmp (&first, 147 &second)); 148 for (unsigned int i = 0; i < 2; i++) 149 { 150 unsigned int seen = 0; 151 152 if (0 == GNUNET_memcmp (&first, 153 &account[i].h_normalized)) 154 seen++; 155 if (0 == GNUNET_memcmp (&second, 156 &account[i].h_normalized)) 157 seen++; 158 FAILIF (1 != seen); 159 } 160 161 /* and the queue is empty again */ 162 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 163 TALER_EXCHANGEDB_do_drain_kyc_alert (pg, 164 AGGREGATOR_TRIGGER, 165 &first)); 166 return 0; 167 } 168 169 170 /** 171 * An account that was drained can be queued again. 172 * 173 * @param pg the database context 174 * @return 0 on success 175 */ 176 static int 177 check_requeue (struct TALER_EXCHANGEDB_PostgresContext *pg) 178 { 179 struct TALER_NormalizedPaytoHashP h_payto; 180 181 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 182 TALER_EXCHANGEDB_insert_aml_program_failure ( 183 pg, 184 0, 185 &account[1].h_normalized, 186 "and again", 187 TALER_EC_EXCHANGE_GENERIC_KYC_FAILED)); 188 FAILIF (1 != TDB_count (pg, 189 "FROM kyc_alerts")); 190 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 191 TALER_EXCHANGEDB_do_drain_kyc_alert (pg, 192 AGGREGATOR_TRIGGER, 193 &h_payto)); 194 FAILIF (0 != GNUNET_memcmp (&h_payto, 195 &account[1].h_normalized)); 196 FAILIF (0 != TDB_count (pg, 197 "FROM kyc_alerts")); 198 return 0; 199 } 200 201 202 /** 203 * The checks to run, in order. 204 */ 205 static const struct TDB_Test tests[] = { 206 { "kyc-alerts-empty", 207 &check_empty }, 208 { "kyc-alerts-raise", 209 &check_raise }, 210 { "kyc-alerts-drain", 211 &check_drain }, 212 { "kyc-alerts-requeue", 213 &check_requeue }, 214 { NULL, NULL } 215 }; 216 217 218 int 219 main (int argc, 220 char *const *argv) 221 { 222 int ret; 223 224 ret = TDB_main (argc, 225 argv, 226 "test-kyc-alerts", 227 "Tests for the exchangedb `kyc_alerts' table", 228 tests); 229 for (unsigned int i = 0; i < 2; i++) 230 TDB_account_free (&account[i]); 231 return ret; 232 } 233 234 235 /* end of test_kyc_alerts.c */