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

Generated by: LCOV version 2.0-1