LCOV - code coverage report
Current view: top level - exchangedb - test_kyc_attributes.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 99.1 % 218 216
Test Date: 2026-10-29 19:05:17 Functions: 100.0 % 16 16

            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_kyc_attributes.c
      18              :  * @brief tests for the exchangedb functions whose primary table is
      19              :  *        `kyc_attributes`
      20              :  * @author Christian Grothoff
      21              :  *
      22              :  * Covers #TALER_EXCHANGEDB_do_insert_kyc_attributes(),
      23              :  * #TALER_EXCHANGEDB_iterate_kyc_attributes(),
      24              :  * #TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes(),
      25              :  * #TALER_EXCHANGEDB_update_to_kyc_attributes_screened(),
      26              :  * #TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened(),
      27              :  * #TALER_EXCHANGEDB_iterate_aml_attributes(),
      28              :  * #TALER_EXCHANGEDB_iterate_kyc_history(),
      29              :  * #TALER_EXCHANGEDB_kyc_history_builder() and
      30              :  * #TALER_EXCHANGEDB_current_attributes_builder().
      31              :  *
      32              :  * A `kyc_attributes` row is the (encrypted) personal data one KYC process
      33              :  * collected, so every row needs a `legitimization_processes` row to hang
      34              :  * off; those in turn need a legitimization measure on a known account.
      35              :  * That is what setup_account() builds before the first insert.  The AML
      36              :  * officer path is exercised too, because it is the only way to get a row
      37              :  * with `by_aml_officer` set, which is what the AML attribute iterator
      38              :  * reports on.
      39              :  */
      40              : #include "test_common.h"
      41              : #include "exchange-database/account_history.h"
      42              : #include "exchange-database/do_insert_kyc_attributes.h"
      43              : #include "exchange-database/do_trigger_kyc_rule_for_account.h"
      44              : #include "exchange-database/insert_aml_decision.h"
      45              : #include "exchange-database/insert_aml_officer.h"
      46              : #include "exchange-database/insert_legitimization_process.h"
      47              : #include "exchange-database/iterate_unscreened_kyc_attributes.h"
      48              : #include "exchange-database/iterate_aml_attributes.h"
      49              : #include "exchange-database/iterate_kyc_attributes.h"
      50              : #include "exchange-database/iterate_kyc_history.h"
      51              : #include "exchange-database/update_to_kyc_attributes_screened.h"
      52              : #include "exchange-database/update_to_kyc_attributes_unscreened.h"
      53              : 
      54              : 
      55              : /**
      56              :  * Account the attributes are about.
      57              :  */
      58              : static struct TDB_Account account;
      59              : 
      60              : 
      61              : /**
      62              :  * Row of the legitimization measures on @e account.
      63              :  */
      64              : static uint64_t measure_row;
      65              : 
      66              : 
      67              : /**
      68              :  * Rows of the two KYC processes we run on @e account.
      69              :  */
      70              : static uint64_t process_row[2];
      71              : 
      72              : 
      73              : /**
      74              :  * Key the attributes are encrypted with.
      75              :  */
      76              : static struct TALER_AttributeEncryptionKeyP attribute_key;
      77              : 
      78              : 
      79              : /**
      80              :  * Name the AML officer is on file under.
      81              :  */
      82              : #define OFFICER_NAME "Alex Officer"
      83              : 
      84              : 
      85              : /**
      86              :  * Build the attribute set of @a name for storage.
      87              :  *
      88              :  * @param name value of the NAME attribute
      89              :  * @param[out] enc set to the encrypted attributes, to be freed by the
      90              :  *        caller
      91              :  * @param[out] enc_size set to the number of bytes in @a enc
      92              :  */
      93              : static void
      94            3 : encrypt_attributes (const char *name,
      95              :                     void **enc,
      96              :                     size_t *enc_size)
      97              : {
      98              :   json_t *attrs;
      99              : 
     100            3 :   attrs = GNUNET_JSON_PACK (
     101              :     GNUNET_JSON_pack_string ("FORM_ID",
     102              :                              "test-form"),
     103              :     GNUNET_JSON_pack_string ("NAME",
     104              :                              name));
     105            3 :   GNUNET_assert (NULL != attrs);
     106            3 :   TALER_CRYPTO_kyc_attributes_encrypt (&attribute_key,
     107              :                                        attrs,
     108              :                                        enc,
     109              :                                        enc_size);
     110            3 :   json_decref (attrs);
     111            3 : }
     112              : 
     113              : 
     114              : /**
     115              :  * Closure for the various attribute callbacks.
     116              :  */
     117              : struct AttributeContext
     118              : {
     119              :   /**
     120              :    * How many rows did the callback see?
     121              :    */
     122              :   unsigned int total;
     123              : 
     124              :   /**
     125              :    * Stop after this many rows; 0 for no limit.
     126              :    */
     127              :   unsigned int stop_after;
     128              : 
     129              :   /**
     130              :    * Value of the NAME attribute of the last row seen, owned by this
     131              :    * struct.
     132              :    */
     133              :   char *name;
     134              : 
     135              :   /**
     136              :    * Provider of the last row seen, owned by this struct.
     137              :    */
     138              :   char *provider;
     139              : 
     140              :   /**
     141              :    * Officer of the last row seen, owned by this struct.
     142              :    */
     143              :   char *officer;
     144              : 
     145              :   /**
     146              :    * Row ID of the last row seen.
     147              :    */
     148              :   uint64_t row_id;
     149              : 
     150              :   /**
     151              :    * Was the last row filed by an AML officer?
     152              :    */
     153              :   bool by_aml_officer;
     154              : 
     155              :   /**
     156              :    * Was the KYC process of the last row finished?
     157              :    */
     158              :   bool finished;
     159              : };
     160              : 
     161              : 
     162              : /**
     163              :  * Release what a `struct AttributeContext` owns.
     164              :  *
     165              :  * @param[in,out] ctx context to clean up
     166              :  */
     167              : static void
     168           10 : ac_free (struct AttributeContext *ctx)
     169              : {
     170           10 :   GNUNET_free (ctx->name);
     171           10 :   GNUNET_free (ctx->provider);
     172           10 :   GNUNET_free (ctx->officer);
     173           10 : }
     174              : 
     175              : 
     176              : /**
     177              :  * Decrypt @a enc and remember its NAME attribute in @a ctx.
     178              :  *
     179              :  * @param[in,out] ctx context to update
     180              :  * @param enc_size number of bytes in @a enc
     181              :  * @param enc encrypted attributes
     182              :  */
     183              : static void
     184           12 : remember_name (struct AttributeContext *ctx,
     185              :                size_t enc_size,
     186              :                const void *enc)
     187              : {
     188              :   json_t *attrs;
     189              :   const char *name;
     190              : 
     191           12 :   GNUNET_free (ctx->name);
     192           12 :   ctx->name = NULL;
     193           12 :   attrs = TALER_CRYPTO_kyc_attributes_decrypt (&attribute_key,
     194              :                                                enc,
     195              :                                                enc_size);
     196           12 :   if (NULL == attrs)
     197            0 :     return;
     198           12 :   name = json_string_value (json_object_get (attrs,
     199              :                                              "NAME"));
     200           12 :   if (NULL != name)
     201           12 :     ctx->name = GNUNET_strdup (name);
     202           12 :   json_decref (attrs);
     203              : }
     204              : 
     205              : 
     206              : /**
     207              :  * Callback for #TALER_EXCHANGEDB_iterate_kyc_attributes().
     208              :  *
     209              :  * @param cls a `struct AttributeContext *`
     210              :  * @param h_payto account the attributes are about
     211              :  * @param provider_name provider that collected them
     212              :  * @param collection_time when they were collected
     213              :  * @param expiration_time when they expire
     214              :  * @param enc_attributes_size number of bytes in @a enc_attributes
     215              :  * @param enc_attributes the encrypted attributes
     216              :  */
     217              : static void
     218            2 : attribute_cb (void *cls,
     219              :               const struct TALER_NormalizedPaytoHashP *h_payto,
     220              :               const char *provider_name,
     221              :               struct GNUNET_TIME_Timestamp collection_time,
     222              :               struct GNUNET_TIME_Timestamp expiration_time,
     223              :               size_t enc_attributes_size,
     224              :               const void *enc_attributes)
     225              : {
     226            2 :   struct AttributeContext *ctx = cls;
     227              : 
     228              :   (void) h_payto;
     229              :   (void) collection_time;
     230              :   (void) expiration_time;
     231            2 :   ctx->total++;
     232            2 :   GNUNET_free (ctx->provider);
     233            2 :   ctx->provider = (NULL == provider_name)
     234              :     ? NULL
     235            2 :     : GNUNET_strdup (provider_name);
     236            2 :   remember_name (ctx,
     237              :                  enc_attributes_size,
     238              :                  enc_attributes);
     239            2 : }
     240              : 
     241              : 
     242              : /**
     243              :  * Callback for #TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes().
     244              :  *
     245              :  * @param cls a `struct AttributeContext *`
     246              :  * @param row_id row of the attributes
     247              :  * @param h_payto account the attributes are about
     248              :  * @param provider_name provider that collected them
     249              :  * @param collection_time when they were collected
     250              :  * @param expiration_time when they expire
     251              :  * @param properties properties set for the account
     252              :  * @param enc_attributes_size number of bytes in @a enc_attributes
     253              :  * @param enc_attributes the encrypted attributes
     254              :  * @return true to continue iterating
     255              :  */
     256              : static bool
     257            4 : all_attributes_cb (void *cls,
     258              :                    uint64_t row_id,
     259              :                    const struct TALER_NormalizedPaytoHashP *h_payto,
     260              :                    const char *provider_name,
     261              :                    struct GNUNET_TIME_Timestamp collection_time,
     262              :                    struct GNUNET_TIME_Timestamp expiration_time,
     263              :                    const json_t *properties,
     264              :                    size_t enc_attributes_size,
     265              :                    const void *enc_attributes)
     266              : {
     267            4 :   struct AttributeContext *ctx = cls;
     268              : 
     269              :   (void) h_payto;
     270              :   (void) collection_time;
     271              :   (void) expiration_time;
     272              :   (void) properties;
     273            4 :   ctx->total++;
     274            4 :   ctx->row_id = row_id;
     275            4 :   GNUNET_free (ctx->provider);
     276            4 :   ctx->provider = (NULL == provider_name)
     277              :     ? NULL
     278            4 :     : GNUNET_strdup (provider_name);
     279            4 :   remember_name (ctx,
     280              :                  enc_attributes_size,
     281              :                  enc_attributes);
     282            5 :   return ! ( (0 != ctx->stop_after) &&
     283            1 :              (ctx->total >= ctx->stop_after) );
     284              : }
     285              : 
     286              : 
     287              : /**
     288              :  * Callback for #TALER_EXCHANGEDB_iterate_aml_attributes().
     289              :  *
     290              :  * @param cls a `struct AttributeContext *`
     291              :  * @param row_id row of the attributes
     292              :  * @param collection_time when they were collected
     293              :  * @param by_aml_officer were they filed by an AML officer
     294              :  * @param officer_name name of that officer, NULL if none
     295              :  * @param enc_attributes_size number of bytes in @a enc_attributes
     296              :  * @param enc_attributes the encrypted attributes
     297              :  */
     298              : static void
     299            4 : aml_attribute_cb (void *cls,
     300              :                   uint64_t row_id,
     301              :                   struct GNUNET_TIME_Timestamp collection_time,
     302              :                   bool by_aml_officer,
     303              :                   const char *officer_name,
     304              :                   size_t enc_attributes_size,
     305              :                   const void *enc_attributes)
     306              : {
     307            4 :   struct AttributeContext *ctx = cls;
     308              : 
     309              :   (void) collection_time;
     310            4 :   ctx->total++;
     311            4 :   ctx->row_id = row_id;
     312            4 :   ctx->by_aml_officer = by_aml_officer;
     313            4 :   GNUNET_free (ctx->officer);
     314            4 :   ctx->officer = (NULL == officer_name)
     315              :     ? NULL
     316            4 :     : GNUNET_strdup (officer_name);
     317            4 :   remember_name (ctx,
     318              :                  enc_attributes_size,
     319              :                  enc_attributes);
     320            4 : }
     321              : 
     322              : 
     323              : /**
     324              :  * Callback for #TALER_EXCHANGEDB_iterate_kyc_history().
     325              :  *
     326              :  * @param cls a `struct AttributeContext *`
     327              :  * @param provider_name provider that ran the process
     328              :  * @param finished did the process finish
     329              :  * @param error_code error the process ran into
     330              :  * @param error_message message for @a error_code
     331              :  * @param provider_user_id account ID at the provider
     332              :  * @param provider_legitimization_id process ID at the provider
     333              :  * @param collection_time when the data was collected
     334              :  * @param expiration_time when the data expires
     335              :  * @param encrypted_attributes_len number of bytes in @a encrypted_attributes
     336              :  * @param encrypted_attributes the encrypted attributes
     337              :  */
     338              : static void
     339            2 : kyc_history_cb (void *cls,
     340              :                 const char *provider_name,
     341              :                 bool finished,
     342              :                 enum TALER_ErrorCode error_code,
     343              :                 const char *error_message,
     344              :                 const char *provider_user_id,
     345              :                 const char *provider_legitimization_id,
     346              :                 struct GNUNET_TIME_Timestamp collection_time,
     347              :                 struct GNUNET_TIME_Absolute expiration_time,
     348              :                 size_t encrypted_attributes_len,
     349              :                 const void *encrypted_attributes)
     350              : {
     351            2 :   struct AttributeContext *ctx = cls;
     352              : 
     353              :   (void) error_code;
     354              :   (void) error_message;
     355              :   (void) provider_user_id;
     356              :   (void) provider_legitimization_id;
     357              :   (void) collection_time;
     358              :   (void) expiration_time;
     359            2 :   ctx->total++;
     360            2 :   ctx->finished = finished;
     361            2 :   GNUNET_free (ctx->provider);
     362            2 :   ctx->provider = (NULL == provider_name)
     363              :     ? NULL
     364            2 :     : GNUNET_strdup (provider_name);
     365            2 :   remember_name (ctx,
     366              :                  encrypted_attributes_len,
     367              :                  encrypted_attributes);
     368            2 : }
     369              : 
     370              : 
     371              : /**
     372              :  * Create the account, put a legitimization measure on it and start the
     373              :  * two KYC processes the attributes will belong to.
     374              :  *
     375              :  * @param pg the database context
     376              :  */
     377              : static void
     378            1 : setup_account (struct TALER_EXCHANGEDB_PostgresContext *pg)
     379              : {
     380              :   json_t *jmeasures;
     381              :   bool bad_kyc_auth;
     382              : 
     383            1 :   if (0 != measure_row)
     384            0 :     return;
     385            1 :   TDB_FILL (attribute_key,
     386              :             42);
     387            1 :   TDB_account (pg,
     388              :                10,
     389              :                &account);
     390            1 :   jmeasures = GNUNET_JSON_PACK (
     391              :     GNUNET_JSON_pack_array_steal (
     392              :       "measures",
     393              :       json_pack ("[{s:s,s:s,s:s}]",
     394              :                  "check_name",
     395              :                  "verify-id",
     396              :                  "prog_name",
     397              :                  "skip",
     398              :                  "context",
     399              :                  "none")),
     400              :     GNUNET_JSON_pack_bool ("is_and_combinator",
     401              :                            true));
     402            1 :   GNUNET_assert (NULL != jmeasures);
     403            1 :   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     404              :                  TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
     405              :                    pg,
     406              :                    account.payto,
     407              :                    &account.h_normalized,
     408              :                    NULL,
     409              :                    NULL,
     410              :                    jmeasures,
     411              :                    1,
     412              :                    &measure_row,
     413              :                    &bad_kyc_auth));
     414            1 :   json_decref (jmeasures);
     415            1 :   GNUNET_assert (0 != measure_row);
     416            3 :   for (unsigned int i = 0; i < 2; i++)
     417              :   {
     418              :     char *legi_id;
     419              : 
     420            2 :     GNUNET_asprintf (&legi_id,
     421              :                      "legi-%u",
     422              :                      i);
     423            2 :     GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
     424              :                    TALER_EXCHANGEDB_insert_legitimization_process (
     425              :                      pg,
     426              :                      &account.h_normalized,
     427              :                      i,
     428              :                      measure_row,
     429              :                      (0 == i) ? "provider-a" : "provider-b",
     430              :                      "provider-account",
     431              :                      legi_id,
     432              :                      &process_row[i]));
     433            2 :     GNUNET_free (legi_id);
     434            2 :     GNUNET_assert (0 != process_row[i]);
     435              :   }
     436              : }
     437              : 
     438              : 
     439              : /**
     440              :  * Nothing is known while the table is empty.
     441              :  *
     442              :  * @param pg the database context
     443              :  * @return 0 on success
     444              :  */
     445              : static int
     446            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
     447              : {
     448            1 :   struct AttributeContext ctx = { 0 };
     449              :   struct TALER_EXCHANGEDB_HistoryBuilderContext hbc;
     450              :   json_t *j;
     451              : 
     452            1 :   setup_account (pg);
     453            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     454              :           TALER_EXCHANGEDB_iterate_kyc_attributes (pg,
     455              :                                                    &account.h_normalized,
     456              :                                                    &attribute_cb,
     457              :                                                    &ctx));
     458            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     459              :           TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
     460              :             pg,
     461              :             &all_attributes_cb,
     462              :             &ctx));
     463            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     464              :           TALER_EXCHANGEDB_iterate_aml_attributes (pg,
     465              :                                                    &account.h_normalized,
     466              :                                                    0,
     467              :                                                    16,
     468              :                                                    &aml_attribute_cb,
     469              :                                                    &ctx));
     470            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     471              :           TALER_EXCHANGEDB_iterate_kyc_history (pg,
     472              :                                                 &account.h_normalized,
     473              :                                                 &kyc_history_cb,
     474              :                                                 &ctx));
     475            1 :   FAILIF (0 != ctx.total);
     476              : 
     477            1 :   hbc.account = &account.h_normalized;
     478            1 :   hbc.pg = pg;
     479            1 :   hbc.attribute_key = &attribute_key;
     480            1 :   hbc.is_wallet = false;
     481            1 :   j = TALER_EXCHANGEDB_kyc_history_builder (&hbc);
     482            1 :   FAILIF (NULL == j);
     483            1 :   FAILIF_C (0 != json_array_size (j),
     484              :             json_decref (j));
     485            1 :   json_decref (j);
     486              :   /* with no attributes at all, the "current" ones are an empty object */
     487            1 :   j = TALER_EXCHANGEDB_current_attributes_builder (&hbc);
     488            1 :   FAILIF (NULL == j);
     489            1 :   FAILIF_C (! json_is_object (j),
     490              :             json_decref (j));
     491            1 :   FAILIF_C (0 != json_object_size (j),
     492              :             json_decref (j));
     493            1 :   json_decref (j);
     494            1 :   return 0;
     495              : }
     496              : 
     497              : 
     498              : /**
     499              :  * Storing attributes creates the row and finishes the KYC process they
     500              :  * were collected by.
     501              :  *
     502              :  * @param pg the database context
     503              :  * @return 0 on success
     504              :  */
     505              : static int
     506            1 : check_insert (struct TALER_EXCHANGEDB_PostgresContext *pg)
     507              : {
     508              :   void *enc;
     509              :   size_t enc_size;
     510              :   enum GNUNET_DB_QueryStatus qs;
     511              : 
     512            1 :   encrypt_attributes ("Alice",
     513              :                       &enc,
     514              :                       &enc_size);
     515            1 :   qs = TALER_EXCHANGEDB_do_insert_kyc_attributes (
     516              :     pg,
     517              :     process_row[0],
     518              :     &account.h_normalized,
     519              :     "provider-a",
     520              :     "provider-account",
     521              :     "legi-0",
     522              :     0,
     523              :     GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS),
     524              :     "test-form",
     525              :     enc_size,
     526              :     enc);
     527            1 :   GNUNET_free (enc);
     528            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
     529            1 :   FAILIF (1 != TDB_count (pg,
     530              :                           "FROM kyc_attributes"));
     531            1 :   FAILIF (1 != TDB_count (pg,
     532              :                           "FROM kyc_attributes"
     533              :                           " WHERE NOT by_aml_officer"
     534              :                           "   AND form_name='test-form'"));
     535              :   /* new attributes still have to be screened against the sanctions list */
     536            1 :   FAILIF (1 != TDB_count (pg,
     537              :                           "FROM kyc_attributes"
     538              :                           " WHERE NOT screened"));
     539              :   /* the KYC process the attributes came from is now finished */
     540            1 :   FAILIF (1 != TDB_count (pg,
     541              :                           "FROM legitimization_processes"
     542              :                           " WHERE legitimization_process_serial_id=%llu"
     543              :                           "   AND finished",
     544              :                           (unsigned long long) process_row[0]));
     545              :   /* ... and the aggregator was told to have another look */
     546            1 :   FAILIF (0 == TDB_count (pg,
     547              :                           "FROM kyc_alerts"));
     548            1 :   return 0;
     549              : }
     550              : 
     551              : 
     552              : /**
     553              :  * Naming a provider that does not own the KYC process stores the
     554              :  * attributes but leaves the process unfinished.
     555              :  *
     556              :  * @param pg the database context
     557              :  * @return 0 on success
     558              :  */
     559              : static int
     560            1 : check_insert_wrong_provider (struct TALER_EXCHANGEDB_PostgresContext *pg)
     561              : {
     562              :   void *enc;
     563              :   size_t enc_size;
     564              :   enum GNUNET_DB_QueryStatus qs;
     565              : 
     566            1 :   encrypt_attributes ("Bob",
     567              :                       &enc,
     568              :                       &enc_size);
     569            1 :   qs = TALER_EXCHANGEDB_do_insert_kyc_attributes (
     570              :     pg,
     571              :     process_row[1],
     572              :     &account.h_normalized,
     573              :     /* process_row[1] belongs to provider-b */
     574              :     "provider-a",
     575              :     "provider-account",
     576              :     "legi-1",
     577              :     0,
     578              :     GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS),
     579              :     NULL,
     580              :     enc_size,
     581              :     enc);
     582            1 :   GNUNET_free (enc);
     583            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
     584            1 :   FAILIF (2 != TDB_count (pg,
     585              :                           "FROM kyc_attributes"));
     586              :   /* the attributes were stored, but the process was not finished; the
     587              :      stored procedure reports that through out_ok, which the C wrapper
     588              :      drops on the floor (EDBT-16) */
     589            1 :   FAILIF (0 != TDB_count (pg,
     590              :                           "FROM legitimization_processes"
     591              :                           " WHERE legitimization_process_serial_id=%llu"
     592              :                           "   AND finished",
     593              :                           (unsigned long long) process_row[1]));
     594            1 :   FAILIF (1 != TDB_count (pg,
     595              :                           "FROM kyc_attributes"
     596              :                           " WHERE form_name IS NULL"));
     597            1 :   return 0;
     598              : }
     599              : 
     600              : 
     601              : /**
     602              :  * The per-account and the global iterator both find the stored rows.
     603              :  *
     604              :  * @param pg the database context
     605              :  * @return 0 on success
     606              :  */
     607              : static int
     608            1 : check_iterate (struct TALER_EXCHANGEDB_PostgresContext *pg)
     609              : {
     610              :   struct AttributeContext ctx;
     611              :   struct TALER_NormalizedPaytoHashP other;
     612              : 
     613            1 :   memset (&ctx,
     614              :           0,
     615              :           sizeof (ctx));
     616            1 :   FAILIF (0 >=
     617              :           TALER_EXCHANGEDB_iterate_kyc_attributes (pg,
     618              :                                                    &account.h_normalized,
     619              :                                                    &attribute_cb,
     620              :                                                    &ctx));
     621            1 :   FAILIF_C (2 != ctx.total,
     622              :             ac_free (&ctx));
     623            1 :   FAILIF_C (NULL == ctx.name,
     624              :             ac_free (&ctx));
     625            1 :   ac_free (&ctx);
     626              : 
     627              :   /* an account without attributes has none */
     628            1 :   TDB_FILL (other,
     629              :             99);
     630            1 :   memset (&ctx,
     631              :           0,
     632              :           sizeof (ctx));
     633            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     634              :           TALER_EXCHANGEDB_iterate_kyc_attributes (pg,
     635              :                                                    &other,
     636              :                                                    &attribute_cb,
     637              :                                                    &ctx));
     638            1 :   FAILIF_C (0 != ctx.total,
     639              :             ac_free (&ctx));
     640            1 :   ac_free (&ctx);
     641              : 
     642              :   /* the unscreened iterator sees both rows, in ascending row order */
     643            1 :   memset (&ctx,
     644              :           0,
     645              :           sizeof (ctx));
     646            1 :   FAILIF (0 >=
     647              :           TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
     648              :             pg,
     649              :             &all_attributes_cb,
     650              :             &ctx));
     651            1 :   FAILIF_C (2 != ctx.total,
     652              :             ac_free (&ctx));
     653            1 :   FAILIF_C (0 != strcmp (ctx.name,
     654              :                          "Bob"),
     655              :             ac_free (&ctx));
     656              :   {
     657            1 :     uint64_t first = ctx.row_id - 1;
     658              : 
     659            1 :     ac_free (&ctx);
     660              :     /* ... but no longer the first row once that one is screened */
     661            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     662              :             TALER_EXCHANGEDB_update_to_kyc_attributes_screened (
     663              :               pg,
     664              :               &account.h_normalized,
     665              :               first));
     666            1 :     memset (&ctx,
     667              :             0,
     668              :             sizeof (ctx));
     669            1 :     FAILIF (0 >=
     670              :             TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
     671              :               pg,
     672              :               &all_attributes_cb,
     673              :               &ctx));
     674            1 :     FAILIF_C (1 != ctx.total,
     675              :               ac_free (&ctx));
     676            1 :     FAILIF_C (first + 1 != ctx.row_id,
     677              :               ac_free (&ctx));
     678            1 :     ac_free (&ctx);
     679              :     /* marking a row under another account does nothing */
     680            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     681              :             TALER_EXCHANGEDB_update_to_kyc_attributes_screened (
     682              :               pg,
     683              :               &other,
     684              :               first + 1));
     685              :     /* with the second row screened as well, nothing is left */
     686            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     687              :             TALER_EXCHANGEDB_update_to_kyc_attributes_screened (
     688              :               pg,
     689              :               &account.h_normalized,
     690              :               first + 1));
     691            1 :     memset (&ctx,
     692              :             0,
     693              :             sizeof (ctx));
     694            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     695              :             TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
     696              :               pg,
     697              :               &all_attributes_cb,
     698              :               &ctx));
     699            1 :     FAILIF_C (0 != ctx.total,
     700              :               ac_free (&ctx));
     701            1 :     ac_free (&ctx);
     702              :     /* a new sanctions list makes both rows show up again */
     703            1 :     FAILIF (2 !=
     704              :             TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened (pg));
     705            1 :     FAILIF (2 != TDB_count (pg,
     706              :                             "FROM kyc_attributes"
     707              :                             " WHERE NOT screened"));
     708            1 :     FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     709              :             TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened (pg));
     710              :   }
     711              : 
     712              :   /* a callback that says stop is not called again */
     713            1 :   memset (&ctx,
     714              :           0,
     715              :           sizeof (ctx));
     716            1 :   ctx.stop_after = 1;
     717            1 :   FAILIF (0 >=
     718              :           TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
     719              :             pg,
     720              :             &all_attributes_cb,
     721              :             &ctx));
     722            1 :   FAILIF_C (1 != ctx.total,
     723              :             ac_free (&ctx));
     724            1 :   FAILIF_C (0 != strcmp (ctx.name,
     725              :                          "Alice"),
     726              :             ac_free (&ctx));
     727            1 :   ac_free (&ctx);
     728            1 :   return 0;
     729              : }
     730              : 
     731              : 
     732              : /**
     733              :  * The KYC history reports the state of the process each set of
     734              :  * attributes came from.
     735              :  *
     736              :  * @param pg the database context
     737              :  * @return 0 on success
     738              :  */
     739              : static int
     740            1 : check_kyc_history (struct TALER_EXCHANGEDB_PostgresContext *pg)
     741              : {
     742              :   struct AttributeContext ctx;
     743            1 :   struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
     744              :     .account = &account.h_normalized,
     745              :     .pg = pg,
     746              :     .attribute_key = &attribute_key,
     747              :     .is_wallet = false
     748              :   };
     749              :   json_t *j;
     750              : 
     751            1 :   memset (&ctx,
     752              :           0,
     753              :           sizeof (ctx));
     754            1 :   FAILIF (0 >=
     755              :           TALER_EXCHANGEDB_iterate_kyc_history (pg,
     756              :                                                 &account.h_normalized,
     757              :                                                 &kyc_history_cb,
     758              :                                                 &ctx));
     759            1 :   FAILIF_C (2 != ctx.total,
     760              :             ac_free (&ctx));
     761            1 :   ac_free (&ctx);
     762              : 
     763            1 :   j = TALER_EXCHANGEDB_kyc_history_builder (&hbc);
     764            1 :   FAILIF (NULL == j);
     765            1 :   FAILIF_C (2 != json_array_size (j),
     766              :             json_decref (j));
     767              :   {
     768            1 :     json_t *e = json_array_get (j,
     769              :                                 0);
     770            1 :     const json_t *attrs = json_object_get (e,
     771              :                                            "attributes");
     772              : 
     773            1 :     FAILIF_C (NULL == attrs,
     774              :               json_decref (j));
     775            1 :     FAILIF_C (NULL == json_object_get (attrs,
     776              :                                        "NAME"),
     777              :               json_decref (j));
     778              :   }
     779            1 :   json_decref (j);
     780            1 :   return 0;
     781              : }
     782              : 
     783              : 
     784              : /**
     785              :  * Attributes filed by an AML officer are reported as such, together with
     786              :  * the officer's name.
     787              :  *
     788              :  * @param pg the database context
     789              :  * @return 0 on success
     790              :  */
     791              : static int
     792            1 : check_aml_attributes (struct TALER_EXCHANGEDB_PostgresContext *pg)
     793              : {
     794              :   struct TALER_AmlOfficerPublicKeyP officer_pub;
     795              :   struct TALER_AmlOfficerSignatureP officer_sig;
     796              :   struct TALER_MasterSignatureP master_sig;
     797              :   struct GNUNET_TIME_Timestamp previous_change;
     798            1 :   struct TALER_FullPayto null_payto = { NULL };
     799              :   struct GNUNET_HashCode attributes_hash;
     800            1 :   const char *no_events[1] = { NULL };
     801              :   struct AttributeContext ctx;
     802              :   json_t *new_rules;
     803              :   void *enc;
     804              :   size_t enc_size;
     805              :   bool invalid_officer;
     806              :   bool unknown_account;
     807              :   bool is_wallet;
     808              :   uint64_t lms;
     809              :   struct GNUNET_TIME_Timestamp last_date;
     810              :   enum GNUNET_DB_QueryStatus qs;
     811              : 
     812            1 :   TDB_FILL (officer_pub,
     813              :             20);
     814            1 :   TDB_FILL (officer_sig,
     815              :             21);
     816            1 :   TDB_FILL (master_sig,
     817              :             22);
     818            1 :   TDB_FILL (attributes_hash,
     819              :             23);
     820            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     821              :           TALER_EXCHANGEDB_insert_aml_officer (pg,
     822              :                                                &officer_pub,
     823              :                                                &master_sig,
     824              :                                                OFFICER_NAME,
     825              :                                                true,
     826              :                                                false,
     827              :                                                GNUNET_TIME_timestamp_get (),
     828              :                                                &previous_change));
     829            1 :   encrypt_attributes ("Carol",
     830              :                       &enc,
     831              :                       &enc_size);
     832            1 :   new_rules = GNUNET_JSON_PACK (
     833              :     GNUNET_JSON_pack_array_steal ("rules",
     834              :                                   json_array ()));
     835            1 :   GNUNET_assert (NULL != new_rules);
     836            1 :   qs = TALER_EXCHANGEDB_insert_aml_decision (
     837              :     pg,
     838              :     null_payto,
     839              :     &account.h_normalized,
     840              :     GNUNET_TIME_timestamp_get (),
     841              :     GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS),
     842              :     NULL,
     843              :     new_rules,
     844              :     false,
     845              :     NULL,
     846              :     NULL,
     847              :     "collected in person",
     848              :     &officer_pub,
     849              :     &officer_sig,
     850              :     0,
     851              :     no_events,
     852              :     "test-form",
     853              :     enc_size,
     854              :     enc,
     855              :     &attributes_hash,
     856              :     GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_DAYS),
     857              :     &invalid_officer,
     858              :     &unknown_account,
     859              :     &last_date,
     860              :     &lms,
     861              :     &is_wallet);
     862            1 :   json_decref (new_rules);
     863            1 :   GNUNET_free (enc);
     864            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
     865            1 :   FAILIF (invalid_officer);
     866            1 :   FAILIF (3 != TDB_count (pg,
     867              :                           "FROM kyc_attributes"));
     868            1 :   FAILIF (1 != TDB_count (pg,
     869              :                           "FROM kyc_attributes"
     870              :                           " WHERE by_aml_officer"));
     871              : 
     872              :   /* ascending from the start: all three rows, the officer's last */
     873            1 :   memset (&ctx,
     874              :           0,
     875              :           sizeof (ctx));
     876            1 :   FAILIF (0 >=
     877              :           TALER_EXCHANGEDB_iterate_aml_attributes (pg,
     878              :                                                    &account.h_normalized,
     879              :                                                    0,
     880              :                                                    16,
     881              :                                                    &aml_attribute_cb,
     882              :                                                    &ctx));
     883            1 :   FAILIF_C (3 != ctx.total,
     884              :             ac_free (&ctx));
     885            1 :   FAILIF_C (! ctx.by_aml_officer,
     886              :             ac_free (&ctx));
     887            1 :   FAILIF_C (NULL == ctx.officer,
     888              :             ac_free (&ctx));
     889            1 :   FAILIF_C (0 != strcmp (ctx.officer,
     890              :                          OFFICER_NAME),
     891              :             ac_free (&ctx));
     892            1 :   FAILIF_C (0 != strcmp (ctx.name,
     893              :                          "Carol"),
     894              :             ac_free (&ctx));
     895            1 :   ac_free (&ctx);
     896              : 
     897              :   /* descending from the end: only the newest row */
     898            1 :   memset (&ctx,
     899              :           0,
     900              :           sizeof (ctx));
     901            1 :   FAILIF (0 >=
     902              :           TALER_EXCHANGEDB_iterate_aml_attributes (pg,
     903              :                                                    &account.h_normalized,
     904              :                                                    INT64_MAX,
     905              :                                                    -1,
     906              :                                                    &aml_attribute_cb,
     907              :                                                    &ctx));
     908            1 :   FAILIF_C (1 != ctx.total,
     909              :             ac_free (&ctx));
     910            1 :   FAILIF_C (! ctx.by_aml_officer,
     911              :             ac_free (&ctx));
     912            1 :   ac_free (&ctx);
     913              : 
     914              :   /* ascending past the last row: nothing */
     915            1 :   memset (&ctx,
     916              :           0,
     917              :           sizeof (ctx));
     918            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     919              :           TALER_EXCHANGEDB_iterate_aml_attributes (pg,
     920              :                                                    &account.h_normalized,
     921              :                                                    INT64_MAX,
     922              :                                                    16,
     923              :                                                    &aml_attribute_cb,
     924              :                                                    &ctx));
     925            1 :   FAILIF_C (0 != ctx.total,
     926              :             ac_free (&ctx));
     927            1 :   ac_free (&ctx);
     928            1 :   return 0;
     929              : }
     930              : 
     931              : 
     932              : /**
     933              :  * The "current attributes" builder returns the newest set, decrypted.
     934              :  *
     935              :  * @param pg the database context
     936              :  * @return 0 on success
     937              :  */
     938              : static int
     939            1 : check_current_attributes (struct TALER_EXCHANGEDB_PostgresContext *pg)
     940              : {
     941            1 :   struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
     942              :     .account = &account.h_normalized,
     943              :     .pg = pg,
     944              :     .attribute_key = &attribute_key,
     945              :     .is_wallet = false
     946              :   };
     947              :   json_t *j;
     948              :   const char *name;
     949              : 
     950            1 :   j = TALER_EXCHANGEDB_current_attributes_builder (&hbc);
     951            1 :   FAILIF (NULL == j);
     952            1 :   name = json_string_value (json_object_get (j,
     953              :                                              "NAME"));
     954            1 :   FAILIF_C (NULL == name,
     955              :             json_decref (j));
     956            1 :   FAILIF_C (0 != strcmp (name,
     957              :                          "Carol"),
     958              :             json_decref (j));
     959            1 :   json_decref (j);
     960            1 :   return 0;
     961              : }
     962              : 
     963              : 
     964              : /**
     965              :  * The checks to run, in order.
     966              :  */
     967              : static const struct TDB_Test tests[] = {
     968              :   { "kyc-attributes-empty",
     969              :     &check_empty },
     970              :   { "kyc-attributes-insert",
     971              :     &check_insert },
     972              :   { "kyc-attributes-insert-wrong-provider",
     973              :     &check_insert_wrong_provider },
     974              :   { "kyc-attributes-iterate",
     975              :     &check_iterate },
     976              :   { "kyc-attributes-kyc-history",
     977              :     &check_kyc_history },
     978              :   { "kyc-attributes-aml-attributes",
     979              :     &check_aml_attributes },
     980              :   { "kyc-attributes-current-attributes",
     981              :     &check_current_attributes },
     982              :   { NULL, NULL }
     983              : };
     984              : 
     985              : 
     986              : int
     987            1 : main (int argc,
     988              :       char *const *argv)
     989              : {
     990              :   int ret;
     991              : 
     992            1 :   ret = TDB_main (argc,
     993              :                   argv,
     994              :                   "test-kyc-attributes",
     995              :                   "Tests for the exchangedb `kyc_attributes' table",
     996              :                   tests);
     997            1 :   TDB_account_free (&account);
     998            1 :   return ret;
     999              : }
    1000              : 
    1001              : 
    1002              : /* end of test_kyc_attributes.c */
        

Generated by: LCOV version 2.0-1