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_prewire.c
18 : * @brief tests for the exchangedb functions whose primary table is `prewire`
19 : * @author Christian Grothoff
20 : *
21 : * Covers #TALER_EXCHANGEDB_insert_prewire(),
22 : * #TALER_EXCHANGEDB_iterate_prewires(),
23 : * #TALER_EXCHANGEDB_update_to_prewire_finished() and
24 : * #TALER_EXCHANGEDB_update_to_prewire_failed().
25 : *
26 : * `prewire` has no foreign keys. The table is a work queue: the iterator
27 : * only reports rows that are neither finished nor failed, which is what the
28 : * checks below are about.
29 : */
30 : #include "test_common.h"
31 : #include "exchange-database/insert_prewire.h"
32 : #include "exchange-database/iterate_prewires.h"
33 : #include "exchange-database/update_to_prewire_finished.h"
34 : #include "exchange-database/update_to_prewire_failed.h"
35 :
36 :
37 : /**
38 : * Closure for #prewire_cb().
39 : */
40 : struct PrewireContext
41 : {
42 : /**
43 : * How many rows did the callback see?
44 : */
45 : unsigned int total;
46 :
47 : /**
48 : * Row of the first entry seen.
49 : */
50 : uint64_t first_row;
51 :
52 : /**
53 : * Payload of the first entry seen, owned by this struct.
54 : */
55 : char *first_buf;
56 :
57 : /**
58 : * Number of bytes in @e first_buf.
59 : */
60 : size_t first_buf_size;
61 :
62 : /**
63 : * Wire method of the first entry seen, owned by this struct.
64 : */
65 : char *first_method;
66 : };
67 :
68 :
69 : /**
70 : * Callback for #TALER_EXCHANGEDB_iterate_prewires().
71 : *
72 : * @param cls a `struct PrewireContext *`
73 : * @param rowid row of the entry
74 : * @param wire_method wire method of the entry
75 : * @param buf payload of the entry
76 : * @param buf_size number of bytes in @a buf
77 : */
78 : static void
79 7 : prewire_cb (void *cls,
80 : uint64_t rowid,
81 : const char *wire_method,
82 : const char *buf,
83 : size_t buf_size)
84 : {
85 7 : struct PrewireContext *ctx = cls;
86 :
87 7 : if (0 == ctx->total++)
88 : {
89 5 : ctx->first_row = rowid;
90 5 : ctx->first_buf = GNUNET_memdup (buf,
91 : buf_size);
92 5 : ctx->first_buf_size = buf_size;
93 5 : ctx->first_method = GNUNET_strdup (wire_method);
94 : }
95 7 : }
96 :
97 :
98 : /**
99 : * Release what #prewire_cb() allocated.
100 : *
101 : * @param[in,out] ctx context to clean up
102 : */
103 : static void
104 6 : ctx_free (struct PrewireContext *ctx)
105 : {
106 6 : GNUNET_free (ctx->first_buf);
107 6 : GNUNET_free (ctx->first_method);
108 6 : }
109 :
110 :
111 : /**
112 : * An empty queue yields nothing, and marking rows that do not exist does
113 : * nothing.
114 : *
115 : * @param pg the database context
116 : * @return 0 on success
117 : */
118 : static int
119 1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
120 : {
121 1 : struct PrewireContext ctx = { 0 };
122 :
123 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
124 : TALER_EXCHANGEDB_iterate_prewires (pg,
125 : 0,
126 : 10,
127 : &prewire_cb,
128 : &ctx));
129 1 : FAILIF (0 != ctx.total);
130 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
131 : TALER_EXCHANGEDB_update_to_prewire_finished (pg,
132 : 1));
133 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
134 : TALER_EXCHANGEDB_update_to_prewire_failed (pg,
135 : 1));
136 1 : return 0;
137 : }
138 :
139 :
140 : /**
141 : * Inserted rows come back in order, with their payload intact.
142 : *
143 : * @param pg the database context
144 : * @return 0 on success
145 : */
146 : static int
147 1 : check_insert_and_iterate (struct TALER_EXCHANGEDB_PostgresContext *pg)
148 : {
149 : static const char buf1[] = "first-transfer";
150 : static const char buf2[] = "second-transfer";
151 : struct PrewireContext ctx;
152 : uint64_t row1;
153 :
154 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
155 : TALER_EXCHANGEDB_insert_prewire (pg,
156 : "x-taler-bank",
157 : buf1,
158 : sizeof (buf1)));
159 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
160 : TALER_EXCHANGEDB_insert_prewire (pg,
161 : "iban",
162 : buf2,
163 : sizeof (buf2)));
164 1 : memset (&ctx,
165 : 0,
166 : sizeof (ctx));
167 1 : FAILIF (0 >=
168 : TALER_EXCHANGEDB_iterate_prewires (pg,
169 : 0,
170 : 10,
171 : &prewire_cb,
172 : &ctx));
173 1 : FAILIF_C (2 != ctx.total,
174 : ctx_free (&ctx));
175 1 : FAILIF_C (sizeof (buf1) != ctx.first_buf_size,
176 : ctx_free (&ctx));
177 1 : FAILIF_C (0 != memcmp (ctx.first_buf,
178 : buf1,
179 : sizeof (buf1)),
180 : ctx_free (&ctx));
181 1 : FAILIF_C (0 != strcmp (ctx.first_method,
182 : "x-taler-bank"),
183 : ctx_free (&ctx));
184 1 : row1 = ctx.first_row;
185 1 : ctx_free (&ctx);
186 :
187 : /* the limit is honoured */
188 1 : memset (&ctx,
189 : 0,
190 : sizeof (ctx));
191 1 : FAILIF (0 >=
192 : TALER_EXCHANGEDB_iterate_prewires (pg,
193 : 0,
194 : 1,
195 : &prewire_cb,
196 : &ctx));
197 1 : FAILIF_C (1 != ctx.total,
198 : ctx_free (&ctx));
199 1 : ctx_free (&ctx);
200 :
201 : /* ...and so is the starting row */
202 1 : memset (&ctx,
203 : 0,
204 : sizeof (ctx));
205 1 : FAILIF (0 >=
206 : TALER_EXCHANGEDB_iterate_prewires (pg,
207 : row1 + 1,
208 : 10,
209 : &prewire_cb,
210 : &ctx));
211 1 : FAILIF_C (1 != ctx.total,
212 : ctx_free (&ctx));
213 1 : FAILIF_C (0 != strcmp (ctx.first_method,
214 : "iban"),
215 : ctx_free (&ctx));
216 1 : ctx_free (&ctx);
217 1 : return 0;
218 : }
219 :
220 :
221 : /**
222 : * Finished and failed rows drop out of the queue.
223 : *
224 : * @param pg the database context
225 : * @return 0 on success
226 : */
227 : static int
228 1 : check_finished_and_failed (struct TALER_EXCHANGEDB_PostgresContext *pg)
229 : {
230 : struct PrewireContext ctx;
231 : uint64_t row1;
232 : uint64_t row2;
233 :
234 1 : memset (&ctx,
235 : 0,
236 : sizeof (ctx));
237 1 : FAILIF (0 >=
238 : TALER_EXCHANGEDB_iterate_prewires (pg,
239 : 0,
240 : 10,
241 : &prewire_cb,
242 : &ctx));
243 1 : FAILIF_C (2 != ctx.total,
244 : ctx_free (&ctx));
245 1 : row1 = ctx.first_row;
246 1 : ctx_free (&ctx);
247 :
248 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
249 : TALER_EXCHANGEDB_update_to_prewire_finished (pg,
250 : row1));
251 1 : memset (&ctx,
252 : 0,
253 : sizeof (ctx));
254 1 : FAILIF (0 >=
255 : TALER_EXCHANGEDB_iterate_prewires (pg,
256 : 0,
257 : 10,
258 : &prewire_cb,
259 : &ctx));
260 1 : FAILIF_C (1 != ctx.total,
261 : ctx_free (&ctx));
262 1 : row2 = ctx.first_row;
263 1 : ctx_free (&ctx);
264 1 : FAILIF (row2 == row1);
265 :
266 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
267 : TALER_EXCHANGEDB_update_to_prewire_failed (pg,
268 : row2));
269 1 : memset (&ctx,
270 : 0,
271 : sizeof (ctx));
272 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
273 : TALER_EXCHANGEDB_iterate_prewires (pg,
274 : 0,
275 : 10,
276 : &prewire_cb,
277 : &ctx));
278 1 : FAILIF_C (0 != ctx.total,
279 : ctx_free (&ctx));
280 1 : ctx_free (&ctx);
281 :
282 : /* both rows are still on file, one finished and one failed */
283 1 : FAILIF (2 != TDB_count (pg,
284 : "FROM prewire"));
285 1 : FAILIF (1 != TDB_count (pg,
286 : "FROM prewire WHERE finished"));
287 1 : FAILIF (1 != TDB_count (pg,
288 : "FROM prewire WHERE failed"));
289 : /* marking again is still reported as a row touched */
290 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
291 : TALER_EXCHANGEDB_update_to_prewire_finished (pg,
292 : row1));
293 1 : return 0;
294 : }
295 :
296 :
297 : /**
298 : * The checks to run, in order.
299 : */
300 : static const struct TDB_Test tests[] = {
301 : { "prewire-empty",
302 : &check_empty },
303 : { "prewire-insert-and-iterate",
304 : &check_insert_and_iterate },
305 : { "prewire-finished-and-failed",
306 : &check_finished_and_failed },
307 : { NULL, NULL }
308 : };
309 :
310 :
311 : int
312 1 : main (int argc,
313 : char *const *argv)
314 : {
315 1 : return TDB_main (argc,
316 : argv,
317 : "test-prewire",
318 : "Tests for the exchangedb `prewire' table",
319 : tests);
320 : }
321 :
322 :
323 : /* end of test_prewire.c */
|