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().
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 1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
57 : {
58 : struct TALER_NormalizedPaytoHashP h_payto;
59 :
60 3 : for (unsigned int i = 0; i < 2; i++)
61 2 : TDB_account (pg,
62 : 10 + i,
63 : &account[i]);
64 1 : memset (&h_payto,
65 : 0,
66 : sizeof (h_payto));
67 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
68 : TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
69 : AGGREGATOR_TRIGGER,
70 : &h_payto));
71 1 : 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 1 : check_raise (struct TALER_EXCHANGEDB_PostgresContext *pg)
83 : {
84 3 : for (unsigned int i = 0; i < 2; i++)
85 2 : 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 1 : 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 1 : 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 1 : FAILIF (2 != TDB_count (pg,
107 : "FROM kyc_alerts"));
108 1 : 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 1 : 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 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
126 : TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
127 : AGGREGATOR_TRIGGER + 1,
128 : &first));
129 1 : FAILIF (2 != TDB_count (pg,
130 : "FROM kyc_alerts"));
131 :
132 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
133 : TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
134 : AGGREGATOR_TRIGGER,
135 : &first));
136 1 : FAILIF (1 != TDB_count (pg,
137 : "FROM kyc_alerts"));
138 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
139 : TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
140 : AGGREGATOR_TRIGGER,
141 : &second));
142 1 : FAILIF (0 != TDB_count (pg,
143 : "FROM kyc_alerts"));
144 :
145 : /* both of our accounts came back, each exactly once */
146 1 : FAILIF (0 == GNUNET_memcmp (&first,
147 : &second));
148 3 : for (unsigned int i = 0; i < 2; i++)
149 : {
150 2 : unsigned int seen = 0;
151 :
152 2 : if (0 == GNUNET_memcmp (&first,
153 : &account[i].h_normalized))
154 1 : seen++;
155 2 : if (0 == GNUNET_memcmp (&second,
156 : &account[i].h_normalized))
157 1 : seen++;
158 2 : FAILIF (1 != seen);
159 : }
160 :
161 : /* and the queue is empty again */
162 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
163 : TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
164 : AGGREGATOR_TRIGGER,
165 : &first));
166 1 : 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 1 : check_requeue (struct TALER_EXCHANGEDB_PostgresContext *pg)
178 : {
179 : struct TALER_NormalizedPaytoHashP h_payto;
180 :
181 1 : 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 1 : FAILIF (1 != TDB_count (pg,
189 : "FROM kyc_alerts"));
190 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
191 : TALER_EXCHANGEDB_do_drain_kyc_alert (pg,
192 : AGGREGATOR_TRIGGER,
193 : &h_payto));
194 1 : FAILIF (0 != GNUNET_memcmp (&h_payto,
195 : &account[1].h_normalized));
196 1 : FAILIF (0 != TDB_count (pg,
197 : "FROM kyc_alerts"));
198 1 : 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 1 : main (int argc,
220 : char *const *argv)
221 : {
222 : int ret;
223 :
224 1 : ret = TDB_main (argc,
225 : argv,
226 : "test-kyc-alerts",
227 : "Tests for the exchangedb `kyc_alerts' table",
228 : tests);
229 3 : for (unsigned int i = 0; i < 2; i++)
230 2 : TDB_account_free (&account[i]);
231 1 : return ret;
232 : }
233 :
234 :
235 : /* end of test_kyc_alerts.c */
|