LCOV - code coverage report
Current view: top level - exchangedb - test_legitimization_processes.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.3 % 148 147
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 10 10

            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_processes.c
      18              :  * @brief tests for the exchangedb functions whose primary table is
      19              :  *        `legitimization_processes`
      20              :  * @author Christian Grothoff
      21              :  *
      22              :  * Covers #TALER_EXCHANGEDB_insert_legitimization_process(),
      23              :  * #TALER_EXCHANGEDB_update_legitimization_process_by_row(),
      24              :  * #TALER_EXCHANGEDB_do_reserve_legitimization_process(),
      25              :  * #TALER_EXCHANGEDB_update_legitimization_process_start(),
      26              :  * #TALER_EXCHANGEDB_insert_kyc_failure(),
      27              :  * #TALER_EXCHANGEDB_insert_aml_program_failure(),
      28              :  * #TALER_EXCHANGEDB_get_legitimization_process_by_account(),
      29              :  * #TALER_EXCHANGEDB_get_pending_legitimization_process(),
      30              :  * #TALER_EXCHANGEDB_get_kyc_provider_account() and
      31              :  * #TALER_EXCHANGEDB_iterate_kyc_references().
      32              :  *
      33              :  * A row of `legitimization_processes` is one run of one KYC provider
      34              :  * against one account, working on one measure of a
      35              :  * `legitimization_measures` set.  The checks therefore create an account
      36              :  * and a measure set first, and then walk a process from "started" through
      37              :  * "redirect known" to "finished".
      38              :  */
      39              : #include "test_common.h"
      40              : #include "exchange-database/update_legitimization_process_start.h"
      41              : #include "exchange-database/do_reserve_legitimization_process.h"
      42              : #include "exchange-database/do_trigger_kyc_rule_for_account.h"
      43              : #include "exchange-database/get_kyc_provider_account.h"
      44              : #include "exchange-database/get_legitimization_process_by_account.h"
      45              : #include "exchange-database/get_pending_legitimization_process.h"
      46              : #include "exchange-database/insert_aml_program_failure.h"
      47              : #include "exchange-database/insert_kyc_failure.h"
      48              : #include "exchange-database/insert_legitimization_process.h"
      49              : #include "exchange-database/iterate_kyc_references.h"
      50              : #include "exchange-database/update_legitimization_process_by_row.h"
      51              : 
      52              : 
      53              : /**
      54              :  * Account the checks run processes against.
      55              :  */
      56              : static struct TDB_Account account;
      57              : 
      58              : 
      59              : /**
      60              :  * Measure set the processes work on.
      61              :  */
      62              : static uint64_t measure_row;
      63              : 
      64              : 
      65              : /**
      66              :  * Row of the process check_start() created.
      67              :  */
      68              : static uint64_t process_row;
      69              : 
      70              : 
      71              : /**
      72              :  * Closure for #reference_cb().
      73              :  */
      74              : struct ReferenceContext
      75              : {
      76              :   /**
      77              :    * How many references did the callback see?
      78              :    */
      79              :   unsigned int total;
      80              : 
      81              :   /**
      82              :    * Provider we are looking for, NULL to match nothing.
      83              :    */
      84              :   const char *provider;
      85              : 
      86              :   /**
      87              :    * How many times did we see it?
      88              :    */
      89              :   unsigned int matched;
      90              : 
      91              :   /**
      92              :    * Provider account id reported for it, owned by this struct.
      93              :    */
      94              :   char *user_id;
      95              : 
      96              :   /**
      97              :    * Provider legitimization id reported for it, owned by this struct.
      98              :    */
      99              :   char *legi_id;
     100              : };
     101              : 
     102              : 
     103              : /**
     104              :  * Callback for #TALER_EXCHANGEDB_iterate_kyc_references().
     105              :  *
     106              :  * @param cls a `struct ReferenceContext *`
     107              :  * @param kyc_provider_name provider that ran the process
     108              :  * @param provider_user_id account id at the provider
     109              :  * @param legi_id legitimization id at the provider
     110              :  */
     111              : static void
     112            5 : reference_cb (void *cls,
     113              :               const char *kyc_provider_name,
     114              :               const char *provider_user_id,
     115              :               const char *legi_id)
     116              : {
     117            5 :   struct ReferenceContext *ctx = cls;
     118              : 
     119            5 :   ctx->total++;
     120            5 :   if ( (NULL != ctx->provider) &&
     121            5 :        (0 == strcmp (kyc_provider_name,
     122              :                      ctx->provider)) )
     123              :   {
     124            2 :     ctx->matched++;
     125            2 :     GNUNET_free (ctx->user_id);
     126            2 :     GNUNET_free (ctx->legi_id);
     127            2 :     ctx->user_id = (NULL == provider_user_id)
     128              :       ? NULL
     129            2 :       : GNUNET_strdup (provider_user_id);
     130            2 :     ctx->legi_id = (NULL == legi_id)
     131              :       ? NULL
     132            2 :       : GNUNET_strdup (legi_id);
     133              :   }
     134            5 : }
     135              : 
     136              : 
     137              : /**
     138              :  * Put a measure on our account, creating the account on the way.
     139              :  *
     140              :  * @param pg the database context
     141              :  */
     142              : static void
     143            1 : setup_account (struct TALER_EXCHANGEDB_PostgresContext *pg)
     144              : {
     145              :   json_t *jmeasures;
     146            1 :   uint64_t row = 0;
     147              :   bool bad_kyc_auth;
     148              : 
     149            1 :   if (0 != measure_row)
     150            0 :     return;
     151            1 :   TDB_account (pg,
     152              :                10,
     153              :                &account);
     154            1 :   jmeasures = GNUNET_JSON_PACK (
     155              :     GNUNET_JSON_pack_array_steal (
     156              :       "measures",
     157              :       json_pack ("[{s:s,s:s,s:s}]",
     158              :                  "check_name",
     159              :                  "verify-id",
     160              :                  "prog_name",
     161              :                  "skip",
     162              :                  "context",
     163              :                  "none")),
     164              :     GNUNET_JSON_pack_bool ("is_and_combinator",
     165              :                            true));
     166            1 :   GNUNET_assert (NULL != jmeasures);
     167            1 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     168              :                  TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
     169              :                    pg,
     170              :                    account.payto,
     171              :                    &account.h_normalized,
     172              :                    NULL,
     173              :                    NULL,
     174              :                    jmeasures,
     175              :                    1,
     176              :                    &row,
     177              :                    &bad_kyc_auth));
     178            1 :   json_decref (jmeasures);
     179            1 :   GNUNET_assert (0 != row);
     180            1 :   measure_row = row;
     181              : }
     182              : 
     183              : 
     184              : /**
     185              :  * Nothing is known while the table is empty.
     186              :  *
     187              :  * @param pg the database context
     188              :  * @return 0 on success
     189              :  */
     190              : static int
     191            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
     192              : {
     193              :   struct TALER_NormalizedPaytoHashP h_payto;
     194              :   struct GNUNET_TIME_Absolute expiration;
     195            1 :   struct ReferenceContext ctx = { 0 };
     196            1 :   char *provider_account_id = NULL;
     197            1 :   char *provider_legitimization_id = NULL;
     198            1 :   char *redirect_url = NULL;
     199              :   uint64_t row;
     200              :   bool is_wallet;
     201              : 
     202            1 :   setup_account (pg);
     203            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     204              :           TALER_EXCHANGEDB_get_legitimization_process_by_account (
     205              :             pg,
     206              :             "test-provider",
     207              :             &account.h_normalized,
     208              :             &row,
     209              :             &expiration,
     210              :             &provider_account_id,
     211              :             &provider_legitimization_id,
     212              :             &is_wallet));
     213            1 :   FAILIF (NULL != provider_account_id);
     214            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     215              :           TALER_EXCHANGEDB_get_pending_legitimization_process (
     216              :             pg,
     217              :             &account.h_normalized,
     218              :             "test-provider",
     219              :             &redirect_url));
     220            1 :   FAILIF (NULL != redirect_url);
     221            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     222              :           TALER_EXCHANGEDB_get_kyc_provider_account (pg,
     223              :                                                      "test-provider",
     224              :                                                      "legi-1",
     225              :                                                      &h_payto,
     226              :                                                      &is_wallet,
     227              :                                                      &row));
     228            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     229              :           TALER_EXCHANGEDB_iterate_kyc_references (pg,
     230              :                                                    &account.h_normalized,
     231              :                                                    &reference_cb,
     232              :                                                    &ctx));
     233            1 :   FAILIF (0 != ctx.total);
     234            1 :   return 0;
     235              : }
     236              : 
     237              : 
     238              : /**
     239              :  * Starting a process records it and makes it findable by provider and by
     240              :  * the provider's own identifiers.
     241              :  *
     242              :  * @param pg the database context
     243              :  * @return 0 on success
     244              :  */
     245              : static int
     246            1 : check_start (struct TALER_EXCHANGEDB_PostgresContext *pg)
     247              : {
     248              :   struct TALER_NormalizedPaytoHashP h_payto;
     249              :   struct GNUNET_TIME_Absolute expiration;
     250              :   struct ReferenceContext ctx;
     251            1 :   char *provider_account_id = NULL;
     252            1 :   char *provider_legitimization_id = NULL;
     253            1 :   uint64_t row = 0;
     254            1 :   bool is_wallet = true;
     255              : 
     256            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     257              :           TALER_EXCHANGEDB_insert_legitimization_process (
     258              :             pg,
     259              :             &account.h_normalized,
     260              :             0,
     261              :             measure_row,
     262              :             "test-provider",
     263              :             "provider-account-1",
     264              :             "legi-1",
     265              :             &process_row));
     266            1 :   FAILIF (0 == process_row);
     267            1 :   FAILIF (1 != TDB_count (pg,
     268              :                           "FROM legitimization_processes"));
     269              : 
     270            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     271              :           TALER_EXCHANGEDB_get_legitimization_process_by_account (
     272              :             pg,
     273              :             "test-provider",
     274              :             &account.h_normalized,
     275              :             &row,
     276              :             &expiration,
     277              :             &provider_account_id,
     278              :             &provider_legitimization_id,
     279              :             &is_wallet));
     280            1 :   FAILIF (row != process_row);
     281            1 :   FAILIF_C (0 != strcmp (provider_account_id,
     282              :                          "provider-account-1"),
     283              :             GNUNET_free (provider_account_id);
     284              :             GNUNET_free (provider_legitimization_id));
     285            1 :   FAILIF_C (0 != strcmp (provider_legitimization_id,
     286              :                          "legi-1"),
     287              :             GNUNET_free (provider_account_id);
     288              :             GNUNET_free (provider_legitimization_id));
     289            1 :   GNUNET_free (provider_account_id);
     290            1 :   GNUNET_free (provider_legitimization_id);
     291            1 :   FAILIF (is_wallet);
     292              : 
     293              :   /* another provider has no process on this account */
     294            1 :   provider_account_id = NULL;
     295            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     296              :           TALER_EXCHANGEDB_get_legitimization_process_by_account (
     297              :             pg,
     298              :             "other-provider",
     299              :             &account.h_normalized,
     300              :             &row,
     301              :             &expiration,
     302              :             &provider_account_id,
     303              :             &provider_legitimization_id,
     304              :             &is_wallet));
     305              : 
     306              :   /* the provider's own identifier resolves back to the account */
     307            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     308              :           TALER_EXCHANGEDB_get_kyc_provider_account (pg,
     309              :                                                      "test-provider",
     310              :                                                      "legi-1",
     311              :                                                      &h_payto,
     312              :                                                      &is_wallet,
     313              :                                                      &row));
     314            1 :   FAILIF (0 != GNUNET_memcmp (&h_payto,
     315              :                               &account.h_normalized));
     316            1 :   FAILIF (row != process_row);
     317            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     318              :           TALER_EXCHANGEDB_get_kyc_provider_account (pg,
     319              :                                                      "test-provider",
     320              :                                                      "legi-does-not-exist",
     321              :                                                      &h_payto,
     322              :                                                      &is_wallet,
     323              :                                                      &row));
     324              : 
     325            1 :   memset (&ctx,
     326              :           0,
     327              :           sizeof (ctx));
     328            1 :   ctx.provider = "test-provider";
     329            1 :   FAILIF (0 >=
     330              :           TALER_EXCHANGEDB_iterate_kyc_references (pg,
     331              :                                                    &account.h_normalized,
     332              :                                                    &reference_cb,
     333              :                                                    &ctx));
     334            1 :   FAILIF_C (1 != ctx.matched,
     335              :             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
     336            1 :   FAILIF_C (0 != strcmp (ctx.user_id,
     337              :                          "provider-account-1"),
     338              :             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
     339            1 :   GNUNET_free (ctx.user_id);
     340            1 :   GNUNET_free (ctx.legi_id);
     341            1 :   return 0;
     342              : }
     343              : 
     344              : 
     345              : /**
     346              :  * Updating a process records the redirect URL and can mark it finished.
     347              :  *
     348              :  * @param pg the database context
     349              :  * @return 0 on success
     350              :  */
     351              : static int
     352            1 : check_update (struct TALER_EXCHANGEDB_PostgresContext *pg)
     353              : {
     354              :   struct GNUNET_TIME_Absolute expiration
     355            1 :     = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
     356            1 :   char *redirect_url = NULL;
     357              : 
     358            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     359              :           TALER_EXCHANGEDB_update_legitimization_process_by_row (
     360              :             pg,
     361              :             process_row,
     362              :             "test-provider",
     363              :             &account.h_normalized,
     364              :             "provider-account-1",
     365              :             "legi-1",
     366              :             "https://kyc.example/start",
     367              :             expiration,
     368              :             TALER_EC_NONE,
     369              :             NULL,
     370              :             false));
     371            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     372              :           TALER_EXCHANGEDB_get_pending_legitimization_process (
     373              :             pg,
     374              :             &account.h_normalized,
     375              :             "test-provider",
     376              :             &redirect_url));
     377            1 :   FAILIF (NULL == redirect_url);
     378            1 :   FAILIF_C (0 != strcmp (redirect_url,
     379              :                          "https://kyc.example/start"),
     380              :             GNUNET_free (redirect_url));
     381            1 :   GNUNET_free (redirect_url);
     382              : 
     383              :   /* a row that does not exist is not created */
     384            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     385              :           TALER_EXCHANGEDB_update_legitimization_process_by_row (
     386              :             pg,
     387              :             process_row + 1000,
     388              :             "test-provider",
     389              :             &account.h_normalized,
     390              :             "provider-account-1",
     391              :             "legi-1",
     392              :             "https://kyc.example/start",
     393              :             expiration,
     394              :             TALER_EC_NONE,
     395              :             NULL,
     396              :             false));
     397            1 :   FAILIF (1 != TDB_count (pg,
     398              :                           "FROM legitimization_processes"));
     399              : 
     400              :   /* marking it finished takes it out of the pending view */
     401            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     402              :           TALER_EXCHANGEDB_update_legitimization_process_by_row (
     403              :             pg,
     404              :             process_row,
     405              :             "test-provider",
     406              :             &account.h_normalized,
     407              :             "provider-account-1",
     408              :             "legi-1",
     409              :             "https://kyc.example/start",
     410              :             expiration,
     411              :             TALER_EC_NONE,
     412              :             NULL,
     413              :             true));
     414            1 :   redirect_url = NULL;
     415            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     416              :           TALER_EXCHANGEDB_get_pending_legitimization_process (
     417              :             pg,
     418              :             &account.h_normalized,
     419              :             "test-provider",
     420              :             &redirect_url));
     421            1 :   FAILIF (NULL != redirect_url);
     422            1 :   return 0;
     423              : }
     424              : 
     425              : 
     426              : /**
     427              :  * A failed KYC check marks the process finished with an error.
     428              :  *
     429              :  * @param pg the database context
     430              :  * @return 0 on success
     431              :  */
     432              : static int
     433            1 : check_kyc_failure (struct TALER_EXCHANGEDB_PostgresContext *pg)
     434              : {
     435            1 :   uint64_t row = 0;
     436              : 
     437            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     438              :           TALER_EXCHANGEDB_insert_legitimization_process (
     439              :             pg,
     440              :             &account.h_normalized,
     441              :             1,
     442              :             measure_row,
     443              :             "failing-provider",
     444              :             "provider-account-2",
     445              :             "legi-2",
     446              :             &row));
     447            1 :   FAILIF (2 != TDB_count (pg,
     448              :                           "FROM legitimization_processes"));
     449            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     450              :           TALER_EXCHANGEDB_insert_kyc_failure (
     451              :             pg,
     452              :             row,
     453              :             &account.h_normalized,
     454              :             "failing-provider",
     455              :             "provider-account-2",
     456              :             "legi-2",
     457              :             "the provider said no",
     458              :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY));
     459            1 :   FAILIF (1 != TDB_count (pg,
     460              :                           "FROM legitimization_processes"
     461              :                           " WHERE finished"
     462              :                           "   AND error_code=%u",
     463              :                           (unsigned int)
     464              :                           TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY));
     465              :   /* a row that does not exist is not created */
     466            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     467              :           TALER_EXCHANGEDB_insert_kyc_failure (
     468              :             pg,
     469              :             row + 1000,
     470              :             &account.h_normalized,
     471              :             "failing-provider",
     472              :             "provider-account-2",
     473              :             "legi-2",
     474              :             "the provider said no",
     475              :             TALER_EC_EXCHANGE_KYC_GENERIC_PROVIDER_UNEXPECTED_REPLY));
     476            1 :   FAILIF (2 != TDB_count (pg,
     477              :                           "FROM legitimization_processes"));
     478            1 :   return 0;
     479              : }
     480              : 
     481              : 
     482              : /**
     483              :  * A failed AML program marks its process finished with an error too.
     484              :  *
     485              :  * @param pg the database context
     486              :  * @return 0 on success
     487              :  */
     488              : static int
     489            1 : check_aml_program_failure (struct TALER_EXCHANGEDB_PostgresContext *pg)
     490              : {
     491            1 :   uint64_t row = 0;
     492              : 
     493            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     494              :           TALER_EXCHANGEDB_insert_legitimization_process (
     495              :             pg,
     496              :             &account.h_normalized,
     497              :             2,
     498              :             measure_row,
     499              :             "aml-provider",
     500              :             "provider-account-3",
     501              :             "legi-3",
     502              :             &row));
     503            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     504              :           TALER_EXCHANGEDB_insert_aml_program_failure (
     505              :             pg,
     506              :             row,
     507              :             &account.h_normalized,
     508              :             "the AML program crashed",
     509              :             TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE));
     510            1 :   FAILIF (1 != TDB_count (pg,
     511              :                           "FROM legitimization_processes"
     512              :                           " WHERE finished"
     513              :                           "   AND error_code=%u",
     514              :                           (unsigned int)
     515              :                           TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE));
     516              :   /* Unlike insert_kyc_failure(), a row that does not exist is *created*
     517              :      here rather than ignored -- the stored procedure would rather keep a
     518              :      record of the failed AML program than lose it. */
     519            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     520              :           TALER_EXCHANGEDB_insert_aml_program_failure (
     521              :             pg,
     522              :             row + 1000,
     523              :             &account.h_normalized,
     524              :             "the AML program crashed",
     525              :             TALER_EC_EXCHANGE_KYC_AML_PROGRAM_FAILURE));
     526            1 :   FAILIF (4 != TDB_count (pg,
     527              :                           "FROM legitimization_processes"));
     528            1 :   return 0;
     529              : }
     530              : 
     531              : 
     532              : /**
     533              :  * The reference listing reports every provider that worked on the
     534              :  * account.
     535              :  *
     536              :  * @param pg the database context
     537              :  * @return 0 on success
     538              :  */
     539              : static int
     540            1 : check_references (struct TALER_EXCHANGEDB_PostgresContext *pg)
     541              : {
     542              :   struct ReferenceContext ctx;
     543              : 
     544            1 :   memset (&ctx,
     545              :           0,
     546              :           sizeof (ctx));
     547            1 :   ctx.provider = "aml-provider";
     548            1 :   FAILIF (0 >=
     549              :           TALER_EXCHANGEDB_iterate_kyc_references (pg,
     550              :                                                    &account.h_normalized,
     551              :                                                    &reference_cb,
     552              :                                                    &ctx));
     553            1 :   FAILIF_C (1 != ctx.matched,
     554              :             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
     555            1 :   FAILIF_C (4 != ctx.total,
     556              :             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
     557            1 :   GNUNET_free (ctx.user_id);
     558            1 :   GNUNET_free (ctx.legi_id);
     559              : 
     560              :   /* an account nobody checked has no references */
     561              :   {
     562              :     struct TALER_NormalizedPaytoHashP other;
     563              : 
     564            1 :     TDB_FILL (other,
     565              :               98);
     566            1 :     memset (&ctx,
     567              :             0,
     568              :             sizeof (ctx));
     569            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     570              :             TALER_EXCHANGEDB_iterate_kyc_references (pg,
     571              :                                                      &other,
     572              :                                                      &reference_cb,
     573              :                                                      &ctx));
     574            1 :     FAILIF (0 != ctx.total);
     575              :   }
     576            1 :   return 0;
     577              : }
     578              : 
     579              : 
     580              : /**
     581              :  * Process initiation is reserved atomically, completed only by the owner,
     582              :  * and restarted after its provider-side expiration.
     583              :  *
     584              :  * @param pg the database context
     585              :  * @return 0 on success
     586              :  */
     587              : static int
     588            1 : check_reservation (struct TALER_EXCHANGEDB_PostgresContext *pg)
     589              : {
     590            1 :   const char *provider = "reservation-provider";
     591            1 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
     592              :   struct GNUNET_TIME_Absolute lease_expiration
     593            1 :     = GNUNET_TIME_absolute_add (now,
     594              :                                 GNUNET_TIME_UNIT_MINUTES);
     595              :   struct GNUNET_TIME_Absolute process_expiration
     596            1 :     = GNUNET_TIME_absolute_add (now,
     597              :                                 GNUNET_TIME_UNIT_HOURS);
     598              :   struct GNUNET_TIME_Absolute start_time;
     599              :   struct GNUNET_TIME_Absolute other_start_time;
     600              :   struct GNUNET_TIME_Absolute restart_time;
     601              :   struct GNUNET_TIME_Absolute restart_lease;
     602              :   enum TALER_EXCHANGEDB_KycProcessReservationState state;
     603              :   uint64_t row;
     604              :   uint64_t other_row;
     605            1 :   char *redirect_url = NULL;
     606              : 
     607            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     608              :           TALER_EXCHANGEDB_do_reserve_legitimization_process (
     609              :             pg,
     610              :             &account.h_normalized,
     611              :             3,
     612              :             measure_row,
     613              :             provider,
     614              :             now,
     615              :             lease_expiration,
     616              :             &row,
     617              :             &start_time,
     618              :             &redirect_url,
     619              :             &state));
     620            1 :   FAILIF (TALER_EXCHANGEDB_KPRS_OWNER != state);
     621            1 :   FAILIF (NULL != redirect_url);
     622              : 
     623              :   /* A concurrent request must wait for the reservation owner. */
     624            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     625              :           TALER_EXCHANGEDB_do_reserve_legitimization_process (
     626              :             pg,
     627              :             &account.h_normalized,
     628              :             3,
     629              :             measure_row,
     630              :             provider,
     631              :             now,
     632              :             lease_expiration,
     633              :             &other_row,
     634              :             &other_start_time,
     635              :             &redirect_url,
     636              :             &state));
     637            1 :   FAILIF (TALER_EXCHANGEDB_KPRS_BUSY != state);
     638            1 :   FAILIF (row != other_row);
     639            1 :   FAILIF (start_time.abs_value_us != other_start_time.abs_value_us);
     640            1 :   FAILIF (NULL != redirect_url);
     641              : 
     642            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     643              :           TALER_EXCHANGEDB_update_legitimization_process_start (
     644              :             pg,
     645              :             row,
     646              :             start_time,
     647              :             provider,
     648              :             &account.h_normalized,
     649              :             "provider-account-reservation",
     650              :             "provider-process-reservation",
     651              :             "https://kyc.example/reserved",
     652              :             process_expiration,
     653              :             TALER_EC_NONE,
     654              :             NULL,
     655              :             false));
     656              : 
     657              :   /* Once initiation completed, all requests reuse its redirect. */
     658            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     659              :           TALER_EXCHANGEDB_do_reserve_legitimization_process (
     660              :             pg,
     661              :             &account.h_normalized,
     662              :             3,
     663              :             measure_row,
     664              :             provider,
     665              :             now,
     666              :             lease_expiration,
     667              :             &other_row,
     668              :             &other_start_time,
     669              :             &redirect_url,
     670              :             &state));
     671            1 :   FAILIF (TALER_EXCHANGEDB_KPRS_READY != state);
     672            1 :   FAILIF (row != other_row);
     673            1 :   FAILIF (NULL == redirect_url);
     674            1 :   FAILIF_C (0 != strcmp (redirect_url,
     675              :                          "https://kyc.example/reserved"),
     676              :             GNUNET_free (redirect_url));
     677            1 :   GNUNET_free (redirect_url);
     678            1 :   redirect_url = NULL;
     679              : 
     680              :   /* A callback from a superseded owner cannot overwrite the process. */
     681            1 :   other_start_time = GNUNET_TIME_absolute_add (
     682              :     start_time,
     683              :     GNUNET_TIME_UNIT_SECONDS);
     684            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     685              :           TALER_EXCHANGEDB_update_legitimization_process_start (
     686              :             pg,
     687              :             row,
     688              :             other_start_time,
     689              :             provider,
     690              :             &account.h_normalized,
     691              :             NULL,
     692              :             NULL,
     693              :             "https://kyc.example/late",
     694              :             process_expiration,
     695              :             TALER_EC_NONE,
     696              :             NULL,
     697              :             false));
     698              : 
     699              :   /* Expiration makes the next request the owner of a fresh start. */
     700            1 :   restart_time = GNUNET_TIME_absolute_add (
     701              :     process_expiration,
     702              :     GNUNET_TIME_UNIT_SECONDS);
     703            1 :   restart_lease = GNUNET_TIME_absolute_add (
     704              :     restart_time,
     705              :     GNUNET_TIME_UNIT_MINUTES);
     706            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     707              :           TALER_EXCHANGEDB_do_reserve_legitimization_process (
     708              :             pg,
     709              :             &account.h_normalized,
     710              :             3,
     711              :             measure_row,
     712              :             provider,
     713              :             restart_time,
     714              :             restart_lease,
     715              :             &other_row,
     716              :             &other_start_time,
     717              :             &redirect_url,
     718              :             &state));
     719            1 :   FAILIF (TALER_EXCHANGEDB_KPRS_OWNER != state);
     720            1 :   FAILIF (row != other_row);
     721            1 :   FAILIF (start_time.abs_value_us == other_start_time.abs_value_us);
     722            1 :   FAILIF (NULL != redirect_url);
     723            1 :   return 0;
     724              : }
     725              : 
     726              : 
     727              : /**
     728              :  * The checks to run, in order.
     729              :  */
     730              : static const struct TDB_Test tests[] = {
     731              :   { "legitimization-processes-empty",
     732              :     &check_empty },
     733              :   { "legitimization-processes-start",
     734              :     &check_start },
     735              :   { "legitimization-processes-update",
     736              :     &check_update },
     737              :   { "legitimization-processes-kyc-failure",
     738              :     &check_kyc_failure },
     739              :   { "legitimization-processes-aml-program-failure",
     740              :     &check_aml_program_failure },
     741              :   { "legitimization-processes-references",
     742              :     &check_references },
     743              :   { "legitimization-processes-reservation",
     744              :     &check_reservation },
     745              :   { NULL, NULL }
     746              : };
     747              : 
     748              : 
     749              : int
     750            1 : main (int argc,
     751              :       char *const *argv)
     752              : {
     753              :   int ret;
     754              : 
     755            1 :   ret = TDB_main (argc,
     756              :                   argv,
     757              :                   "test-legitimization-processes",
     758              :                   "Tests for the exchangedb `legitimization_processes' table",
     759              :                   tests);
     760            1 :   TDB_account_free (&account);
     761            1 :   return ret;
     762              : }
     763              : 
     764              : 
     765              : /* end of test_legitimization_processes.c */
        

Generated by: LCOV version 2.0-1