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_auditor_denom_sigs.c
18 : * @brief tests for the exchangedb functions whose primary table is
19 : * `auditor_denom_sigs`
20 : * @author Christian Grothoff
21 : *
22 : * Covers #TALER_EXCHANGEDB_insert_auditor_denom_sig(),
23 : * #TALER_EXCHANGEDB_get_auditor_denom_sig() and
24 : * #TALER_EXCHANGEDB_iterate_auditor_denominations().
25 : *
26 : * The table references `auditors` and `denominations`, and the insert
27 : * resolves both by their natural keys inside the statement -- so an unknown
28 : * auditor or denomination has to come back as "nothing inserted". Fixtures
29 : * come from #TALER_EXCHANGEDB_insert_auditor() and TDB_denom(), whose own
30 : * tables are covered by test_auditors.c and test_denominations.c.
31 : */
32 : #include "test_common.h"
33 : #include "exchange-database/insert_auditor.h"
34 : #include "exchange-database/update_auditor.h"
35 : #include "exchange-database/insert_auditor_denom_sig.h"
36 : #include "exchange-database/get_auditor_denom_sig.h"
37 : #include "exchange-database/iterate_auditor_denominations.h"
38 :
39 :
40 : /**
41 : * Closure for #count_cb().
42 : */
43 : struct CountContext
44 : {
45 : /**
46 : * Auditor we are looking for.
47 : */
48 : const struct TALER_AuditorPublicKeyP *auditor_pub;
49 :
50 : /**
51 : * Denomination we are looking for.
52 : */
53 : const struct TALER_DenominationHashP *h_denom_pub;
54 :
55 : /**
56 : * How many rows did the callback see in total?
57 : */
58 : unsigned int total;
59 :
60 : /**
61 : * How many times did we see the pair we are after?
62 : */
63 : unsigned int matched;
64 :
65 : /**
66 : * Signature reported for that pair.
67 : */
68 : struct TALER_AuditorSignatureP auditor_sig;
69 : };
70 :
71 :
72 : /**
73 : * Callback for #TALER_EXCHANGEDB_iterate_auditor_denominations().
74 : *
75 : * @param cls a `struct CountContext *`
76 : * @param auditor_pub public key of the auditor
77 : * @param h_denom_pub denomination audited by @a auditor_pub
78 : * @param auditor_sig the auditor's signature
79 : */
80 : static void
81 1 : count_cb (void *cls,
82 : const struct TALER_AuditorPublicKeyP *auditor_pub,
83 : const struct TALER_DenominationHashP *h_denom_pub,
84 : const struct TALER_AuditorSignatureP *auditor_sig)
85 : {
86 1 : struct CountContext *ctx = cls;
87 :
88 1 : ctx->total++;
89 1 : if ( (0 != GNUNET_memcmp (auditor_pub,
90 1 : ctx->auditor_pub)) ||
91 1 : (0 != GNUNET_memcmp (h_denom_pub,
92 : ctx->h_denom_pub)) )
93 0 : return;
94 1 : ctx->matched++;
95 1 : ctx->auditor_sig = *auditor_sig;
96 : }
97 :
98 :
99 : /**
100 : * Neither half of the pair existing means nothing is inserted and nothing
101 : * is found.
102 : *
103 : * @param pg the database context
104 : * @return 0 on success
105 : */
106 : static int
107 1 : check_unknown_references (struct TALER_EXCHANGEDB_PostgresContext *pg)
108 : {
109 : struct TALER_AuditorPublicKeyP auditor_pub;
110 : struct TALER_DenominationHashP h_denom_pub;
111 : struct TALER_AuditorSignatureP auditor_sig;
112 : struct TALER_AuditorSignatureP got;
113 : struct TDB_Denom denom;
114 :
115 1 : TDB_FILL (auditor_pub,
116 : 1);
117 1 : TDB_FILL (h_denom_pub,
118 : 1);
119 1 : TDB_FILL (auditor_sig,
120 : 1);
121 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
122 : TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
123 : &h_denom_pub,
124 : &auditor_pub,
125 : &got));
126 : /* neither the auditor nor the denomination exist */
127 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
128 : TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
129 : &h_denom_pub,
130 : &auditor_pub,
131 : &auditor_sig));
132 : /* the denomination exists, the auditor does not */
133 1 : TDB_denom (pg,
134 : 10,
135 : "5",
136 : "0.1",
137 : &denom);
138 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
139 : TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
140 : &denom.h_denom_pub,
141 : &auditor_pub,
142 : &auditor_sig),
143 : TDB_denom_free (&denom));
144 : /* the auditor exists, the denomination does not */
145 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
146 : TALER_EXCHANGEDB_insert_auditor (pg,
147 : &auditor_pub,
148 : "https://auditor.example/",
149 : "The Auditor",
150 : GNUNET_TIME_timestamp_get ()),
151 : TDB_denom_free (&denom));
152 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
153 : TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
154 : &h_denom_pub,
155 : &auditor_pub,
156 : &auditor_sig),
157 : TDB_denom_free (&denom));
158 1 : FAILIF_C (0 != TDB_count (pg,
159 : "FROM auditor_denom_sigs"),
160 : TDB_denom_free (&denom));
161 1 : TDB_denom_free (&denom);
162 1 : return 0;
163 : }
164 :
165 :
166 : /**
167 : * With both halves present the signature is stored, found and iterated;
168 : * a repeated insert is a no-op.
169 : *
170 : * @param pg the database context
171 : * @return 0 on success
172 : */
173 : static int
174 1 : check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg)
175 : {
176 : struct TALER_AuditorPublicKeyP auditor_pub;
177 : struct TALER_AuditorSignatureP auditor_sig;
178 : struct TALER_AuditorSignatureP other_sig;
179 : struct TALER_AuditorSignatureP got;
180 : struct TDB_Denom denom;
181 : struct CountContext ctx;
182 :
183 : /* the auditor and denomination from the previous check */
184 1 : TDB_FILL (auditor_pub,
185 : 1);
186 1 : TDB_FILL (auditor_sig,
187 : 1);
188 1 : TDB_FILL (other_sig,
189 : 77);
190 1 : TDB_denom (pg,
191 : 10,
192 : "5",
193 : "0.1",
194 : &denom);
195 : /* TDB_denom() with the same seed builds the same key, so the row is the
196 : one the previous check created; that is exactly what we want here. */
197 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
198 : TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
199 : &denom.h_denom_pub,
200 : &auditor_pub,
201 : &auditor_sig),
202 : TDB_denom_free (&denom));
203 1 : memset (&got,
204 : 0,
205 : sizeof (got));
206 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
207 : TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
208 : &denom.h_denom_pub,
209 : &auditor_pub,
210 : &got),
211 : TDB_denom_free (&denom));
212 1 : FAILIF_C (0 != GNUNET_memcmp (&got,
213 : &auditor_sig),
214 : TDB_denom_free (&denom));
215 :
216 : /* re-inserting with a different signature does nothing (ON CONFLICT DO
217 : NOTHING), and in particular does not overwrite the stored one */
218 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
219 : TALER_EXCHANGEDB_insert_auditor_denom_sig (pg,
220 : &denom.h_denom_pub,
221 : &auditor_pub,
222 : &other_sig),
223 : TDB_denom_free (&denom));
224 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
225 : TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
226 : &denom.h_denom_pub,
227 : &auditor_pub,
228 : &got),
229 : TDB_denom_free (&denom));
230 1 : FAILIF_C (0 != GNUNET_memcmp (&got,
231 : &auditor_sig),
232 : TDB_denom_free (&denom));
233 :
234 1 : memset (&ctx,
235 : 0,
236 : sizeof (ctx));
237 1 : ctx.auditor_pub = &auditor_pub;
238 1 : ctx.h_denom_pub = &denom.h_denom_pub;
239 1 : FAILIF_C (0 >=
240 : TALER_EXCHANGEDB_iterate_auditor_denominations (pg,
241 : &count_cb,
242 : &ctx),
243 : TDB_denom_free (&denom));
244 1 : FAILIF_C (1 != ctx.matched,
245 : TDB_denom_free (&denom));
246 1 : FAILIF_C (0 != GNUNET_memcmp (&ctx.auditor_sig,
247 : &auditor_sig),
248 : TDB_denom_free (&denom));
249 1 : TDB_denom_free (&denom);
250 1 : return 0;
251 : }
252 :
253 :
254 : /**
255 : * A disabled auditor keeps its rows but drops out of the iterator.
256 : *
257 : * @param pg the database context
258 : * @return 0 on success
259 : */
260 : static int
261 1 : check_disabled_auditor (struct TALER_EXCHANGEDB_PostgresContext *pg)
262 : {
263 : struct TALER_AuditorPublicKeyP auditor_pub;
264 : struct TALER_AuditorSignatureP got;
265 : struct TDB_Denom denom;
266 : struct CountContext ctx;
267 :
268 1 : TDB_FILL (auditor_pub,
269 : 1);
270 1 : TDB_denom (pg,
271 : 10,
272 : "5",
273 : "0.1",
274 : &denom);
275 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
276 : TALER_EXCHANGEDB_update_auditor (pg,
277 : &auditor_pub,
278 : "https://auditor.example/",
279 : "The Auditor",
280 : GNUNET_TIME_timestamp_get (),
281 : false),
282 : TDB_denom_free (&denom));
283 1 : memset (&ctx,
284 : 0,
285 : sizeof (ctx));
286 1 : ctx.auditor_pub = &auditor_pub;
287 1 : ctx.h_denom_pub = &denom.h_denom_pub;
288 1 : FAILIF_C (0 >
289 : TALER_EXCHANGEDB_iterate_auditor_denominations (pg,
290 : &count_cb,
291 : &ctx),
292 : TDB_denom_free (&denom));
293 1 : FAILIF_C (0 != ctx.matched,
294 : TDB_denom_free (&denom));
295 1 : FAILIF_C (0 != ctx.total,
296 : TDB_denom_free (&denom));
297 : /* the row itself is untouched, and the direct lookup ignores is_active */
298 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
299 : TALER_EXCHANGEDB_get_auditor_denom_sig (pg,
300 : &denom.h_denom_pub,
301 : &auditor_pub,
302 : &got),
303 : TDB_denom_free (&denom));
304 1 : FAILIF_C (1 != TDB_count (pg,
305 : "FROM auditor_denom_sigs"),
306 : TDB_denom_free (&denom));
307 1 : TDB_denom_free (&denom);
308 1 : return 0;
309 : }
310 :
311 :
312 : /**
313 : * The checks to run, in order.
314 : */
315 : static const struct TDB_Test tests[] = {
316 : { "auditor-denom-sigs-unknown-references",
317 : &check_unknown_references },
318 : { "auditor-denom-sigs-insert-and-lookup",
319 : &check_insert_and_lookup },
320 : { "auditor-denom-sigs-disabled-auditor",
321 : &check_disabled_auditor },
322 : { NULL, NULL }
323 : };
324 :
325 :
326 : int
327 1 : main (int argc,
328 : char *const *argv)
329 : {
330 1 : return TDB_main (argc,
331 : argv,
332 : "test-auditor-denom-sigs",
333 : "Tests for the exchangedb `auditor_denom_sigs' table",
334 : tests);
335 : }
336 :
337 :
338 : /* end of test_auditor_denom_sigs.c */
|