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_legitimization_measures.c
18 : * @brief tests for the exchangedb functions whose primary table is
19 : * `legitimization_measures`
20 : * @author Christian Grothoff
21 : *
22 : * Covers #TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account(),
23 : * #TALER_EXCHANGEDB_insert_active_legitimization_measure(),
24 : * #TALER_EXCHANGEDB_insert_successor_measure(),
25 : * #TALER_EXCHANGEDB_get_pending_legitimization(),
26 : * #TALER_EXCHANGEDB_get_active_legitimization(),
27 : * #TALER_EXCHANGEDB_get_completed_legitimization(),
28 : * #TALER_EXCHANGEDB_get_kyc_status_by_token(),
29 : * #TALER_EXCHANGEDB_get_open_legitimization_measure(),
30 : * #TALER_EXCHANGEDB_get_legitimization_requirement_by_row() and
31 : * #TALER_EXCHANGEDB_iterate_aml_measures().
32 : *
33 : * A row of `legitimization_measures` is one set of KYC measures the
34 : * exchange put on an account. It is keyed by the account's access token,
35 : * so `kyc_targets` has to exist first -- do_trigger_kyc_rule_for_account()
36 : * creates it when it has to. Only one measure set per account is active
37 : * at a time: triggering a different set finishes the previous one.
38 : */
39 : #include "test_common.h"
40 : #include "exchange-database/do_trigger_kyc_rule_for_account.h"
41 : #include "exchange-database/get_active_legitimization.h"
42 : #include "exchange-database/get_completed_legitimization.h"
43 : #include "exchange-database/get_kyc_status_by_token.h"
44 : #include "exchange-database/get_legitimization_requirement_by_row.h"
45 : #include "exchange-database/get_open_legitimization_measure.h"
46 : #include "exchange-database/get_pending_legitimization.h"
47 : #include "exchange-database/insert_active_legitimization_measure.h"
48 : #include "exchange-database/insert_legitimization_process.h"
49 : #include "exchange-database/insert_successor_measure.h"
50 : #include "exchange-database/iterate_aml_measures.h"
51 :
52 :
53 : /**
54 : * Account the checks put measures on.
55 : */
56 : static struct TDB_Account account;
57 :
58 :
59 : /**
60 : * Row of the measure set that check_trigger() created.
61 : */
62 : static uint64_t measure_row;
63 :
64 :
65 : /**
66 : * Key the account may use to authorise KYC work on itself.
67 : */
68 : static union TALER_AccountPublicKeyP account_pub;
69 :
70 :
71 : /**
72 : * Build a timestamp from a number of seconds since the epoch.
73 : *
74 : * @param secs seconds since the epoch
75 : * @return the timestamp
76 : */
77 : static struct GNUNET_TIME_Timestamp
78 4 : ts (uint64_t secs)
79 : {
80 4 : struct GNUNET_TIME_Absolute abs = {
81 4 : .abs_value_us = secs * 1000LLU * 1000LLU
82 : };
83 :
84 4 : return GNUNET_TIME_absolute_to_timestamp (abs);
85 : }
86 :
87 :
88 : /**
89 : * Build a measure set naming @a check.
90 : *
91 : * @param check name of the check to demand
92 : * @return the measure set, to be freed with json_decref()
93 : */
94 : static json_t *
95 4 : make_measures (const char *check)
96 : {
97 : json_t *j;
98 :
99 4 : j = GNUNET_JSON_PACK (
100 : GNUNET_JSON_pack_array_steal (
101 : "measures",
102 : json_pack ("[{s:s,s:s,s:s}]",
103 : "check_name",
104 : check,
105 : "prog_name",
106 : "skip",
107 : "context",
108 : "none")),
109 : GNUNET_JSON_pack_bool ("is_and_combinator",
110 : true));
111 4 : GNUNET_assert (NULL != j);
112 4 : return j;
113 : }
114 :
115 :
116 : /**
117 : * Read the access token the database generated for our account.
118 : *
119 : * @param pg the database context
120 : * @param[out] access_token set to the account's access token
121 : */
122 : static void
123 3 : get_access_token (struct TALER_EXCHANGEDB_PostgresContext *pg,
124 : struct TALER_AccountAccessTokenP *access_token)
125 : {
126 3 : struct GNUNET_PQ_QueryParam params[] = {
127 3 : GNUNET_PQ_query_param_auto_from_type (&account.h_normalized),
128 : GNUNET_PQ_query_param_end
129 : };
130 3 : struct GNUNET_PQ_ResultSpec rs[] = {
131 3 : GNUNET_PQ_result_spec_auto_from_type ("access_token",
132 : access_token),
133 : GNUNET_PQ_result_spec_end
134 : };
135 :
136 3 : GNUNET_assert (GNUNET_OK ==
137 : GNUNET_PQ_prepare_anon (pg->conn,
138 : "SELECT access_token"
139 : " FROM kyc_targets"
140 : " WHERE h_normalized_payto=$1;"));
141 3 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
142 : GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
143 : "",
144 : params,
145 : rs));
146 3 : }
147 :
148 :
149 : /**
150 : * Closure for #measure_cb().
151 : */
152 : struct MeasureContext
153 : {
154 : /**
155 : * How many measures did the callback see?
156 : */
157 : unsigned int total;
158 :
159 : /**
160 : * Row we are looking for, 0 to match nothing.
161 : */
162 : uint64_t measure_row;
163 :
164 : /**
165 : * How many times did we see it?
166 : */
167 : unsigned int matched;
168 :
169 : /**
170 : * Was it reported as finished?
171 : */
172 : bool is_finished;
173 :
174 : /**
175 : * Account it was reported for.
176 : */
177 : struct TALER_NormalizedPaytoHashP h_payto;
178 : };
179 :
180 :
181 : /**
182 : * Callback for #TALER_EXCHANGEDB_iterate_aml_measures().
183 : *
184 : * @param cls a `struct MeasureContext *`
185 : * @param h_payto account the measure applies to
186 : * @param start_time when the measure was imposed
187 : * @param jmeasures the measures
188 : * @param is_finished whether the measure was completed
189 : * @param measure_serial_id row of the measure
190 : */
191 : static void
192 9 : measure_cb (void *cls,
193 : struct TALER_NormalizedPaytoHashP *h_payto,
194 : struct GNUNET_TIME_Absolute start_time,
195 : const json_t *jmeasures,
196 : bool is_finished,
197 : uint64_t measure_serial_id)
198 : {
199 9 : struct MeasureContext *ctx = cls;
200 :
201 : (void) start_time;
202 : (void) jmeasures;
203 9 : ctx->total++;
204 9 : if ( (0 != ctx->measure_row) &&
205 0 : (measure_serial_id == ctx->measure_row) )
206 : {
207 0 : ctx->matched++;
208 0 : ctx->is_finished = is_finished;
209 0 : ctx->h_payto = *h_payto;
210 : }
211 9 : }
212 :
213 :
214 : /**
215 : * Nothing is known while the table is empty.
216 : *
217 : * @param pg the database context
218 : * @return 0 on success
219 : */
220 : static int
221 1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
222 : {
223 : struct TALER_NormalizedPaytoHashP h_payto;
224 : struct TALER_AccountAccessTokenP access_token;
225 : struct GNUNET_TIME_Absolute start_time;
226 1 : struct MeasureContext ctx = { 0 };
227 1 : json_t *jmeasures = NULL;
228 : uint64_t row;
229 : bool is_finished;
230 : bool is_wallet;
231 :
232 1 : TDB_FILL (h_payto,
233 : 1);
234 1 : TDB_FILL (access_token,
235 : 1);
236 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
237 : TALER_EXCHANGEDB_get_pending_legitimization (pg,
238 : 1,
239 : &access_token,
240 : &h_payto,
241 : &jmeasures,
242 : &is_finished,
243 : &is_wallet));
244 1 : FAILIF (NULL != jmeasures);
245 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
246 : TALER_EXCHANGEDB_get_kyc_status_by_token (pg,
247 : &access_token,
248 : &row,
249 : &jmeasures));
250 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
251 : TALER_EXCHANGEDB_get_open_legitimization_measure (pg,
252 : &h_payto,
253 : &row,
254 : &start_time));
255 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
256 : TALER_EXCHANGEDB_iterate_aml_measures (pg,
257 : NULL,
258 : TALER_EXCHANGE_YNA_ALL,
259 : 0,
260 : 10,
261 : &measure_cb,
262 : &ctx));
263 1 : FAILIF (0 != ctx.total);
264 1 : return 0;
265 : }
266 :
267 :
268 : /**
269 : * Triggering a rule creates the account and the measure set.
270 : *
271 : * @param pg the database context
272 : * @return 0 on success
273 : */
274 : static int
275 1 : check_trigger (struct TALER_EXCHANGEDB_PostgresContext *pg)
276 : {
277 : struct TALER_NormalizedPayto npayto;
278 : struct TALER_FullPayto payto;
279 : struct TALER_NormalizedPaytoHashP h_payto;
280 : struct TALER_AccountAccessTokenP access_token;
281 : struct TALER_AccountAccessTokenP got_token;
282 : struct TALER_NormalizedPaytoHashP got_payto;
283 1 : json_t *jmeasures = make_measures ("verify-id");
284 1 : json_t *got = NULL;
285 1 : uint64_t row = 0;
286 1 : bool bad_kyc_auth = false;
287 1 : bool is_finished = true;
288 1 : bool is_wallet = true;
289 :
290 1 : payto.full_payto = (char *)
291 : "payto://x-taler-bank/localhost/lm?receiver-name=LM";
292 1 : TALER_full_payto_hash (payto,
293 : &account.h_full);
294 1 : npayto = TALER_payto_normalize (payto);
295 1 : GNUNET_assert (NULL != npayto.normalized_payto);
296 1 : TALER_normalized_payto_hash (npayto,
297 : &h_payto);
298 1 : GNUNET_free (npayto.normalized_payto);
299 1 : account.payto.full_payto = GNUNET_strdup (payto.full_payto);
300 1 : account.h_normalized = h_payto;
301 :
302 1 : TDB_FILL (account_pub,
303 : 42);
304 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
305 : TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
306 : pg,
307 : payto,
308 : &h_payto,
309 : &account_pub,
310 : NULL,
311 : jmeasures,
312 : 1,
313 : &row,
314 : &bad_kyc_auth),
315 : json_decref (jmeasures));
316 1 : FAILIF_C (0 == row,
317 : json_decref (jmeasures));
318 : /* The account was not known, so there was no key to match against; the
319 : function reports that even though it just set one. */
320 1 : FAILIF_C (! bad_kyc_auth,
321 : json_decref (jmeasures));
322 1 : measure_row = row;
323 1 : FAILIF_C (1 != TDB_count (pg,
324 : "FROM legitimization_measures"),
325 : json_decref (jmeasures));
326 : /* the account was created along the way */
327 1 : FAILIF_C (1 != TDB_count (pg,
328 : "FROM kyc_targets"),
329 : json_decref (jmeasures));
330 1 : FAILIF_C (1 != TDB_count (pg,
331 : "FROM wire_targets"),
332 : json_decref (jmeasures));
333 :
334 : /* the measure set can be read back by its row... */
335 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
336 : TALER_EXCHANGEDB_get_pending_legitimization (pg,
337 : row,
338 : &got_token,
339 : &got_payto,
340 : &got,
341 : &is_finished,
342 : &is_wallet),
343 : json_decref (jmeasures));
344 1 : FAILIF_C (0 != GNUNET_memcmp (&got_payto,
345 : &h_payto),
346 : json_decref (got); json_decref (jmeasures));
347 1 : FAILIF_C (is_finished,
348 : json_decref (got); json_decref (jmeasures));
349 1 : FAILIF_C (is_wallet,
350 : json_decref (got); json_decref (jmeasures));
351 1 : FAILIF_C (1 != json_equal (got,
352 : jmeasures),
353 : json_decref (got); json_decref (jmeasures));
354 1 : json_decref (got);
355 1 : got = NULL;
356 :
357 : /* ...and by the account's access token */
358 1 : get_access_token (pg,
359 : &access_token);
360 1 : FAILIF_C (0 != GNUNET_memcmp (&got_token,
361 : &access_token),
362 : json_decref (jmeasures));
363 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
364 : TALER_EXCHANGEDB_get_kyc_status_by_token (pg,
365 : &access_token,
366 : &row,
367 : &got),
368 : json_decref (jmeasures));
369 1 : FAILIF_C (row != measure_row,
370 : json_decref (got); json_decref (jmeasures));
371 1 : json_decref (got);
372 :
373 : /* triggering the very same measure set again keeps the one row */
374 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
375 : TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
376 : pg,
377 : payto,
378 : &h_payto,
379 : NULL,
380 : NULL,
381 : jmeasures,
382 : 1,
383 : &row,
384 : &bad_kyc_auth),
385 : json_decref (jmeasures));
386 1 : FAILIF_C (row != measure_row,
387 : json_decref (jmeasures));
388 1 : FAILIF_C (1 != TDB_count (pg,
389 : "FROM legitimization_measures"),
390 : json_decref (jmeasures));
391 1 : json_decref (jmeasures);
392 1 : return 0;
393 : }
394 :
395 :
396 : /**
397 : * A different measure set supersedes the previous one, which is marked
398 : * finished.
399 : *
400 : * @param pg the database context
401 : * @return 0 on success
402 : */
403 : static int
404 1 : check_supersede (struct TALER_EXCHANGEDB_PostgresContext *pg)
405 : {
406 1 : json_t *jmeasures = make_measures ("verify-address");
407 1 : uint64_t row = 0;
408 1 : bool bad_kyc_auth = false;
409 :
410 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
411 : TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
412 : pg,
413 : account.payto,
414 : &account.h_normalized,
415 : NULL,
416 : NULL,
417 : jmeasures,
418 : 2,
419 : &row,
420 : &bad_kyc_auth),
421 : json_decref (jmeasures));
422 1 : json_decref (jmeasures);
423 1 : FAILIF (row == measure_row);
424 1 : FAILIF (2 != TDB_count (pg,
425 : "FROM legitimization_measures"));
426 1 : FAILIF (1 != TDB_count (pg,
427 : "FROM legitimization_measures"
428 : " WHERE is_finished"));
429 1 : measure_row = row;
430 1 : return 0;
431 : }
432 :
433 :
434 : /**
435 : * The account's rule requirement and its open measure are reported.
436 : *
437 : * @param pg the database context
438 : * @return 0 on success
439 : */
440 : static int
441 1 : check_requirement (struct TALER_EXCHANGEDB_PostgresContext *pg)
442 : {
443 : struct TALER_AccountAccessTokenP access_token;
444 : struct TALER_AccountAccessTokenP got_token;
445 : struct GNUNET_TIME_Absolute start_time;
446 : enum GNUNET_GenericReturnValue is_wallet;
447 1 : json_t *jrules = NULL;
448 1 : uint64_t rule_gen = 42;
449 1 : uint64_t row = 0;
450 1 : bool aml_review = true;
451 1 : bool kyc_required = false;
452 :
453 1 : get_access_token (pg,
454 : &access_token);
455 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
456 : TALER_EXCHANGEDB_get_legitimization_requirement_by_row (
457 : pg,
458 : &account.h_normalized,
459 : &account_pub,
460 : &is_wallet,
461 : &got_token,
462 : &rule_gen,
463 : &jrules,
464 : &aml_review,
465 : &kyc_required));
466 1 : FAILIF_C (0 != GNUNET_memcmp (&got_token,
467 : &access_token),
468 : json_decref (jrules));
469 1 : FAILIF_C (GNUNET_NO != is_wallet,
470 : json_decref (jrules));
471 : /* no AML decision has been taken for the account */
472 1 : FAILIF_C (aml_review,
473 : json_decref (jrules));
474 1 : FAILIF_C (0 != rule_gen,
475 : json_decref (jrules));
476 : /* ...but a measure is pending, so KYC is required */
477 1 : FAILIF_C (! kyc_required,
478 : json_decref (jrules));
479 1 : json_decref (jrules);
480 :
481 : /* the exchange's own account of why it is holding back */
482 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
483 : TALER_EXCHANGEDB_get_open_legitimization_measure (
484 : pg,
485 : &account.h_normalized,
486 : &row,
487 : &start_time));
488 : /* the oldest undecided measure is the one from check_trigger() */
489 1 : FAILIF (0 == row);
490 1 : FAILIF (GNUNET_TIME_absolute_is_zero (start_time));
491 :
492 : /* an account nobody put a measure on has none */
493 : {
494 : struct TALER_NormalizedPaytoHashP other;
495 :
496 1 : TDB_FILL (other,
497 : 98);
498 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
499 : TALER_EXCHANGEDB_get_open_legitimization_measure (pg,
500 : &other,
501 : &row,
502 : &start_time));
503 : }
504 1 : return 0;
505 : }
506 :
507 :
508 : /**
509 : * A legitimization process ties a measure set to the check it is
510 : * satisfying.
511 : *
512 : * @param pg the database context
513 : * @return 0 on success
514 : */
515 : static int
516 1 : check_process (struct TALER_EXCHANGEDB_PostgresContext *pg)
517 : {
518 : struct TALER_AccountAccessTokenP access_token;
519 : struct TALER_NormalizedPaytoHashP h_payto;
520 1 : json_t *jmeasures = NULL;
521 1 : size_t attributes_len = 42;
522 1 : void *attributes = NULL;
523 1 : uint64_t process_row = 0;
524 1 : uint32_t measure_index = 99;
525 1 : bool is_finished = true;
526 1 : bool is_wallet = true;
527 :
528 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
529 : TALER_EXCHANGEDB_insert_legitimization_process (
530 : pg,
531 : &account.h_normalized,
532 : 0,
533 : measure_row,
534 : "test-provider",
535 : "provider-account-1",
536 : "provider-legi-1",
537 : &process_row));
538 1 : FAILIF (0 == process_row);
539 :
540 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
541 : TALER_EXCHANGEDB_get_active_legitimization (pg,
542 : process_row,
543 : &measure_index,
544 : &jmeasures));
545 1 : FAILIF_C (0 != measure_index,
546 : json_decref (jmeasures));
547 1 : FAILIF_C (NULL == jmeasures,
548 : json_decref (jmeasures));
549 1 : json_decref (jmeasures);
550 1 : jmeasures = NULL;
551 :
552 : /* a process that does not exist has no active measure */
553 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
554 : TALER_EXCHANGEDB_get_active_legitimization (pg,
555 : process_row + 1000,
556 : &measure_index,
557 : &jmeasures));
558 :
559 : /* the completed view reaches the same measure through the process */
560 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
561 : TALER_EXCHANGEDB_get_completed_legitimization (pg,
562 : measure_row,
563 : 0,
564 : &access_token,
565 : &h_payto,
566 : &is_wallet,
567 : &jmeasures,
568 : &is_finished,
569 : &attributes_len,
570 : &attributes));
571 1 : FAILIF_C (0 != GNUNET_memcmp (&h_payto,
572 : &account.h_normalized),
573 : json_decref (jmeasures); GNUNET_free (attributes));
574 1 : FAILIF_C (is_finished,
575 : json_decref (jmeasures); GNUNET_free (attributes));
576 : /* no attributes have been collected yet */
577 1 : FAILIF_C (NULL != attributes,
578 : json_decref (jmeasures); GNUNET_free (attributes));
579 1 : json_decref (jmeasures);
580 1 : jmeasures = NULL;
581 :
582 : /* a measure index no process is working on is not found */
583 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
584 : TALER_EXCHANGEDB_get_completed_legitimization (pg,
585 : measure_row,
586 : 7,
587 : &access_token,
588 : &h_payto,
589 : &is_wallet,
590 : &jmeasures,
591 : &is_finished,
592 : &attributes_len,
593 : &attributes));
594 1 : return 0;
595 : }
596 :
597 :
598 : /**
599 : * A measure can also be created directly against an access token.
600 : *
601 : * @param pg the database context
602 : * @return 0 on success
603 : */
604 : static int
605 1 : check_insert_active (struct TALER_EXCHANGEDB_PostgresContext *pg)
606 : {
607 : struct TALER_AccountAccessTokenP access_token;
608 1 : json_t *jmeasures = make_measures ("verify-phone");
609 1 : uint64_t row = 0;
610 :
611 1 : get_access_token (pg,
612 : &access_token);
613 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
614 : TALER_EXCHANGEDB_insert_active_legitimization_measure (
615 : pg,
616 : &access_token,
617 : jmeasures,
618 : &row),
619 : json_decref (jmeasures));
620 1 : json_decref (jmeasures);
621 1 : FAILIF (0 == row);
622 1 : FAILIF (3 != TDB_count (pg,
623 : "FROM legitimization_measures"));
624 : /* it becomes the one active measure for the account */
625 1 : FAILIF (1 != TDB_count (pg,
626 : "FROM legitimization_measures"
627 : " WHERE NOT is_finished"));
628 1 : measure_row = row;
629 :
630 1 : return 0;
631 : }
632 :
633 :
634 : /**
635 : * A successor measure replaces what is active for the account.
636 : *
637 : * @param pg the database context
638 : * @return 0 on success
639 : */
640 : static int
641 1 : check_successor (struct TALER_EXCHANGEDB_PostgresContext *pg)
642 : {
643 : struct GNUNET_TIME_Timestamp last_date;
644 1 : json_t *jmeasures = make_measures ("verify-income");
645 1 : bool unknown_account = true;
646 :
647 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
648 : TALER_EXCHANGEDB_insert_successor_measure (
649 : pg,
650 : &account.h_normalized,
651 : ts (1600000000),
652 : "verify-income",
653 : jmeasures,
654 : &unknown_account,
655 : &last_date),
656 : json_decref (jmeasures));
657 1 : FAILIF_C (unknown_account,
658 : json_decref (jmeasures));
659 1 : FAILIF_C (4 != TDB_count (pg,
660 : "FROM legitimization_measures"),
661 : json_decref (jmeasures));
662 :
663 : /* an older decision is ignored */
664 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
665 : TALER_EXCHANGEDB_insert_successor_measure (
666 : pg,
667 : &account.h_normalized,
668 : ts (1500000000),
669 : "verify-income",
670 : jmeasures,
671 : &unknown_account,
672 : &last_date),
673 : json_decref (jmeasures));
674 1 : FAILIF_C (GNUNET_TIME_timestamp_cmp (last_date,
675 : !=,
676 : ts (1600000000)),
677 : json_decref (jmeasures));
678 1 : FAILIF_C (4 != TDB_count (pg,
679 : "FROM legitimization_measures"),
680 : json_decref (jmeasures));
681 :
682 : /* an account the exchange never saw is reported as unknown */
683 : {
684 : struct TALER_NormalizedPaytoHashP other;
685 :
686 1 : TDB_FILL (other,
687 : 95);
688 1 : unknown_account = false;
689 1 : FAILIF_C (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
690 : TALER_EXCHANGEDB_insert_successor_measure (
691 : pg,
692 : &other,
693 : ts (1600000000),
694 : "verify-income",
695 : jmeasures,
696 : &unknown_account,
697 : &last_date),
698 : json_decref (jmeasures));
699 1 : FAILIF_C (! unknown_account,
700 : json_decref (jmeasures));
701 : }
702 1 : json_decref (jmeasures);
703 1 : return 0;
704 : }
705 :
706 :
707 : /**
708 : * The measure listing reports the account's measures, filtered.
709 : *
710 : * @param pg the database context
711 : * @return 0 on success
712 : */
713 : static int
714 1 : check_iterate (struct TALER_EXCHANGEDB_PostgresContext *pg)
715 : {
716 : struct MeasureContext ctx;
717 : unsigned int all;
718 :
719 1 : memset (&ctx,
720 : 0,
721 : sizeof (ctx));
722 1 : FAILIF (0 >=
723 : TALER_EXCHANGEDB_iterate_aml_measures (pg,
724 : &account.h_normalized,
725 : TALER_EXCHANGE_YNA_ALL,
726 : 0,
727 : 100,
728 : &measure_cb,
729 : &ctx));
730 1 : all = ctx.total;
731 1 : FAILIF (0 == all);
732 :
733 : /* the account filter matters */
734 : {
735 : struct TALER_NormalizedPaytoHashP other;
736 :
737 1 : TDB_FILL (other,
738 : 94);
739 1 : memset (&ctx,
740 : 0,
741 : sizeof (ctx));
742 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
743 : TALER_EXCHANGEDB_iterate_aml_measures (pg,
744 : &other,
745 : TALER_EXCHANGE_YNA_ALL,
746 : 0,
747 : 100,
748 : &measure_cb,
749 : &ctx));
750 1 : FAILIF (0 != ctx.total);
751 : }
752 :
753 : /* only one measure is still open */
754 1 : memset (&ctx,
755 : 0,
756 : sizeof (ctx));
757 1 : FAILIF (0 >=
758 : TALER_EXCHANGEDB_iterate_aml_measures (pg,
759 : &account.h_normalized,
760 : TALER_EXCHANGE_YNA_YES,
761 : 0,
762 : 100,
763 : &measure_cb,
764 : &ctx));
765 1 : FAILIF (1 != ctx.total);
766 :
767 : /* the finished ones make up the rest */
768 1 : memset (&ctx,
769 : 0,
770 : sizeof (ctx));
771 1 : FAILIF (0 >=
772 : TALER_EXCHANGEDB_iterate_aml_measures (pg,
773 : &account.h_normalized,
774 : TALER_EXCHANGE_YNA_NO,
775 : 0,
776 : 100,
777 : &measure_cb,
778 : &ctx));
779 1 : FAILIF (all - 1 != ctx.total);
780 :
781 : /* the limit caps the result set */
782 1 : memset (&ctx,
783 : 0,
784 : sizeof (ctx));
785 1 : FAILIF (1 !=
786 : TALER_EXCHANGEDB_iterate_aml_measures (pg,
787 : NULL,
788 : TALER_EXCHANGE_YNA_ALL,
789 : 0,
790 : 1,
791 : &measure_cb,
792 : &ctx));
793 1 : FAILIF (1 != ctx.total);
794 1 : return 0;
795 : }
796 :
797 :
798 : /**
799 : * The checks to run, in order.
800 : */
801 : static const struct TDB_Test tests[] = {
802 : { "legitimization-measures-empty",
803 : &check_empty },
804 : { "legitimization-measures-trigger",
805 : &check_trigger },
806 : { "legitimization-measures-supersede",
807 : &check_supersede },
808 : { "legitimization-measures-requirement",
809 : &check_requirement },
810 : { "legitimization-measures-process",
811 : &check_process },
812 : { "legitimization-measures-insert-active",
813 : &check_insert_active },
814 : { "legitimization-measures-successor",
815 : &check_successor },
816 : { "legitimization-measures-iterate",
817 : &check_iterate },
818 : { NULL, NULL }
819 : };
820 :
821 :
822 : int
823 1 : main (int argc,
824 : char *const *argv)
825 : {
826 : int ret;
827 :
828 1 : ret = TDB_main (argc,
829 : argv,
830 : "test-legitimization-measures",
831 : "Tests for the exchangedb `legitimization_measures' table",
832 : tests);
833 1 : TDB_account_free (&account);
834 1 : return ret;
835 : }
836 :
837 :
838 : /* end of test_legitimization_measures.c */
|