exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_legitimization_processes.c (24210B)


      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_complete_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/complete_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 reference_cb (void *cls,
    113               const char *kyc_provider_name,
    114               const char *provider_user_id,
    115               const char *legi_id)
    116 {
    117   struct ReferenceContext *ctx = cls;
    118 
    119   ctx->total++;
    120   if ( (NULL != ctx->provider) &&
    121        (0 == strcmp (kyc_provider_name,
    122                      ctx->provider)) )
    123   {
    124     ctx->matched++;
    125     GNUNET_free (ctx->user_id);
    126     GNUNET_free (ctx->legi_id);
    127     ctx->user_id = (NULL == provider_user_id)
    128       ? NULL
    129       : GNUNET_strdup (provider_user_id);
    130     ctx->legi_id = (NULL == legi_id)
    131       ? NULL
    132       : GNUNET_strdup (legi_id);
    133   }
    134 }
    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 setup_account (struct TALER_EXCHANGEDB_PostgresContext *pg)
    144 {
    145   json_t *jmeasures;
    146   uint64_t row = 0;
    147   bool bad_kyc_auth;
    148 
    149   if (0 != measure_row)
    150     return;
    151   TDB_account (pg,
    152                10,
    153                &account);
    154   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   GNUNET_assert (NULL != jmeasures);
    167   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   json_decref (jmeasures);
    179   GNUNET_assert (0 != row);
    180   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 check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
    192 {
    193   struct TALER_NormalizedPaytoHashP h_payto;
    194   struct GNUNET_TIME_Absolute expiration;
    195   struct ReferenceContext ctx = { 0 };
    196   char *provider_account_id = NULL;
    197   char *provider_legitimization_id = NULL;
    198   char *redirect_url = NULL;
    199   uint64_t row;
    200   bool is_wallet;
    201 
    202   setup_account (pg);
    203   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   FAILIF (NULL != provider_account_id);
    214   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   FAILIF (NULL != redirect_url);
    221   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   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    229           TALER_EXCHANGEDB_iterate_kyc_references (pg,
    230                                                    &account.h_normalized,
    231                                                    &reference_cb,
    232                                                    &ctx));
    233   FAILIF (0 != ctx.total);
    234   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 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   char *provider_account_id = NULL;
    252   char *provider_legitimization_id = NULL;
    253   uint64_t row = 0;
    254   bool is_wallet = true;
    255 
    256   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   FAILIF (0 == process_row);
    267   FAILIF (1 != TDB_count (pg,
    268                           "FROM legitimization_processes"));
    269 
    270   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   FAILIF (row != process_row);
    281   FAILIF_C (0 != strcmp (provider_account_id,
    282                          "provider-account-1"),
    283             GNUNET_free (provider_account_id);
    284             GNUNET_free (provider_legitimization_id));
    285   FAILIF_C (0 != strcmp (provider_legitimization_id,
    286                          "legi-1"),
    287             GNUNET_free (provider_account_id);
    288             GNUNET_free (provider_legitimization_id));
    289   GNUNET_free (provider_account_id);
    290   GNUNET_free (provider_legitimization_id);
    291   FAILIF (is_wallet);
    292 
    293   /* another provider has no process on this account */
    294   provider_account_id = NULL;
    295   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   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   FAILIF (0 != GNUNET_memcmp (&h_payto,
    315                               &account.h_normalized));
    316   FAILIF (row != process_row);
    317   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   memset (&ctx,
    326           0,
    327           sizeof (ctx));
    328   ctx.provider = "test-provider";
    329   FAILIF (0 >=
    330           TALER_EXCHANGEDB_iterate_kyc_references (pg,
    331                                                    &account.h_normalized,
    332                                                    &reference_cb,
    333                                                    &ctx));
    334   FAILIF_C (1 != ctx.matched,
    335             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
    336   FAILIF_C (0 != strcmp (ctx.user_id,
    337                          "provider-account-1"),
    338             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
    339   GNUNET_free (ctx.user_id);
    340   GNUNET_free (ctx.legi_id);
    341   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 check_update (struct TALER_EXCHANGEDB_PostgresContext *pg)
    353 {
    354   struct GNUNET_TIME_Absolute expiration
    355     = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS);
    356   char *redirect_url = NULL;
    357 
    358   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   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   FAILIF (NULL == redirect_url);
    378   FAILIF_C (0 != strcmp (redirect_url,
    379                          "https://kyc.example/start"),
    380             GNUNET_free (redirect_url));
    381   GNUNET_free (redirect_url);
    382 
    383   /* a row that does not exist is not created */
    384   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   FAILIF (1 != TDB_count (pg,
    398                           "FROM legitimization_processes"));
    399 
    400   /* marking it finished takes it out of the pending view */
    401   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   redirect_url = NULL;
    415   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   FAILIF (NULL != redirect_url);
    422   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 check_kyc_failure (struct TALER_EXCHANGEDB_PostgresContext *pg)
    434 {
    435   uint64_t row = 0;
    436 
    437   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   FAILIF (2 != TDB_count (pg,
    448                           "FROM legitimization_processes"));
    449   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   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   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   FAILIF (2 != TDB_count (pg,
    477                           "FROM legitimization_processes"));
    478   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 check_aml_program_failure (struct TALER_EXCHANGEDB_PostgresContext *pg)
    490 {
    491   uint64_t row = 0;
    492 
    493   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   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   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   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   FAILIF (4 != TDB_count (pg,
    527                           "FROM legitimization_processes"));
    528   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 check_references (struct TALER_EXCHANGEDB_PostgresContext *pg)
    541 {
    542   struct ReferenceContext ctx;
    543 
    544   memset (&ctx,
    545           0,
    546           sizeof (ctx));
    547   ctx.provider = "aml-provider";
    548   FAILIF (0 >=
    549           TALER_EXCHANGEDB_iterate_kyc_references (pg,
    550                                                    &account.h_normalized,
    551                                                    &reference_cb,
    552                                                    &ctx));
    553   FAILIF_C (1 != ctx.matched,
    554             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
    555   FAILIF_C (4 != ctx.total,
    556             GNUNET_free (ctx.user_id); GNUNET_free (ctx.legi_id));
    557   GNUNET_free (ctx.user_id);
    558   GNUNET_free (ctx.legi_id);
    559 
    560   /* an account nobody checked has no references */
    561   {
    562     struct TALER_NormalizedPaytoHashP other;
    563 
    564     TDB_FILL (other,
    565               98);
    566     memset (&ctx,
    567             0,
    568             sizeof (ctx));
    569     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    570             TALER_EXCHANGEDB_iterate_kyc_references (pg,
    571                                                      &other,
    572                                                      &reference_cb,
    573                                                      &ctx));
    574     FAILIF (0 != ctx.total);
    575   }
    576   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 check_reservation (struct TALER_EXCHANGEDB_PostgresContext *pg)
    589 {
    590   const char *provider = "reservation-provider";
    591   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
    592   struct GNUNET_TIME_Absolute lease_expiration
    593     = GNUNET_TIME_absolute_add (now,
    594                                 GNUNET_TIME_UNIT_MINUTES);
    595   struct GNUNET_TIME_Absolute process_expiration
    596     = 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   char *redirect_url = NULL;
    606 
    607   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   FAILIF (TALER_EXCHANGEDB_KPRS_OWNER != state);
    621   FAILIF (NULL != redirect_url);
    622 
    623   /* A concurrent request must wait for the reservation owner. */
    624   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   FAILIF (TALER_EXCHANGEDB_KPRS_BUSY != state);
    638   FAILIF (row != other_row);
    639   FAILIF (start_time.abs_value_us != other_start_time.abs_value_us);
    640   FAILIF (NULL != redirect_url);
    641 
    642   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    643           TALER_EXCHANGEDB_complete_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   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   FAILIF (TALER_EXCHANGEDB_KPRS_READY != state);
    672   FAILIF (row != other_row);
    673   FAILIF (NULL == redirect_url);
    674   FAILIF_C (0 != strcmp (redirect_url,
    675                          "https://kyc.example/reserved"),
    676             GNUNET_free (redirect_url));
    677   GNUNET_free (redirect_url);
    678   redirect_url = NULL;
    679 
    680   /* A callback from a superseded owner cannot overwrite the process. */
    681   other_start_time = GNUNET_TIME_absolute_add (
    682     start_time,
    683     GNUNET_TIME_UNIT_SECONDS);
    684   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    685           TALER_EXCHANGEDB_complete_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   restart_time = GNUNET_TIME_absolute_add (
    701     process_expiration,
    702     GNUNET_TIME_UNIT_SECONDS);
    703   restart_lease = GNUNET_TIME_absolute_add (
    704     restart_time,
    705     GNUNET_TIME_UNIT_MINUTES);
    706   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   FAILIF (TALER_EXCHANGEDB_KPRS_OWNER != state);
    720   FAILIF (row != other_row);
    721   FAILIF (start_time.abs_value_us == other_start_time.abs_value_us);
    722   FAILIF (NULL != redirect_url);
    723   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 main (int argc,
    751       char *const *argv)
    752 {
    753   int ret;
    754 
    755   ret = TDB_main (argc,
    756                   argv,
    757                   "test-legitimization-processes",
    758                   "Tests for the exchangedb `legitimization_processes' table",
    759                   tests);
    760   TDB_account_free (&account);
    761   return ret;
    762 }
    763 
    764 
    765 /* end of test_legitimization_processes.c */