Line data Source code
1 : /*
2 : This file is part of Challenger
3 : (C) 2023 Taler Systems SA
4 :
5 : Challenger 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 : Challenger 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 : Challenger; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file challengerdb/test_challenger_db.c
18 : * @brief testcase for challenger postgres db plugin
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include <gnunet/gnunet_pq_lib.h>
24 : #include <taler/taler_util.h>
25 : #include "challenger_database_lib.h"
26 : #include "challenger-database/drop_tables.h"
27 : #include "challenger-database/create_tables.h"
28 : #include "challenger-database/preflight.h"
29 : #include "challenger-database/gc.h"
30 : #include "challenger-database/insert_client.h"
31 : #include "challenger-database/do_insert_validation.h"
32 : #include "challenger-database/do_challenge_address.h"
33 : #include "challenger-database/do_solve_challenge.h"
34 : #include "challenger-database/do_insert_token.h"
35 : #include "challenger-database/get_token.h"
36 : #include "challenger-database/get_validation_pkce.h"
37 : #include "challenger_util.h"
38 : #include "pg_helper.h"
39 : #include "challenger-database/delete_client.h"
40 : #include "challenger-database/do_insert_validation.h"
41 :
42 :
43 : #define FAILIF(cond) \
44 : do { \
45 : if (! (cond)) { break;} \
46 : GNUNET_break (0); \
47 : goto drop; \
48 : } while (0)
49 :
50 : /**
51 : * Secret of the client the tests register and act as.
52 : */
53 : #define CLIENT_SECRET "secret-token:test-secret"
54 :
55 : /**
56 : * Redirect URI of the client the tests register.
57 : */
58 : #define CLIENT_URI "http://client.example.com/"
59 :
60 : /**
61 : * Global return value for the test. Initially -1, set to 0 upon
62 : * completion. Other values indicate some kind of error.
63 : */
64 : static int result;
65 :
66 : /**
67 : * Handle to the database we are testing.
68 : */
69 : static struct CHALLENGERDB_PostgresContext *pg;
70 :
71 : /**
72 : * Serial ID of the client registered by #setup_client().
73 : */
74 : static uint64_t client_id;
75 :
76 :
77 : /**
78 : * Register the OAuth client all tests act as.
79 : *
80 : * @return #GNUNET_OK on success
81 : */
82 : static enum GNUNET_GenericReturnValue
83 1 : setup_client (void)
84 : {
85 1 : bool uri_taken = false;
86 :
87 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
88 1 : CHALLENGERDB_insert_client (pg,
89 : CLIENT_URI,
90 : CLIENT_SECRET,
91 : &client_id,
92 : &uri_taken))
93 : {
94 0 : GNUNET_break (0);
95 0 : return GNUNET_SYSERR;
96 : }
97 1 : return GNUNET_OK;
98 : }
99 :
100 :
101 : /**
102 : * Create a fresh validation for #client_id and have a TAN transmitted
103 : * for it, leaving the validation in the state a user reaches by posting
104 : * an address to ``/challenge`` and then walking away.
105 : *
106 : * @param[out] nonce set to the nonce identifying the new validation
107 : * @param[out] pin set to the TAN that was "transmitted"
108 : * @return #GNUNET_OK on success
109 : */
110 : static enum GNUNET_GenericReturnValue
111 5 : challenge_validation (struct CHALLENGER_ValidationNonceP *nonce,
112 : uint32_t *pin)
113 : {
114 : struct GNUNET_TIME_Absolute expiration
115 5 : = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
116 : json_t *address;
117 5 : char *state = NULL;
118 5 : char *redirect_uri = NULL;
119 : struct GNUNET_TIME_Absolute last_tx_time;
120 : uint32_t auth_attempts_left;
121 : uint32_t pin_transmissions_left;
122 : bool pin_transmit;
123 : bool address_refused;
124 : bool solved;
125 : enum GNUNET_DB_QueryStatus qs;
126 :
127 5 : GNUNET_CRYPTO_random_block (nonce,
128 : sizeof (*nonce));
129 5 : qs = CHALLENGERDB_do_insert_validation (pg,
130 : client_id,
131 : CLIENT_SECRET,
132 : nonce,
133 : expiration,
134 : NULL);
135 5 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
136 : {
137 0 : GNUNET_break (0);
138 0 : return GNUNET_SYSERR;
139 : }
140 5 : address = json_pack ("{s:s}",
141 : "filename",
142 : "test-challenger-db.txt");
143 5 : GNUNET_assert (NULL != address);
144 5 : *pin = 424242;
145 5 : qs = CHALLENGERDB_do_challenge_address (pg,
146 : nonce,
147 : address,
148 5 : GNUNET_TIME_UNIT_ZERO,
149 : pin,
150 : &state,
151 : &last_tx_time,
152 : &auth_attempts_left,
153 : &pin_transmissions_left,
154 : &pin_transmit,
155 : &redirect_uri,
156 : &address_refused,
157 : &solved);
158 5 : json_decref (address);
159 : /* The TAN is only pending until its transmission is confirmed; this
160 : stands in for a successful AUTH_COMMAND run. */
161 5 : qs = CHALLENGERDB_do_challenge_address_confirm_pin (pg,
162 : nonce,
163 : &auth_attempts_left);
164 5 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
165 : {
166 0 : GNUNET_break (0);
167 0 : return GNUNET_SYSERR;
168 : }
169 5 : GNUNET_free (state);
170 5 : GNUNET_free (redirect_uri);
171 5 : if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ||
172 5 : (! pin_transmit) ||
173 5 : address_refused ||
174 : solved)
175 : {
176 0 : GNUNET_break (0);
177 0 : return GNUNET_SYSERR;
178 : }
179 5 : return GNUNET_OK;
180 : }
181 :
182 :
183 : /**
184 : * Enter @a pin for the validation under @a nonce and check it was accepted.
185 : *
186 : * @param nonce validation to solve
187 : * @param pin TAN to enter
188 : * @return #GNUNET_OK on success
189 : */
190 : static enum GNUNET_GenericReturnValue
191 4 : solve_validation (const struct CHALLENGER_ValidationNonceP *nonce,
192 : uint32_t pin)
193 : {
194 4 : char *state = NULL;
195 4 : char *redirect_uri = NULL;
196 : uint32_t addr_left;
197 : uint32_t auth_attempts_left;
198 : uint32_t pin_transmissions_left;
199 : bool solved;
200 : bool exhausted;
201 : bool no_challenge;
202 : enum GNUNET_DB_QueryStatus qs;
203 :
204 4 : qs = CHALLENGERDB_do_solve_challenge (pg,
205 : nonce,
206 : pin,
207 : &solved,
208 : &exhausted,
209 : &no_challenge,
210 : &state,
211 : &addr_left,
212 : &auth_attempts_left,
213 : &pin_transmissions_left,
214 : &redirect_uri);
215 4 : GNUNET_free (state);
216 4 : GNUNET_free (redirect_uri);
217 4 : if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ||
218 4 : (! solved) ||
219 4 : exhausted ||
220 : no_challenge)
221 : {
222 0 : GNUNET_break (0);
223 0 : return GNUNET_SYSERR;
224 : }
225 4 : return GNUNET_OK;
226 : }
227 :
228 :
229 : /**
230 : * Mint an access token for the validation under @a nonce.
231 : *
232 : * @param client client redeeming the authorization code
233 : * @param nonce validation to redeem
234 : * @param[out] token set to the (random) access token we tried to store
235 : * @return transaction status of CHALLENGERDB_do_insert_token()
236 : */
237 : static enum GNUNET_DB_QueryStatus
238 7 : insert_token (uint64_t client,
239 : const struct CHALLENGER_ValidationNonceP *nonce,
240 : struct CHALLENGER_AccessTokenP *token)
241 : {
242 7 : GNUNET_CRYPTO_random_block (token,
243 : sizeof (*token));
244 7 : return CHALLENGERDB_do_insert_token (pg,
245 : nonce,
246 : client,
247 : token,
248 : GNUNET_TIME_UNIT_HOURS,
249 : GNUNET_TIME_UNIT_DAYS);
250 : }
251 :
252 :
253 : /**
254 : * Test that a validation for which the user never entered the correct
255 : * TAN cannot be redeemed for an access token, and is not even visible to
256 : * the ``/token`` lookup. Without the ``auth_attempts_left < 0`` guard
257 : * anyone able to compute the authorization code could mint an
258 : * attestation for an address nobody ever proved control over.
259 : *
260 : * @return #GNUNET_OK on success
261 : */
262 : static enum GNUNET_GenericReturnValue
263 1 : test_unsolved_not_redeemable (void)
264 : {
265 : struct CHALLENGER_ValidationNonceP nonce;
266 : struct CHALLENGER_AccessTokenP token;
267 : uint32_t pin;
268 :
269 1 : if (GNUNET_OK !=
270 1 : challenge_validation (&nonce,
271 : &pin))
272 0 : return GNUNET_SYSERR;
273 : {
274 : char *client_secret;
275 : json_t *address;
276 : char *client_scope;
277 : char *client_state;
278 : char *client_redirect_uri;
279 : char *code_challenge;
280 : uint32_t code_challenge_method;
281 :
282 1 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
283 1 : CHALLENGERDB_get_validation_pkce (pg,
284 : &nonce,
285 : client_id,
286 : &client_secret,
287 : &address,
288 : &client_scope,
289 : &client_state,
290 : &client_redirect_uri,
291 : &code_challenge,
292 : &code_challenge_method))
293 : {
294 0 : GNUNET_break (0);
295 0 : return GNUNET_SYSERR;
296 : }
297 : }
298 1 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
299 1 : insert_token (client_id,
300 : &nonce,
301 : &token))
302 : {
303 0 : GNUNET_break (0);
304 0 : return GNUNET_SYSERR;
305 : }
306 1 : return GNUNET_OK;
307 : }
308 :
309 :
310 : /**
311 : * Test that a solved validation is redeemable, and redeemable exactly
312 : * once (the authorization code must not be replayable).
313 : *
314 : * @return #GNUNET_OK on success
315 : */
316 : static enum GNUNET_GenericReturnValue
317 1 : test_solved_redeemable (void)
318 : {
319 : struct CHALLENGER_ValidationNonceP nonce;
320 : struct CHALLENGER_AccessTokenP token;
321 : uint32_t pin;
322 :
323 1 : if ( (GNUNET_OK !=
324 1 : challenge_validation (&nonce,
325 1 : &pin)) ||
326 : (GNUNET_OK !=
327 1 : solve_validation (&nonce,
328 : pin)) )
329 0 : return GNUNET_SYSERR;
330 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
331 1 : insert_token (client_id,
332 : &nonce,
333 : &token))
334 : {
335 0 : GNUNET_break (0);
336 0 : return GNUNET_SYSERR;
337 : }
338 : /* replay: the validation was consumed, so this must not mint a token */
339 1 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
340 1 : insert_token (client_id,
341 : &nonce,
342 : &token))
343 : {
344 0 : GNUNET_break (0);
345 0 : return GNUNET_SYSERR;
346 : }
347 1 : return GNUNET_OK;
348 : }
349 :
350 :
351 : /**
352 : * Test that the address expiration stored with a freshly minted token is
353 : * in the future, and in particular that it does *not* depend on the
354 : * validation's ``last_tx_time``. The regression this guards against
355 : * computed the expiration as ``address_expiration + last_tx_time``, which
356 : * lands in 1970 whenever that column was never written. We force the
357 : * column back to 0 to pin the property down without relying on any
358 : * particular code path leaving it there.
359 : *
360 : * @return #GNUNET_OK on success
361 : */
362 : static enum GNUNET_GenericReturnValue
363 1 : test_address_expiry_is_in_the_future (void)
364 : {
365 1 : struct GNUNET_PQ_ExecuteStatement es[] = {
366 1 : GNUNET_PQ_make_execute ("UPDATE validations SET last_tx_time=0;"),
367 : GNUNET_PQ_EXECUTE_STATEMENT_END
368 : };
369 : struct CHALLENGER_ValidationNonceP nonce;
370 : struct CHALLENGER_AccessTokenP token;
371 : struct GNUNET_TIME_Timestamp address_expiration;
372 : struct GNUNET_TIME_Absolute now;
373 1 : json_t *address = NULL;
374 : uint64_t rowid;
375 : uint32_t pin;
376 : enum GNUNET_GenericReturnValue ret;
377 :
378 1 : if ( (GNUNET_OK !=
379 1 : challenge_validation (&nonce,
380 1 : &pin)) ||
381 : (GNUNET_OK !=
382 1 : solve_validation (&nonce,
383 : pin)) )
384 0 : return GNUNET_SYSERR;
385 1 : if (GNUNET_OK !=
386 1 : GNUNET_PQ_exec_statements (pg->conn,
387 : es))
388 : {
389 0 : GNUNET_break (0);
390 0 : return GNUNET_SYSERR;
391 : }
392 1 : now = GNUNET_TIME_absolute_get ();
393 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
394 1 : insert_token (client_id,
395 : &nonce,
396 : &token))
397 : {
398 0 : GNUNET_break (0);
399 0 : return GNUNET_SYSERR;
400 : }
401 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
402 1 : CHALLENGERDB_get_token (pg,
403 : &token,
404 : &rowid,
405 : &address,
406 : &address_expiration))
407 : {
408 0 : GNUNET_break (0);
409 0 : return GNUNET_SYSERR;
410 : }
411 1 : ret = GNUNET_OK;
412 1 : if (address_expiration.abs_time.abs_value_us <= now.abs_value_us)
413 : {
414 0 : GNUNET_break (0);
415 0 : ret = GNUNET_SYSERR;
416 : }
417 1 : json_decref (address);
418 1 : return ret;
419 : }
420 :
421 :
422 : /**
423 : * Test that an expired validation is not consumable, even though the
424 : * caller (``/token``) checked the expiration in an earlier, separate
425 : * transaction. Everything get_validation_pkce() filters on has to be
426 : * repeated by do_insert_token(), or the gap between the two statements is
427 : * an unguarded TOCTOU window.
428 : *
429 : * @return #GNUNET_OK on success
430 : */
431 : static enum GNUNET_GenericReturnValue
432 1 : test_expired_not_redeemable (void)
433 : {
434 1 : struct GNUNET_PQ_ExecuteStatement es[] = {
435 1 : GNUNET_PQ_make_execute ("UPDATE validations SET expiration_time=1;"),
436 : GNUNET_PQ_EXECUTE_STATEMENT_END
437 : };
438 : struct CHALLENGER_ValidationNonceP nonce;
439 : struct CHALLENGER_AccessTokenP token;
440 : uint32_t pin;
441 :
442 1 : if ( (GNUNET_OK !=
443 1 : challenge_validation (&nonce,
444 1 : &pin)) ||
445 : (GNUNET_OK !=
446 1 : solve_validation (&nonce,
447 : pin)) )
448 0 : return GNUNET_SYSERR;
449 1 : if (GNUNET_OK !=
450 1 : GNUNET_PQ_exec_statements (pg->conn,
451 : es))
452 : {
453 0 : GNUNET_break (0);
454 0 : return GNUNET_SYSERR;
455 : }
456 1 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
457 1 : insert_token (client_id,
458 : &nonce,
459 : &token))
460 : {
461 0 : GNUNET_break (0);
462 0 : return GNUNET_SYSERR;
463 : }
464 1 : return GNUNET_OK;
465 : }
466 :
467 :
468 : /**
469 : * Test that a validation cannot be consumed by a client it does not
470 : * belong to.
471 : *
472 : * @return #GNUNET_OK on success
473 : */
474 : static enum GNUNET_GenericReturnValue
475 1 : test_foreign_client_not_redeemable (void)
476 : {
477 : struct CHALLENGER_ValidationNonceP nonce;
478 : struct CHALLENGER_AccessTokenP token;
479 : uint32_t pin;
480 :
481 1 : if ( (GNUNET_OK !=
482 1 : challenge_validation (&nonce,
483 1 : &pin)) ||
484 : (GNUNET_OK !=
485 1 : solve_validation (&nonce,
486 : pin)) )
487 0 : return GNUNET_SYSERR;
488 1 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
489 1 : insert_token (client_id + 1,
490 : &nonce,
491 : &token))
492 : {
493 0 : GNUNET_break (0);
494 0 : return GNUNET_SYSERR;
495 : }
496 : /* ... and the rightful client still can */
497 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
498 1 : insert_token (client_id,
499 : &nonce,
500 : &token))
501 : {
502 0 : GNUNET_break (0);
503 0 : return GNUNET_SYSERR;
504 : }
505 1 : return GNUNET_OK;
506 : }
507 :
508 :
509 : /**
510 : * Run @a sql directly on the database, bypassing the CHALLENGERDB API.
511 : * Used to create states (and to make assertions about the schema) that
512 : * the API deliberately cannot produce.
513 : *
514 : * @param sql SQL statement to execute
515 : * @return #GNUNET_OK on success
516 : */
517 : static enum GNUNET_GenericReturnValue
518 2 : exec_sql (const char *sql)
519 : {
520 2 : struct GNUNET_PQ_ExecuteStatement es[] = {
521 2 : GNUNET_PQ_make_execute (sql),
522 : GNUNET_PQ_EXECUTE_STATEMENT_END
523 : };
524 :
525 2 : return GNUNET_PQ_exec_statements (pg->conn,
526 : es);
527 : }
528 :
529 :
530 : /**
531 : * Test that a client cannot be inserted silently: a URI that is already
532 : * registered must be reported as such, and any *other* unique violation
533 : * (notably one on the primary key, which happens once the identity sequence
534 : * of 'clients' lags behind max(client_serial_id)) must not be misreported as
535 : * a duplicate URI.
536 : *
537 : * @return #GNUNET_OK on success
538 : */
539 : static enum GNUNET_GenericReturnValue
540 1 : test_insert_client (void)
541 : {
542 : uint64_t nclient_id;
543 : bool uri_taken;
544 :
545 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
546 1 : CHALLENGERDB_insert_client (pg,
547 : "https://example.com/a",
548 : "secret-token:a",
549 : &nclient_id,
550 : &uri_taken))
551 : {
552 0 : GNUNET_break (0);
553 0 : return GNUNET_SYSERR;
554 : }
555 1 : if (uri_taken)
556 : {
557 0 : GNUNET_break (0);
558 0 : return GNUNET_SYSERR;
559 : }
560 : /* Same URI again: this one really is a duplicate. */
561 1 : if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
562 1 : CHALLENGERDB_insert_client (pg,
563 : "https://example.com/a",
564 : "secret-token:b",
565 : &nclient_id,
566 1 : &uri_taken)) ||
567 1 : (! uri_taken) )
568 : {
569 0 : GNUNET_break (0);
570 0 : return GNUNET_SYSERR;
571 : }
572 : /* Rewind the identity sequence, as a restore that did not restore the
573 : sequences leaves it: the next INSERT then collides on the primary key,
574 : not on the URI. */
575 1 : if (GNUNET_OK !=
576 1 : exec_sql ("DO $$ BEGIN"
577 : " PERFORM setval("
578 : " pg_get_serial_sequence('challenger.clients',"
579 : " 'client_serial_id'),"
580 : " (SELECT MIN(client_serial_id) FROM challenger.clients),"
581 : " false);"
582 : "END $$;"))
583 : {
584 0 : GNUNET_break (0);
585 0 : return GNUNET_SYSERR;
586 : }
587 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
588 1 : CHALLENGERDB_insert_client (pg,
589 : "https://example.com/b",
590 : "secret-token:b",
591 : &nclient_id,
592 : &uri_taken))
593 : {
594 : /* The PK collision must not go unnoticed. */
595 0 : GNUNET_break (0);
596 0 : return GNUNET_SYSERR;
597 : }
598 1 : if (uri_taken)
599 : {
600 : /* This is the regression: the failure has nothing to do with the URI,
601 : and the operator must not be told that the URI already exists. */
602 0 : GNUNET_break (0);
603 0 : return GNUNET_SYSERR;
604 : }
605 : /* Repair the sequence, then the very same insert must work. */
606 1 : if (GNUNET_OK !=
607 1 : exec_sql ("DO $$ BEGIN"
608 : " PERFORM setval("
609 : " pg_get_serial_sequence('challenger.clients',"
610 : " 'client_serial_id'),"
611 : " (SELECT MAX(client_serial_id) FROM challenger.clients),"
612 : " true);"
613 : "END $$;"))
614 : {
615 0 : GNUNET_break (0);
616 0 : return GNUNET_SYSERR;
617 : }
618 1 : if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
619 1 : CHALLENGERDB_insert_client (pg,
620 : "https://example.com/b",
621 : "secret-token:b",
622 : &nclient_id,
623 1 : &uri_taken)) ||
624 : (uri_taken) )
625 : {
626 0 : GNUNET_break (0);
627 0 : return GNUNET_SYSERR;
628 : }
629 1 : return GNUNET_OK;
630 : }
631 :
632 :
633 : /**
634 : * Test that deleting a client reports how many validations it took with it:
635 : * validations_client_serial_id_fkey cascades, so an operator would otherwise
636 : * abort in-flight KYC processes without being told.
637 : *
638 : * @return #GNUNET_OK on success
639 : */
640 : static enum GNUNET_GenericReturnValue
641 1 : test_delete_client (void)
642 : {
643 1 : const char *uri = "https://example.com/del";
644 1 : const char *secret = "secret-token:del";
645 : struct GNUNET_TIME_Absolute expiration
646 1 : = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
647 : uint64_t nclient_id;
648 : uint64_t validations_deleted;
649 : bool uri_taken;
650 :
651 1 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
652 1 : CHALLENGERDB_insert_client (pg,
653 : uri,
654 : secret,
655 : &nclient_id,
656 : &uri_taken))
657 : {
658 0 : GNUNET_break (0);
659 0 : return GNUNET_SYSERR;
660 : }
661 3 : for (unsigned int i = 0; i < 2; i++)
662 : {
663 : struct CHALLENGER_ValidationNonceP nonce;
664 :
665 2 : GNUNET_CRYPTO_random_block (&nonce,
666 : sizeof (nonce));
667 2 : if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
668 2 : CHALLENGERDB_do_insert_validation (pg,
669 : nclient_id,
670 : secret,
671 : &nonce,
672 : expiration,
673 : NULL))
674 : {
675 0 : GNUNET_break (0);
676 0 : return GNUNET_SYSERR;
677 : }
678 : }
679 1 : if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
680 1 : CHALLENGERDB_delete_client (pg,
681 : uri,
682 1 : &validations_deleted)) ||
683 1 : (2 != validations_deleted) )
684 : {
685 0 : GNUNET_break (0);
686 0 : return GNUNET_SYSERR;
687 : }
688 : /* Deleting it again finds nothing and discards nothing. */
689 1 : if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
690 1 : CHALLENGERDB_delete_client (pg,
691 : uri,
692 1 : &validations_deleted)) ||
693 1 : (0 != validations_deleted) )
694 : {
695 0 : GNUNET_break (0);
696 0 : return GNUNET_SYSERR;
697 : }
698 1 : return GNUNET_OK;
699 : }
700 :
701 :
702 : /**
703 : * Main function that will be run by the scheduler.
704 : *
705 : * @param cls closure with config
706 : */
707 : static void
708 1 : run (void *cls)
709 : {
710 1 : struct GNUNET_CONFIGURATION_Handle *cfg = cls;
711 :
712 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
713 : "Connecting\n");
714 1 : if (NULL == (pg = CHALLENGERDB_connect_admin (cfg)))
715 : {
716 0 : result = 77;
717 0 : return;
718 : }
719 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
720 : "Connected\n");
721 1 : if (GNUNET_OK !=
722 1 : CHALLENGERDB_drop_tables (pg))
723 : {
724 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
725 : "Dropping tables failed\n");
726 : }
727 1 : if (GNUNET_OK !=
728 1 : CHALLENGERDB_create_tables (pg))
729 : {
730 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
731 : "Creating tables failed\n");
732 0 : goto drop;
733 : }
734 1 : GNUNET_assert (GNUNET_OK ==
735 : CHALLENGERDB_preflight (pg));
736 : {
737 1 : struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get ();
738 :
739 1 : FAILIF (0 >
740 : CHALLENGERDB_gc (pg,
741 : ts));
742 : }
743 1 : FAILIF (GNUNET_OK !=
744 : setup_client ());
745 1 : FAILIF (GNUNET_OK !=
746 : test_unsolved_not_redeemable ());
747 1 : FAILIF (GNUNET_OK !=
748 : test_solved_redeemable ());
749 1 : FAILIF (GNUNET_OK !=
750 : test_address_expiry_is_in_the_future ());
751 1 : FAILIF (GNUNET_OK !=
752 : test_expired_not_redeemable ());
753 1 : FAILIF (GNUNET_OK !=
754 : test_foreign_client_not_redeemable ());
755 1 : FAILIF (GNUNET_OK !=
756 : test_insert_client ());
757 1 : FAILIF (GNUNET_OK !=
758 : test_delete_client ());
759 1 : result = 0;
760 1 : drop:
761 1 : GNUNET_break (GNUNET_OK ==
762 : CHALLENGERDB_drop_tables (pg));
763 1 : CHALLENGERDB_disconnect (pg);
764 1 : pg = NULL;
765 : }
766 :
767 :
768 : int
769 1 : main (int argc,
770 : char *const argv[])
771 : {
772 : struct GNUNET_CONFIGURATION_Handle *cfg;
773 :
774 : (void) argc;
775 1 : result = EXIT_FAILURE;
776 1 : GNUNET_log_setup (argv[0],
777 : "DEBUG",
778 : NULL);
779 1 : cfg = GNUNET_CONFIGURATION_create (CHALLENGER_project_data ());
780 1 : if (GNUNET_OK !=
781 1 : GNUNET_CONFIGURATION_parse (cfg,
782 : "test_challenger_db_postgres.conf"))
783 : {
784 0 : GNUNET_break (0);
785 0 : return EXIT_NOTCONFIGURED;
786 : }
787 1 : GNUNET_SCHEDULER_run (&run, cfg);
788 1 : GNUNET_CONFIGURATION_destroy (cfg);
789 1 : return result;
790 : }
791 :
792 :
793 : /* end of test_challenger_db.c */
|