Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2016--2024 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 auditordb/test_auditordb_checkpoints.c
18 : * @brief test cases for DB interaction functions
19 : * @author Christian Grothoff
20 : */
21 : #include <gnunet/gnunet_common.h>
22 : #include <gnunet/gnunet_db_lib.h>
23 : #include "auditordb_lib.h"
24 : #include "auditor-database/create_tables.h"
25 : #include "auditor-database/drop_tables.h"
26 : #include "auditor-database/get_auditor_progress.h"
27 : #include "auditor-database/get_balance.h"
28 : #include "auditor-database/insert_auditor_progress.h"
29 : #include "auditor-database/insert_balance.h"
30 : #include "auditor-database/preflight.h"
31 : #include "auditor-database/start.h"
32 :
33 :
34 : /**
35 : * Currency we use, must match CURRENCY in "test-auditor-db-postgres.conf".
36 : */
37 : #define CURRENCY "EUR"
38 :
39 : /**
40 : * Report line of error if @a cond is true, and jump to label "drop".
41 : */
42 : #define FAILIF(cond) \
43 : do { \
44 : if (! (cond)) { break;} \
45 : GNUNET_break (0); \
46 : goto drop; \
47 : } while (0)
48 :
49 : /**
50 : * Initializes @a ptr with random data.
51 : */
52 : #define RND_BLK(ptr) \
53 : GNUNET_CRYPTO_random_block (ptr, \
54 : sizeof (*ptr))
55 :
56 : /**
57 : * Initializes @a ptr with zeros.
58 : */
59 : #define ZR_BLK(ptr) \
60 : memset (ptr, 0, sizeof (*ptr))
61 :
62 :
63 : /**
64 : * Global result from the testcase.
65 : */
66 : static int result = -1;
67 :
68 : /**
69 : * Database connection under test.
70 : */
71 : static struct TALER_AUDITORDB_PostgresContext *pg;
72 :
73 :
74 : /**
75 : * Main function that will be run by the scheduler.
76 : *
77 : * @param cls closure with config
78 : */
79 : static void
80 1 : run (void *cls)
81 : {
82 1 : struct GNUNET_CONFIGURATION_Handle *cfg = cls;
83 : struct TALER_Amount a1;
84 : struct TALER_Amount a2;
85 : struct TALER_Amount a3;
86 :
87 1 : GNUNET_assert (GNUNET_OK ==
88 : TALER_string_to_amount (CURRENCY ":11.245678",
89 : &a1));
90 1 : GNUNET_assert (GNUNET_OK ==
91 : TALER_string_to_amount (CURRENCY ":2",
92 : &a2));
93 1 : GNUNET_assert (GNUNET_OK ==
94 : TALER_string_to_amount (CURRENCY ":3",
95 : &a3));
96 :
97 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
98 : "Connecting to database\n");
99 1 : if (NULL ==
100 1 : (pg = TALER_AUDITORDB_connect (cfg)))
101 : {
102 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
103 : "Failed to connect to database\n");
104 0 : result = 77;
105 0 : return;
106 : }
107 1 : GNUNET_assert (GNUNET_OK ==
108 : TALER_AUDITORDB_preflight (pg));
109 1 : (void) TALER_AUDITORDB_drop_tables (pg,
110 : GNUNET_YES);
111 1 : if (GNUNET_OK !=
112 1 : TALER_AUDITORDB_create_tables (pg,
113 : false,
114 : 0))
115 : {
116 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
117 : "Failed to 'create_tables'\n");
118 0 : result = 77;
119 0 : goto unload;
120 : }
121 1 : if (GNUNET_SYSERR ==
122 1 : TALER_AUDITORDB_preflight (pg))
123 : {
124 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
125 : "Failed preflight check\n");
126 0 : result = 77;
127 0 : goto drop;
128 : }
129 :
130 1 : FAILIF (GNUNET_OK !=
131 : TALER_AUDITORDB_start (pg,
132 : "test-auditordb-checkpoints"));
133 :
134 : /* Test inserting a blank value, should tell us one result */
135 1 : GNUNET_assert (
136 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
137 : TALER_AUDITORDB_insert_auditor_progress (pg,
138 : "Test",
139 : 69,
140 : NULL)
141 : );
142 : /* Test re-inserting the same value; insert is an upsert, so this
143 : still touches the row */
144 1 : GNUNET_assert (
145 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
146 : TALER_AUDITORDB_insert_auditor_progress (pg,
147 : "Test",
148 : 69,
149 : NULL)
150 : );
151 : /* Test inserting multiple values, with one already existing */
152 1 : GNUNET_assert (
153 : 3 == TALER_AUDITORDB_insert_auditor_progress (pg,
154 : "Test",
155 : 69,
156 : "Test2",
157 : 123,
158 : "Test3",
159 : 245,
160 : NULL)
161 : );
162 : /* Test re-re-inserting the same key with a different value; the
163 : upsert must store the new value */
164 1 : GNUNET_assert (
165 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
166 : TALER_AUDITORDB_insert_auditor_progress (pg,
167 : "Test",
168 : 42,
169 : NULL)
170 : );
171 : /* Test updating the same key (again) with a different value; should yield a result */
172 1 : GNUNET_assert (
173 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
174 : TALER_AUDITORDB_insert_auditor_progress (pg,
175 : "Test",
176 : 42,
177 : NULL)
178 : );
179 : /* Test updating a key that does not exist yet; update is an upsert,
180 : so the row must be created */
181 1 : GNUNET_assert (
182 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
183 : TALER_AUDITORDB_insert_auditor_progress (pg,
184 : "NonexistentTest",
185 : 1,
186 : NULL)
187 : );
188 :
189 : /* Right now, the state should look like this:
190 : * Test = 42
191 : * Test2 = 123
192 : * Test3 = 245
193 : * Let's make sure that's the case! */
194 : {
195 : uint64_t value;
196 : uint64_t valueNX;
197 : uint64_t value3;
198 :
199 1 : GNUNET_assert (
200 : 3 ==
201 : TALER_AUDITORDB_get_auditor_progress (
202 : pg,
203 : "Test",
204 : &value,
205 : "TestNX",
206 : &valueNX,
207 : "Test3",
208 : &value3,
209 : NULL)
210 : );
211 1 : GNUNET_assert (value == 42);
212 1 : GNUNET_assert (valueNX == 0);
213 1 : GNUNET_assert (value3 == 245);
214 : }
215 : /* Ensure the rest are also at their expected values */
216 : {
217 : uint64_t value;
218 :
219 1 : GNUNET_assert (
220 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
221 : TALER_AUDITORDB_get_auditor_progress (
222 : pg,
223 : "Test2",
224 : &value,
225 : NULL)
226 : );
227 1 : GNUNET_assert (value == 123);
228 : }
229 : {
230 : uint64_t value;
231 :
232 1 : GNUNET_assert (
233 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
234 : TALER_AUDITORDB_get_auditor_progress (
235 : pg,
236 : "Test3",
237 : &value,
238 : NULL)
239 : );
240 1 : GNUNET_assert (value == 245);
241 : }
242 : {
243 : uint64_t value;
244 :
245 : /* Try fetching value that does not exist */
246 1 : GNUNET_assert (
247 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
248 : TALER_AUDITORDB_get_auditor_progress (
249 : pg,
250 : "TestNX",
251 : &value,
252 : NULL)
253 : );
254 1 : GNUNET_assert (0 == value);
255 : }
256 :
257 : /* Test inserting a blank value, should tell us one result */
258 1 : GNUNET_assert (
259 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
260 : TALER_AUDITORDB_insert_balance (pg,
261 : "Test",
262 : &a1,
263 : NULL)
264 : );
265 : /* Test re-inserting the same value; insert is an upsert, so this
266 : still touches the row */
267 1 : GNUNET_assert (
268 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
269 : TALER_AUDITORDB_insert_balance (pg,
270 : "Test",
271 : &a1,
272 : NULL)
273 : );
274 : /* Test inserting multiple values, with one already existing */
275 1 : GNUNET_assert (
276 : 3 == TALER_AUDITORDB_insert_balance (pg,
277 : "Test",
278 : &a1,
279 : "Test2",
280 : &a2,
281 : "Test3",
282 : &a3,
283 : NULL)
284 : );
285 : /* Test re-re-inserting the same key with a different value; the
286 : upsert must store the new value */
287 1 : GNUNET_assert (
288 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
289 : TALER_AUDITORDB_insert_balance (pg,
290 : "Test",
291 : &a2,
292 : NULL)
293 : );
294 : /* Test updating the same key (again) with a different value; should yield a result */
295 1 : GNUNET_assert (
296 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
297 : TALER_AUDITORDB_insert_balance (pg,
298 : "Test",
299 : &a2,
300 : NULL)
301 : );
302 : /* Test updating a key that does not exist yet; update is an upsert,
303 : so the row must be created */
304 1 : GNUNET_assert (
305 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
306 : TALER_AUDITORDB_insert_balance (pg,
307 : "NonexistentTest",
308 : &a2,
309 : NULL)
310 : );
311 :
312 : /* Right now, the state should look like this:
313 : * Test = a2
314 : * Test2 = a2
315 : * Test3 = a3
316 : * Let's make sure that's the case! */
317 1 : GNUNET_assert (
318 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
319 : TALER_AUDITORDB_get_balance (
320 : pg,
321 : "Test",
322 : &a1,
323 : NULL)
324 : );
325 1 : GNUNET_assert (0 ==
326 : TALER_amount_cmp (&a1,
327 : &a2));
328 :
329 : /* Ensure the rest are also at their expected values */
330 1 : GNUNET_assert (
331 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
332 : TALER_AUDITORDB_get_balance (
333 : pg,
334 : "Test2",
335 : &a1,
336 : NULL)
337 : );
338 1 : GNUNET_assert (0 ==
339 : TALER_amount_cmp (&a1,
340 : &a2));
341 1 : GNUNET_assert (
342 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
343 : TALER_AUDITORDB_get_balance (
344 : pg,
345 : "Test3",
346 : &a1,
347 : NULL)
348 : );
349 1 : GNUNET_assert (0 ==
350 : TALER_amount_cmp (&a1,
351 : &a3));
352 :
353 : /* Try fetching value that does not exist */
354 1 : GNUNET_assert (
355 : GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
356 : TALER_AUDITORDB_get_balance (
357 : pg,
358 : "TestNX",
359 : &a1,
360 : NULL)
361 : );
362 1 : GNUNET_assert (TALER_amount_is_zero (&a1));
363 :
364 1 : result = 0;
365 1 : GNUNET_break (0 <=
366 : TALER_AUDITORDB_commit (pg));
367 1 : drop:
368 1 : GNUNET_break (GNUNET_OK ==
369 : TALER_AUDITORDB_drop_tables (pg,
370 : GNUNET_YES));
371 1 : unload:
372 1 : TALER_AUDITORDB_disconnect (pg);
373 1 : pg = NULL;
374 : }
375 :
376 :
377 : int
378 1 : main (int argc,
379 : char *const argv[])
380 : {
381 : struct GNUNET_CONFIGURATION_Handle *cfg;
382 :
383 : (void) argc;
384 1 : result = -1;
385 1 : GNUNET_log_setup (argv[0],
386 : "INFO",
387 : NULL);
388 1 : cfg = GNUNET_CONFIGURATION_create (TALER_AUDITOR_project_data ());
389 1 : if (GNUNET_OK !=
390 1 : GNUNET_CONFIGURATION_parse (cfg,
391 : "test-auditor-db-postgres.conf"))
392 : {
393 0 : GNUNET_break (0);
394 0 : return 2;
395 : }
396 1 : GNUNET_SCHEDULER_run (&run, cfg);
397 1 : GNUNET_CONFIGURATION_destroy (cfg);
398 1 : return result;
399 : }
|