merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

test_merchantdb.c (251950B)


      1 /*
      2   This file is part of TALER
      3   (C) 2014-2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser 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 src/backenddb/test_merchantdb.c
     18  * @brief testcase for merchant's postgres db plugin
     19  * @author Marcello Stanisci
     20  * @author Christian Grothoff
     21  * @author Pricilla Huang
     22  */
     23 #include "platform.h"
     24 #include "microhttpd.h"
     25 #include <taler/taler_util.h>
     26 #include <taler/taler_json_lib.h>
     27 #include <taler/taler_signatures.h>
     28 #include "taler/taler_merchant_util.h"
     29 #include "merchantdb_lib.h"
     30 #include "merchant-database/account_kyc_get_status.h"
     31 #include "merchant-database/account_kyc_set_status.h"
     32 #include "merchant-database/delete_contract_terms.h"
     33 #include "merchant-database/delete_instance_private_key.h"
     34 #include "merchant-database/delete_order.h"
     35 #include "merchant-database/delete_pending_webhook.h"
     36 #include "merchant-database/delete_product.h"
     37 #include "merchant-database/delete_template.h"
     38 #include "merchant-database/delete_webhook.h"
     39 #include "merchant-database/inactivate_account.h"
     40 #include "merchant-database/increase_refund.h"
     41 #include "merchant-database/insert_account.h"
     42 #include "merchant-database/insert_contract_terms.h"
     43 #include "merchant-database/insert_deposit.h"
     44 #include "merchant-database/insert_deposit_confirmation.h"
     45 #include "merchant-database/insert_deposit_to_transfer.h"
     46 #include "merchant-database/insert_exchange_signkey.h"
     47 #include "merchant-database/insert_instance.h"
     48 #include "merchant-database/insert_order.h"
     49 #include "merchant-database/insert_order_lock.h"
     50 #include "merchant-database/insert_otp.h"
     51 #include "merchant-database/insert_pending_webhook.h"
     52 #include "merchant-database/insert_product.h"
     53 #include "merchant-database/insert_refund_proof.h"
     54 #include "merchant-database/insert_template.h"
     55 #include "merchant-database/insert_transfer.h"
     56 #include "merchant-database/insert_transfer_details.h"
     57 #include "merchant-database/insert_webhook.h"
     58 #include "merchant-database/lock_product.h"
     59 #include "merchant-database/lookup_account.h"
     60 #include "merchant-database/lookup_contract_terms.h"
     61 #include "merchant-database/lookup_contract_terms3.h"
     62 #include "merchant-database/lookup_deposits.h"
     63 #include "merchant-database/lookup_deposits_by_contract_and_coin.h"
     64 #include "merchant-database/lookup_deposits_by_order.h"
     65 #include "merchant-database/lookup_instances.h"
     66 #include "merchant-database/lookup_order.h"
     67 #include "merchant-database/lookup_order_by_fulfillment.h"
     68 #include "merchant-database/lookup_order_status.h"
     69 #include "merchant-database/lookup_orders.h"
     70 #include "merchant-database/lookup_pending_webhooks.h"
     71 #include "merchant-database/lookup_product.h"
     72 #include "merchant-database/lookup_products.h"
     73 #include "merchant-database/lookup_refund_proof.h"
     74 #include "merchant-database/lookup_refunds.h"
     75 #include "merchant-database/lookup_refunds_detailed.h"
     76 #include "merchant-database/lookup_template.h"
     77 #include "merchant-database/lookup_templates.h"
     78 #include "merchant-database/lookup_transfer_details.h"
     79 #include "merchant-database/lookup_transfer_details_by_order.h"
     80 #include "merchant-database/lookup_transfer_summary.h"
     81 #include "merchant-database/lookup_transfers.h"
     82 #include "merchant-database/lookup_webhook.h"
     83 #include "merchant-database/lookup_webhook_by_event.h"
     84 #include "merchant-database/lookup_webhooks.h"
     85 #include "merchant-database/lookup_wire_fee.h"
     86 #include "merchant-database/mark_contract_paid.h"
     87 #include "merchant-database/mark_order_wired.h"
     88 #include "merchant-database/refund_coin.h"
     89 #include "merchant-database/store_wire_fee_by_exchange.h"
     90 #include "merchant-database/unlock_inventory.h"
     91 #include "merchant-database/update_contract_terms.h"
     92 #include "merchant-database/update_instance.h"
     93 #include "merchant-database/update_pending_webhook.h"
     94 #include "merchant-database/update_product.h"
     95 #include "merchant-database/update_template.h"
     96 #include "merchant-database/update_webhook.h"
     97 #include "merchant-database/create_tables.h"
     98 #include "merchant-database/drop_tables.h"
     99 #include "merchant-database/preflight.h"
    100 #include "merchant-database/purge_instance.h"
    101 
    102 
    103 /**
    104  * Global return value for the test.  Initially -1, set to 0 upon
    105  * completion.  Other values indicate some kind of error.
    106  */
    107 static int result;
    108 
    109 /**
    110  * Handle to the database we are testing.
    111  */
    112 static struct TALER_MERCHANTDB_PostgresContext *pg;
    113 
    114 /**
    115  * @param test 0 on success, non-zero on failure
    116  */
    117 #define TEST_WITH_FAIL_CLAUSE(test, on_fail) \
    118         if ((test)) \
    119         { \
    120           GNUNET_break (0); \
    121           on_fail \
    122         }
    123 
    124 #define TEST_COND_RET_ON_FAIL(cond, msg) \
    125         if (! (cond)) \
    126         { \
    127           GNUNET_break (0); \
    128           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \
    129                       msg); \
    130           return 1; \
    131         }
    132 
    133 /**
    134  * @param __test 0 on success, non-zero on failure
    135  */
    136 #define TEST_RET_ON_FAIL(__test) \
    137         TEST_WITH_FAIL_CLAUSE (__test, \
    138                                return 1; \
    139                                )
    140 
    141 
    142 /* ********** Instances ********** */
    143 
    144 
    145 /**
    146  * Container for instance settings along with keys.
    147  */
    148 struct InstanceData
    149 {
    150   /**
    151    * The instance settings.
    152    */
    153   struct TALER_MERCHANTDB_InstanceSettings instance;
    154 
    155   /**
    156    * The public key for the instance.
    157    */
    158   struct TALER_MerchantPublicKeyP merchant_pub;
    159 
    160   /**
    161    * The private key for the instance.
    162    */
    163   struct TALER_MerchantPrivateKeyP merchant_priv;
    164 };
    165 
    166 
    167 /**
    168  * Creates data for an instance to use with testing.
    169  *
    170  * @param instance_id the identifier for this instance.
    171  * @param instance the instance data to be filled.
    172  */
    173 static void
    174 make_instance (const char *instance_id,
    175                struct InstanceData *instance)
    176 {
    177   memset (instance,
    178           0,
    179           sizeof (*instance));
    180   GNUNET_CRYPTO_eddsa_key_create (&instance->merchant_priv.eddsa_priv);
    181   GNUNET_CRYPTO_eddsa_key_get_public (&instance->merchant_priv.eddsa_priv,
    182                                       &instance->merchant_pub.eddsa_pub);
    183   instance->instance.id = (char *) instance_id;
    184   instance->instance.name = (char *) "Test";
    185   instance->instance.address = json_array ();
    186   GNUNET_assert (NULL != instance->instance.address);
    187   GNUNET_assert (0 == json_array_append_new (instance->instance.address,
    188                                              json_string ("123 Example St")));
    189   instance->instance.jurisdiction = json_array ();
    190   GNUNET_assert (NULL != instance->instance.jurisdiction);
    191   GNUNET_assert (0 == json_array_append_new (instance->instance.jurisdiction,
    192                                              json_string ("Ohio")));
    193   instance->instance.use_stefan = true;
    194   instance->instance.default_wire_transfer_delay =
    195     GNUNET_TIME_relative_get_minute_ ();
    196   instance->instance.default_pay_delay = GNUNET_TIME_UNIT_SECONDS;
    197   instance->instance.default_refund_delay = GNUNET_TIME_UNIT_MINUTES;
    198 }
    199 
    200 
    201 /**
    202  * Frees memory allocated when creating an instance for testing.
    203  *
    204  * @param instance the instance containing the memory to be freed.
    205  */
    206 static void
    207 free_instance_data (struct InstanceData *instance)
    208 {
    209   json_decref (instance->instance.address);
    210   json_decref (instance->instance.jurisdiction);
    211 }
    212 
    213 
    214 /**
    215  * Creates an account with test data for an instance.
    216  *
    217  * @param account the account to initialize.
    218  */
    219 static void
    220 make_account (struct TALER_MERCHANTDB_AccountDetails *account)
    221 {
    222   memset (account,
    223           0,
    224           sizeof (*account));
    225   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG,
    226                                     &account->h_wire.hash);
    227   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
    228                               &account->salt,
    229                               sizeof (account->salt));
    230   account->payto_uri.full_payto
    231     = (char *) "payto://x-taler-bank/bank.demo.taler.net/4";
    232   account->active = true;
    233 }
    234 
    235 
    236 /**
    237  * Instance settings along with corresponding accounts.
    238  */
    239 struct InstanceWithAccounts
    240 {
    241   /**
    242    * Pointer to the instance settings.
    243    */
    244   const struct TALER_MERCHANTDB_InstanceSettings *instance;
    245 
    246   /**
    247    * Length of the array of accounts.
    248    */
    249   unsigned int accounts_length;
    250 
    251   /**
    252    * Pointer to the array of accounts.
    253    */
    254   const struct TALER_MERCHANTDB_AccountDetails *accounts;
    255 
    256 };
    257 
    258 
    259 /**
    260  * Closure for testing instance lookup.
    261  */
    262 struct TestLookupInstances_Closure
    263 {
    264   /**
    265    * Number of instances to compare to.
    266    */
    267   unsigned int instances_to_cmp_length;
    268 
    269   /**
    270    * Pointer to array of instances.
    271    */
    272   const struct InstanceWithAccounts *instances_to_cmp;
    273 
    274   /**
    275    * Pointer to array of number of matches for each instance.
    276    */
    277   unsigned int *results_matching;
    278 
    279   /**
    280    * Total number of results returned.
    281    */
    282   unsigned int results_length;
    283 };
    284 
    285 
    286 /**
    287  * Compares two instances for equality.
    288  *
    289  * @param a the first instance.
    290  * @param b the second instance.
    291  * @return 0 on equality, 1 otherwise.
    292  */
    293 static int
    294 check_instances_equal (const struct TALER_MERCHANTDB_InstanceSettings *a,
    295                        const struct TALER_MERCHANTDB_InstanceSettings *b)
    296 {
    297   if ((0 != strcmp (a->id,
    298                     b->id)) ||
    299       (0 != strcmp (a->name,
    300                     b->name)) ||
    301       (1 != json_equal (a->address,
    302                         b->address)) ||
    303       (1 != json_equal (a->jurisdiction,
    304                         b->jurisdiction)) ||
    305       (a->use_stefan != b->use_stefan) ||
    306       (a->default_wire_transfer_delay.rel_value_us !=
    307        b->default_wire_transfer_delay.rel_value_us) ||
    308       (a->default_pay_delay.rel_value_us != b->default_pay_delay.rel_value_us))
    309     return 1;
    310   return 0;
    311 }
    312 
    313 
    314 #if 0
    315 /**
    316  * Compares two accounts for equality.
    317  *
    318  * @param a the first account.
    319  * @param b the second account.
    320  * @return 0 on equality, 1 otherwise.
    321  */
    322 static int
    323 check_accounts_equal (const struct TALER_MERCHANTDB_AccountDetails *a,
    324                       const struct TALER_MERCHANTDB_AccountDetails *b)
    325 {
    326   if ((0 != GNUNET_memcmp (&a->h_wire,
    327                            &b->h_wire)) ||
    328       (0 != GNUNET_memcmp (&a->salt,
    329                            &b->salt)) ||
    330       (0 != TALER_full_payto_cmp (a->payto_uri,
    331                                   b->payto_uri)) ||
    332       (a->active != b->active))
    333     return 1;
    334   return 0;
    335 }
    336 
    337 
    338 #endif
    339 
    340 
    341 /**
    342  * Called after testing 'lookup_instances'.
    343  *
    344  * @param cls pointer to 'struct TestLookupInstances_Closure'.
    345  * @param merchant_pub public key of the instance
    346  * @param merchant_priv private key of the instance, NULL if not available
    347  * @param is general instance settings
    348  * @param ias instance authentication settings
    349 */
    350 static void
    351 lookup_instances_cb (void *cls,
    352                      const struct TALER_MerchantPublicKeyP *merchant_pub,
    353                      const struct TALER_MerchantPrivateKeyP *merchant_priv,
    354                      const struct TALER_MERCHANTDB_InstanceSettings *is,
    355                      const struct TALER_MERCHANTDB_InstanceAuthSettings *ias)
    356 {
    357   struct TestLookupInstances_Closure *cmp = cls;
    358 
    359   if (NULL == cmp)
    360     return;
    361   cmp->results_length += 1;
    362   /* Look through the closure and test each instance for equality */
    363   for (unsigned int i = 0; cmp->instances_to_cmp_length > i; ++i)
    364   {
    365     if (0 != check_instances_equal (cmp->instances_to_cmp[i].instance,
    366                                     is))
    367       continue;
    368     cmp->results_matching[i] += 1;
    369   }
    370 }
    371 
    372 
    373 /**
    374  * Tests @e insert_instance.
    375  *
    376  * @param instance the instance data to insert.
    377  * @param expected_result the result that should be returned from the DB.
    378  * @return 0 on success, 1 on failure.
    379  */
    380 static int
    381 test_insert_instance (const struct InstanceData *instance,
    382                       enum GNUNET_DB_QueryStatus expected_result)
    383 {
    384   struct TALER_MERCHANTDB_InstanceAuthSettings ias = { 0 };
    385 
    386   TEST_COND_RET_ON_FAIL (expected_result ==
    387                          TALER_MERCHANTDB_insert_instance (pg,
    388                                                            &instance->merchant_pub,
    389                                                            &instance->merchant_priv,
    390                                                            &instance->instance,
    391                                                            &ias,
    392                                                            false),
    393                          "Insert instance failed\n");
    394   return 0;
    395 }
    396 
    397 
    398 /**
    399  * Tests @e update_instance.
    400  *
    401  * @param updated_data the instance data to update the row in the database to.
    402  * @param expected_result the result that should be returned from the DB.
    403  * @return 0 on success, 1 on failure.
    404  */
    405 static int
    406 test_update_instance (const struct InstanceData *updated_data,
    407                       enum GNUNET_DB_QueryStatus expected_result)
    408 {
    409   TEST_COND_RET_ON_FAIL (expected_result ==
    410                          TALER_MERCHANTDB_update_instance (pg,
    411                                                            &updated_data->instance),
    412                          "Update instance failed\n");
    413   return 0;
    414 }
    415 
    416 
    417 /**
    418  * Tests @e lookup_instances.
    419  *
    420  * @param active_only whether to lookup all instance, or only active ones.
    421  * @param instances_length number of instances to compare to in @e instances.
    422  * @param instances a list of instances that will be compared with the results
    423  *        found.
    424  * @return 0 on success, 1 otherwise.
    425  */
    426 static int
    427 test_lookup_instances (bool active_only,
    428                        unsigned int instances_length,
    429                        struct InstanceWithAccounts instances[])
    430 {
    431   unsigned int results_matching[GNUNET_NZL (instances_length)];
    432   struct TestLookupInstances_Closure cmp = {
    433     .instances_to_cmp_length = instances_length,
    434     .instances_to_cmp = instances,
    435     .results_matching = results_matching,
    436     .results_length = 0
    437   };
    438   memset (results_matching, 0, sizeof (unsigned int) * instances_length);
    439   if (0 > TALER_MERCHANTDB_lookup_instances (pg,
    440                                              active_only,
    441                                              &lookup_instances_cb,
    442                                              &cmp))
    443   {
    444     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    445                 "Lookup instances failed\n");
    446     return 1;
    447   }
    448   if (instances_length != cmp.results_length)
    449   {
    450     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    451                 "Lookup instances failed: incorrect number of results\n");
    452     return 1;
    453   }
    454   for (unsigned int i = 0; instances_length > i; ++i)
    455   {
    456     if (1 != cmp.results_matching[i])
    457     {
    458       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    459                   "Lookup instances failed: mismatched data\n");
    460       return 1;
    461     }
    462   }
    463   return 0;
    464 }
    465 
    466 
    467 /**
    468  * Tests removing the private key of the given instance from the database.
    469  *
    470  * @param instance the instance whose private key to delete.
    471  * @param expected_result the result we expect the db to return.
    472  * @return 0 on success, 1 otherwise.
    473  */
    474 static int
    475 test_delete_instance_private_key (const struct InstanceData *instance,
    476                                   enum GNUNET_DB_QueryStatus expected_result)
    477 {
    478   TEST_COND_RET_ON_FAIL (expected_result ==
    479                          TALER_MERCHANTDB_delete_instance_private_key (
    480                            pg,
    481                            instance->instance.id),
    482                          "Delete instance private key failed\n");
    483   return 0;
    484 }
    485 
    486 
    487 /**
    488  * Tests purging all data for an instance from the database.
    489  *
    490  * @param instance the instance to purge.
    491  * @param expected_result the result we expect the db to return.
    492  * @return 0 on success, 1 otherwise.
    493  */
    494 static int
    495 test_purge_instance (const struct InstanceData *instance,
    496                      enum GNUNET_DB_QueryStatus expected_result)
    497 {
    498   TEST_COND_RET_ON_FAIL (expected_result ==
    499                          TALER_MERCHANTDB_purge_instance (pg,
    500                                                           instance->instance.id),
    501                          "Purge instance failed\n");
    502   return 0;
    503 }
    504 
    505 
    506 /**
    507  * Tests inserting an account for a merchant instance.
    508  *
    509  * @param instance the instance to associate the account with.
    510  * @param account the account to insert.
    511  * @param expected_result the result expected from the db.
    512  * @return 0 on success, 1 otherwise.
    513  */
    514 static int
    515 test_insert_account (const struct InstanceData *instance,
    516                      const struct TALER_MERCHANTDB_AccountDetails *account,
    517                      enum GNUNET_DB_QueryStatus expected_result)
    518 {
    519   TEST_COND_RET_ON_FAIL (expected_result ==
    520                          TALER_MERCHANTDB_insert_account (pg,
    521                                                           account),
    522                          "Insert account failed\n");
    523   return 0;
    524 }
    525 
    526 
    527 /**
    528  * Tests deactivating an account.
    529  *
    530  * @param account the account to deactivate.
    531  * @param expected_result the result expected from the DB.
    532  * @return 0 on success, 1 otherwise.
    533  */
    534 static int
    535 test_inactivate_account (const struct InstanceData *instance,
    536                          const struct TALER_MERCHANTDB_AccountDetails *account,
    537                          enum GNUNET_DB_QueryStatus expected_result)
    538 {
    539   TEST_COND_RET_ON_FAIL (expected_result ==
    540                          TALER_MERCHANTDB_inactivate_account (pg,
    541                                                               instance->instance.id,
    542                                                               &account->h_wire),
    543                          "Deactivate account failed\n");
    544   return 0;
    545 }
    546 
    547 
    548 /**
    549  * Closure for instance tests
    550  */
    551 struct TestInstances_Closure
    552 {
    553   /**
    554    * The list of instances that we use for testing instances.
    555    */
    556   struct InstanceData instances[2];
    557 
    558   /**
    559    * The list of accounts to use with the instances.
    560    */
    561   struct TALER_MERCHANTDB_AccountDetails accounts[2];
    562 
    563 };
    564 
    565 
    566 /**
    567  * Sets up the data structures used in the instance tests
    568  *
    569  * @cls the closure to initialize with test data.
    570  */
    571 static void
    572 pre_test_instances (struct TestInstances_Closure *cls)
    573 {
    574   /* Instance */
    575   make_instance ("test_instances_inst0",
    576                  &cls->instances[0]);
    577   make_instance ("test_instances_inst1",
    578                  &cls->instances[1]);
    579 
    580   /* Accounts */
    581   make_account (&cls->accounts[0]);
    582   cls->accounts[0].instance_id
    583     = cls->instances[0].instance.id;
    584   make_account (&cls->accounts[1]);
    585   cls->accounts[1].instance_id
    586     = cls->instances[1].instance.id;
    587 }
    588 
    589 
    590 /**
    591  * Handles all teardown after testing
    592  *
    593  * @cls the closure to free data from
    594  */
    595 static void
    596 post_test_instances (struct TestInstances_Closure *cls)
    597 {
    598   free_instance_data (&cls->instances[0]);
    599   free_instance_data (&cls->instances[1]);
    600 }
    601 
    602 
    603 /**
    604  * Function that tests instances.
    605  *
    606  * @param cls closure with config
    607  * @return 0 on success, 1 if failure.
    608  */
    609 static int
    610 run_test_instances (struct TestInstances_Closure *cls)
    611 {
    612   struct InstanceWithAccounts instances[2] = {
    613     {
    614       .accounts_length = 0,
    615       .accounts = cls->accounts,
    616       .instance = &cls->instances[0].instance
    617     },
    618     {
    619       .accounts_length = 0,
    620       .accounts = cls->accounts,
    621       .instance = &cls->instances[1].instance
    622     }
    623   };
    624   uint64_t account_serial;
    625 
    626   /* Test inserting an instance */
    627   TEST_RET_ON_FAIL (test_insert_instance (&cls->instances[0],
    628                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    629   /* Test double insertion fails */
    630   TEST_RET_ON_FAIL (test_insert_instance (&cls->instances[0],
    631                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    632   /* Test lookup instances- is our new instance there? */
    633   TEST_RET_ON_FAIL (test_lookup_instances (false,
    634                                            1,
    635                                            instances));
    636   /* Test update instance */
    637   cls->instances[0].instance.name = "Test - updated";
    638   json_array_append_new (cls->instances[0].instance.address,
    639                          json_pack ("{s:s, s:I}",
    640                                     "this", "is",
    641                                     "more data", 47));
    642   json_array_append_new (cls->instances[0].instance.jurisdiction,
    643                          json_pack ("{s:s}",
    644                                     "vegetables", "bad"));
    645   cls->instances[0].instance.use_stefan = false;
    646   cls->instances[0].instance.default_wire_transfer_delay =
    647     GNUNET_TIME_UNIT_HOURS;
    648   cls->instances[0].instance.default_pay_delay = GNUNET_TIME_UNIT_MINUTES;
    649 
    650   TEST_RET_ON_FAIL (test_update_instance (&cls->instances[0],
    651                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    652   TEST_RET_ON_FAIL (test_lookup_instances (false,
    653                                            1,
    654                                            instances));
    655   TEST_RET_ON_FAIL (test_update_instance (&cls->instances[1],
    656                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    657   /* Test account creation */
    658   TEST_RET_ON_FAIL (test_insert_account (&cls->instances[0],
    659                                          &cls->accounts[0],
    660                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    661   /* Test double account insertion fails */
    662   TEST_RET_ON_FAIL (test_insert_account (&cls->instances[1],
    663                                          &cls->accounts[1],
    664                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    665   TEST_RET_ON_FAIL (test_insert_account (&cls->instances[0],
    666                                          &cls->accounts[0],
    667                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    668   instances[0].accounts_length = 1;
    669   TEST_RET_ON_FAIL (test_lookup_instances (false,
    670                                            1,
    671                                            instances));
    672   /* Test deactivate account */
    673   TEST_RET_ON_FAIL (test_inactivate_account (&cls->instances[0],
    674                                              &cls->accounts[0],
    675                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    676   TEST_RET_ON_FAIL (test_inactivate_account (&cls->instances[1],
    677                                              &cls->accounts[1],
    678                                              GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    679   cls->accounts[0].active = false;
    680   TEST_RET_ON_FAIL (test_lookup_instances (false,
    681                                            1,
    682                                            instances));
    683   /* Test lookup account */
    684   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    685       TALER_MERCHANTDB_lookup_account (pg,
    686                                        cls->instances[0].instance.id,
    687                                        cls->accounts[0].payto_uri,
    688                                        &account_serial))
    689   {
    690     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    691                 "Lookup account failed\n");
    692     return 1;
    693   }
    694   if (1 != account_serial)
    695   {
    696     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    697                 "Lookup account failed: incorrect serial number found\n");
    698     return 1;
    699   }
    700   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
    701       TALER_MERCHANTDB_lookup_account (pg,
    702                                        cls->instances[0].instance.id,
    703                                        (struct TALER_FullPayto) {
    704     (char *) "payto://other-uri"
    705   },
    706                                        &account_serial))
    707   {
    708     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    709                 "Lookup account failed: account found where there is none\n");
    710     return 1;
    711   }
    712   /* Test instance private key deletion */
    713   TEST_RET_ON_FAIL (test_delete_instance_private_key (&cls->instances[0],
    714                                                       GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    715   TEST_RET_ON_FAIL (test_delete_instance_private_key (&cls->instances[1],
    716                                                       GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    717   TEST_RET_ON_FAIL (test_lookup_instances (true,
    718                                            0,
    719                                            NULL));
    720   TEST_RET_ON_FAIL (test_lookup_instances (false,
    721                                            1,
    722                                            instances));
    723   TEST_RET_ON_FAIL (test_insert_instance (&cls->instances[1],
    724                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    725   TEST_RET_ON_FAIL (test_lookup_instances (false,
    726                                            2,
    727                                            instances));
    728   TEST_RET_ON_FAIL (test_lookup_instances (true,
    729                                            1,
    730                                            &instances[1]));
    731   TEST_RET_ON_FAIL (test_purge_instance (&cls->instances[1],
    732                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
    733   TEST_RET_ON_FAIL (test_purge_instance (&cls->instances[1],
    734                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
    735   /* Test that the instance is gone. */
    736   TEST_RET_ON_FAIL (test_lookup_instances (false,
    737                                            1,
    738                                            instances));
    739   return 0;
    740 }
    741 
    742 
    743 /**
    744  * Function that tests instances.
    745  *
    746  * @return 0 on success, 1 otherwise.
    747  */
    748 static int
    749 test_instances (void)
    750 {
    751   struct TestInstances_Closure test_cls;
    752   int test_result;
    753 
    754   pre_test_instances (&test_cls);
    755   test_result = run_test_instances (&test_cls);
    756   post_test_instances (&test_cls);
    757   return test_result;
    758 }
    759 
    760 
    761 /* *********** Products ********** */
    762 
    763 
    764 /**
    765  * A container for data relevant to a product.
    766  */
    767 struct ProductData
    768 {
    769   /**
    770    * The identifier of the product.
    771    */
    772   const char *id;
    773 
    774   /**
    775    * The details of the product.
    776    */
    777   struct TALER_MERCHANTDB_ProductDetails product;
    778 };
    779 
    780 
    781 /**
    782  * Creates a product for testing with.
    783  *
    784  * @param id the id of the product.
    785  * @param product the product data to fill.
    786  */
    787 static void
    788 make_product (const char *id,
    789               struct ProductData *product)
    790 {
    791   static struct TALER_Amount htwenty40;
    792 
    793   GNUNET_assert (GNUNET_OK ==
    794                  TALER_string_to_amount ("EUR:120.40",
    795                                          &htwenty40));
    796 
    797   memset (product,
    798           0,
    799           sizeof (*product));
    800   product->id = id;
    801   product->product.product_name = "Test product";
    802   product->product.description = "This is a test product";
    803   product->product.description_i18n = json_array ();
    804   GNUNET_assert (NULL != product->product.description_i18n);
    805   product->product.unit = "boxes";
    806   product->product.minimum_age = 0;
    807   product->product.price_array = &htwenty40;
    808   product->product.price_array_length = 1;
    809   product->product.taxes = json_array ();
    810   GNUNET_assert (NULL != product->product.taxes);
    811   product->product.total_stock = 55;
    812   product->product.total_sold = 0;
    813   product->product.total_lost = 0;
    814   product->product.image = GNUNET_strdup ("");
    815   GNUNET_assert (NULL != product->product.image);
    816   product->product.address = json_array ();
    817   GNUNET_assert (NULL != product->product.address);
    818   product->product.next_restock = GNUNET_TIME_UNIT_ZERO_TS;
    819 }
    820 
    821 
    822 /**
    823  * Frees memory associated with @e ProductData.
    824  *
    825  * @param product the container to free.
    826  */
    827 static void
    828 free_product_data (struct ProductData *product)
    829 {
    830   json_decref (product->product.description_i18n);
    831   json_decref (product->product.taxes);
    832   GNUNET_free (product->product.image);
    833   json_decref (product->product.address);
    834 }
    835 
    836 
    837 /**
    838  * Compare two products for equality.
    839  *
    840  * @param a the first product.
    841  * @param b the second product.
    842  * @return 0 on equality, 1 otherwise.
    843  */
    844 static int
    845 check_products_equal (const struct TALER_MERCHANTDB_ProductDetails *a,
    846                       const struct TALER_MERCHANTDB_ProductDetails *b)
    847 {
    848   if ((0 != strcmp (a->description,
    849                     b->description)) ||
    850       (1 != json_equal (a->description_i18n,
    851                         b->description_i18n)) ||
    852       (0 != strcmp (a->unit,
    853                     b->unit)) ||
    854       (a->price_array_length != b->price_array_length) ||
    855       (1 != json_equal (a->taxes,
    856                         b->taxes)) ||
    857       (a->total_stock != b->total_stock) ||
    858       (a->total_sold != b->total_sold) ||
    859       (a->total_lost != b->total_lost) ||
    860       (0 != strcmp (a->image,
    861                     b->image)) ||
    862       (1 != json_equal (a->address,
    863                         b->address)) ||
    864       (GNUNET_TIME_timestamp_cmp (a->next_restock,
    865                                   !=,
    866                                   b->next_restock)))
    867 
    868     return 1;
    869   for (size_t i = 0; i<a->price_array_length; i++)
    870     if ( (GNUNET_OK !=
    871           TALER_amount_cmp_currency (&a->price_array[i],
    872                                      &b->price_array[i])) ||
    873          (0 != TALER_amount_cmp (&a->price_array[i],
    874                                  &b->price_array[i])) )
    875       return 1;
    876   return 0;
    877 }
    878 
    879 
    880 /**
    881  * Tests inserting product data into the database.
    882  *
    883  * @param instance the instance to insert the product for.
    884  * @param product the product data to insert.
    885  * @param num_cats length of the @a cats array
    886  * @param cats array of categories for the product
    887  * @param expected_result the result we expect the db to return.
    888  * @param expect_conflict expected conflict status
    889  * @param expect_no_instance expected instance missing status
    890  * @param expected_no_cat expected category missing index
    891  * @return 0 when successful, 1 otherwise.
    892  */
    893 static int
    894 test_insert_product (const struct InstanceData *instance,
    895                      const struct ProductData *product,
    896                      unsigned int num_cats,
    897                      const uint64_t *cats,
    898                      enum GNUNET_DB_QueryStatus expected_result,
    899                      bool expect_conflict,
    900                      bool expect_no_instance,
    901                      ssize_t expected_no_cat)
    902 {
    903   bool conflict;
    904   bool no_instance;
    905   ssize_t no_cat;
    906   bool no_group;
    907   bool no_pot;
    908 
    909   TEST_COND_RET_ON_FAIL (expected_result ==
    910                          TALER_MERCHANTDB_insert_product (pg,
    911                                                           instance->instance.id,
    912                                                           product->id,
    913                                                           &product->product,
    914                                                           num_cats,
    915                                                           cats,
    916                                                           &no_instance,
    917                                                           &conflict,
    918                                                           &no_cat,
    919                                                           &no_group,
    920                                                           &no_pot),
    921                          "Insert product failed\n");
    922   if (expected_result > 0)
    923   {
    924     TEST_COND_RET_ON_FAIL (no_instance == expect_no_instance,
    925                            "No instance wrong");
    926     TEST_COND_RET_ON_FAIL (conflict == expect_conflict,
    927                            "Conflict wrong");
    928     TEST_COND_RET_ON_FAIL (no_cat == expected_no_cat,
    929                            "Wrong category missing returned");
    930   }
    931   return 0;
    932 }
    933 
    934 
    935 /**
    936  * Tests updating product data in the database.
    937  *
    938  * @param instance the instance to update the product for.
    939  * @param product the product data to update.
    940  * @param expected_result the result we expect the db to return.
    941  * @return 0 when successful, 1 otherwise.
    942  */
    943 static int
    944 test_update_product (const struct InstanceData *instance,
    945                      const struct ProductData *product,
    946                      unsigned int num_cats,
    947                      const uint64_t *cats,
    948                      enum GNUNET_DB_QueryStatus expected_result,
    949                      bool expect_no_instance,
    950                      bool expect_no_product,
    951                      bool expect_lost_reduced,
    952                      bool expect_sold_reduced,
    953                      bool expect_stocked_reduced,
    954                      ssize_t expected_no_cat)
    955 
    956 {
    957   bool no_instance;
    958   ssize_t no_cat;
    959   bool no_product;
    960   bool lost_reduced;
    961   bool sold_reduced;
    962   bool stocked_reduced;
    963   bool no_group;
    964   bool no_pot;
    965 
    966   TEST_COND_RET_ON_FAIL (
    967     expected_result ==
    968     TALER_MERCHANTDB_update_product (pg,
    969                                      instance->instance.id,
    970                                      product->id,
    971                                      &product->product,
    972                                      num_cats,
    973                                      cats,
    974                                      &no_instance,
    975                                      &no_cat,
    976                                      &no_product,
    977                                      &lost_reduced,
    978                                      &sold_reduced,
    979                                      &stocked_reduced,
    980                                      &no_group,
    981                                      &no_pot),
    982     "Update product failed\n");
    983   if (expected_result > 0)
    984   {
    985     TEST_COND_RET_ON_FAIL (no_instance == expect_no_instance,
    986                            "No instance wrong");
    987     TEST_COND_RET_ON_FAIL (no_product == expect_no_product,
    988                            "No product wrong");
    989     TEST_COND_RET_ON_FAIL (lost_reduced == expect_lost_reduced,
    990                            "No product wrong");
    991     TEST_COND_RET_ON_FAIL (stocked_reduced == expect_stocked_reduced,
    992                            "Stocked reduced wrong");
    993     TEST_COND_RET_ON_FAIL (sold_reduced == expect_sold_reduced,
    994                            "Sold reduced wrong");
    995     TEST_COND_RET_ON_FAIL (no_cat == expected_no_cat,
    996                            "Wrong category missing returned");
    997   }
    998   return 0;
    999 }
   1000 
   1001 
   1002 /**
   1003  * Tests looking up a product from the db.
   1004  *
   1005  * @param instance the instance to query from.
   1006  * @param product the product to query and compare to.
   1007  * @return 0 when successful, 1 otherwise.
   1008  */
   1009 static int
   1010 test_lookup_product (const struct InstanceData *instance,
   1011                      const struct ProductData *product)
   1012 {
   1013   struct TALER_MERCHANTDB_ProductDetails lookup_result;
   1014   size_t num_categories = 0;
   1015   uint64_t *categories = NULL;
   1016 
   1017   if (0 > TALER_MERCHANTDB_lookup_product (pg,
   1018                                            instance->instance.id,
   1019                                            product->id,
   1020                                            &lookup_result,
   1021                                            &num_categories,
   1022                                            &categories))
   1023   {
   1024     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1025                 "Lookup product failed\n");
   1026     TALER_MERCHANTDB_product_details_free (&lookup_result);
   1027     return 1;
   1028   }
   1029   GNUNET_free (categories);
   1030   {
   1031     const struct TALER_MERCHANTDB_ProductDetails *to_cmp = &product->product;
   1032 
   1033     if (0 != check_products_equal (&lookup_result,
   1034                                    to_cmp))
   1035     {
   1036       GNUNET_break (0);
   1037       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1038                   "Lookup product failed: incorrect product returned\n");
   1039       TALER_MERCHANTDB_product_details_free (&lookup_result);
   1040       return 1;
   1041     }
   1042   }
   1043   TALER_MERCHANTDB_product_details_free (&lookup_result);
   1044   return 0;
   1045 }
   1046 
   1047 
   1048 /**
   1049  * Closure for testing product lookup
   1050  */
   1051 struct TestLookupProducts_Closure
   1052 {
   1053   /**
   1054    * Number of product ids to compare to
   1055    */
   1056   unsigned int products_to_cmp_length;
   1057 
   1058   /**
   1059    * Pointer to array of product ids
   1060    */
   1061   const struct ProductData *products_to_cmp;
   1062 
   1063   /**
   1064    * Pointer to array of number of matches for each product
   1065    */
   1066   unsigned int *results_matching;
   1067 
   1068   /**
   1069    * Total number of results returned
   1070    */
   1071   unsigned int results_length;
   1072 };
   1073 
   1074 
   1075 /**
   1076  * Function called after calling @e test_lookup_products
   1077  *
   1078  * @param cls a pointer to the lookup closure.
   1079  * @param product_serial DB row ID
   1080  * @param product_id the identifier of the product found.
   1081  */
   1082 static void
   1083 lookup_products_cb (void *cls,
   1084                     uint64_t product_serial,
   1085                     const char *product_id)
   1086 {
   1087   struct TestLookupProducts_Closure *cmp = cls;
   1088 
   1089   GNUNET_assert (product_serial > 0);
   1090   if (NULL == cmp)
   1091     return;
   1092   cmp->results_length += 1;
   1093   for (unsigned int i = 0; cmp->products_to_cmp_length > i; ++i)
   1094   {
   1095     if (0 == strcmp (cmp->products_to_cmp[i].id,
   1096                      product_id))
   1097       cmp->results_matching[i] += 1;
   1098   }
   1099 }
   1100 
   1101 
   1102 /**
   1103  * Tests looking up all products for an instance.
   1104  *
   1105  * @param instance the instance to query from.
   1106  * @param products_length the number of products we are expecting.
   1107  * @param products the list of products that we expect to be found.
   1108  * @return 0 when successful, 1 otherwise.
   1109  */
   1110 static int
   1111 test_lookup_products (const struct InstanceData *instance,
   1112                       unsigned int products_length,
   1113                       const struct ProductData *products)
   1114 {
   1115   unsigned int results_matching[GNUNET_NZL (products_length)];
   1116   struct TestLookupProducts_Closure cls = {
   1117     .products_to_cmp_length = products_length,
   1118     .products_to_cmp = products,
   1119     .results_matching = results_matching,
   1120     .results_length = 0
   1121   };
   1122   memset (results_matching, 0, sizeof (unsigned int) * products_length);
   1123   if (0 > TALER_MERCHANTDB_lookup_products (pg,
   1124                                             instance->instance.id,
   1125                                             0,
   1126                                             20,
   1127                                             NULL,
   1128                                             NULL,
   1129                                             NULL,
   1130                                             0,
   1131                                             &lookup_products_cb,
   1132                                             &cls))
   1133   {
   1134     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1135                 "Lookup products failed\n");
   1136     return 1;
   1137   }
   1138   if (products_length != cls.results_length)
   1139   {
   1140     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1141                 "Lookup products failed: incorrect number of results\n");
   1142     return 1;
   1143   }
   1144   for (unsigned int i = 0; products_length > i; ++i)
   1145   {
   1146     if (1 != cls.results_matching[i])
   1147     {
   1148       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1149                   "Lookup products failed: mismatched data\n");
   1150       return 1;
   1151     }
   1152   }
   1153   return 0;
   1154 }
   1155 
   1156 
   1157 /**
   1158  * Tests deleting a product.
   1159  *
   1160  * @param instance the instance to delete the product from.
   1161  * @param product the product that should be deleted.
   1162  * @param expected_result the result that we expect the DB to return.
   1163  * @return 0 when successful, 1 otherwise.
   1164  */
   1165 static int
   1166 test_delete_product (const struct InstanceData *instance,
   1167                      const struct ProductData *product,
   1168                      enum GNUNET_DB_QueryStatus expected_result)
   1169 {
   1170   TEST_COND_RET_ON_FAIL (expected_result ==
   1171                          TALER_MERCHANTDB_delete_product (pg,
   1172                                                           instance->instance.id,
   1173                                                           product->id),
   1174                          "Delete product failed\n");
   1175   return 0;
   1176 }
   1177 
   1178 
   1179 /**
   1180  * Closure for product tests.
   1181  */
   1182 struct TestProducts_Closure
   1183 {
   1184   /**
   1185    * The instance to use for this test.
   1186    */
   1187   struct InstanceData instance;
   1188 
   1189   /**
   1190    * The array of products.
   1191    */
   1192   struct ProductData products[2];
   1193 };
   1194 
   1195 
   1196 /**
   1197  * Sets up the data structures used in the product tests.
   1198  *
   1199  * @param cls the closure to fill with test data.
   1200  */
   1201 static void
   1202 pre_test_products (struct TestProducts_Closure *cls)
   1203 {
   1204   static struct TALER_Amount four95;
   1205 
   1206   /* Instance */
   1207   make_instance ("test_inst_products",
   1208                  &cls->instance);
   1209 
   1210   /* Products */
   1211   make_product ("test_products_pd_0",
   1212                 &cls->products[0]);
   1213 
   1214   make_product ("test_products_pd_1",
   1215                 &cls->products[1]);
   1216   cls->products[1].product.description = "This is a another test product";
   1217   cls->products[1].product.unit = "cans";
   1218   cls->products[1].product.minimum_age = 0;
   1219 
   1220   GNUNET_assert (GNUNET_OK ==
   1221                  TALER_string_to_amount ("EUR:4.95",
   1222                                          &four95));
   1223   cls->products[1].product.price_array = &four95;
   1224   cls->products[1].product.price_array_length = 1;
   1225   cls->products[1].product.total_stock = 5001;
   1226 }
   1227 
   1228 
   1229 /**
   1230  * Handles all teardown after testing.
   1231  *
   1232  * @param cls the closure containing memory to be freed.
   1233  */
   1234 static void
   1235 post_test_products (struct TestProducts_Closure *cls)
   1236 {
   1237   free_instance_data (&cls->instance);
   1238   free_product_data (&cls->products[0]);
   1239   free_product_data (&cls->products[1]);
   1240 }
   1241 
   1242 
   1243 /**
   1244  * Runs the tests for products.
   1245  *
   1246  * @param cls the container of the test data.
   1247  * @return 0 on success, 1 otherwise.
   1248  */
   1249 static int
   1250 run_test_products (struct TestProducts_Closure *cls)
   1251 {
   1252   struct GNUNET_Uuid uuid;
   1253   struct GNUNET_TIME_Timestamp refund_deadline =
   1254     GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_WEEKS);
   1255 
   1256   /* Test that insert without an instance fails */
   1257   TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   1258                                          &cls->products[0],
   1259                                          0,
   1260                                          NULL,
   1261                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1262                                          false,
   1263                                          true,
   1264                                          -1));
   1265   /* Insert the instance */
   1266   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   1267                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   1268   /* Test inserting a product */
   1269   TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   1270                                          &cls->products[0],
   1271                                          0,
   1272                                          NULL,
   1273                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1274                                          false,
   1275                                          false,
   1276                                          -1));
   1277   /* Test that double insert succeeds */
   1278   TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   1279                                          &cls->products[0],
   1280                                          0,
   1281                                          NULL,
   1282                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1283                                          false,
   1284                                          false,
   1285                                          -1));
   1286   /* Test that conflicting insert fails */
   1287   {
   1288     uint64_t cat = 42;
   1289 
   1290     TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   1291                                            &cls->products[0],
   1292                                            1,
   1293                                            &cat,
   1294                                            GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1295                                            true,
   1296                                            false,
   1297                                            -1));
   1298   }
   1299   /* Test lookup of individual products */
   1300   TEST_RET_ON_FAIL (test_lookup_product (&cls->instance,
   1301                                          &cls->products[0]));
   1302   /* Make sure it fails correctly for products that don't exist */
   1303   {
   1304     size_t num_categories = 0;
   1305     uint64_t *categories = NULL;
   1306 
   1307     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   1308         TALER_MERCHANTDB_lookup_product (pg,
   1309                                          cls->instance.instance.id,
   1310                                          "nonexistent_product",
   1311                                          NULL,
   1312                                          &num_categories,
   1313                                          &categories))
   1314     {
   1315       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1316                   "Lookup product failed\n");
   1317       return 1;
   1318     }
   1319     GNUNET_free (categories);
   1320   }
   1321   /* Test product update */
   1322   cls->products[0].product.description =
   1323     "This is a test product that has been updated!";
   1324   GNUNET_assert (0 ==
   1325                  json_array_append_new (
   1326                    cls->products[0].product.description_i18n,
   1327                    json_string (
   1328                      "description in another language")));
   1329   cls->products[0].product.unit = "barrels";
   1330   {
   1331     static struct TALER_Amount seven68;
   1332 
   1333     GNUNET_assert (GNUNET_OK ==
   1334                    TALER_string_to_amount ("EUR:7.68",
   1335                                            &seven68));
   1336     cls->products[0].product.price_array = &seven68;
   1337     cls->products[0].product.price_array_length = 1;
   1338   }
   1339   GNUNET_assert (0 ==
   1340                  json_array_append_new (cls->products[0].product.taxes,
   1341                                         json_string ("2% sales tax")));
   1342   cls->products[0].product.total_stock = 100;
   1343   cls->products[0].product.total_sold = 0; /* will be ignored! */
   1344   cls->products[0].product.total_lost = 7;
   1345   GNUNET_free (cls->products[0].product.image);
   1346   cls->products[0].product.image = GNUNET_strdup ("image");
   1347   GNUNET_assert (0 ==
   1348                  json_array_append_new (cls->products[0].product.address,
   1349                                         json_string ("444 Some Street")));
   1350   cls->products[0].product.next_restock = GNUNET_TIME_timestamp_get ();
   1351   TEST_RET_ON_FAIL (test_update_product (
   1352                       &cls->instance,
   1353                       &cls->products[0],
   1354                       0,
   1355                       NULL,
   1356                       GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1357                       false,
   1358                       false,
   1359                       false,
   1360                       false,
   1361                       false,
   1362                       -1));
   1363 
   1364   {
   1365     struct ProductData stock_dec = cls->products[0];
   1366 
   1367     stock_dec.product.total_stock = 40;
   1368     TEST_RET_ON_FAIL (test_update_product (
   1369                         &cls->instance,
   1370                         &stock_dec,
   1371                         0,
   1372                         NULL,
   1373                         GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1374                         false,
   1375                         false,
   1376                         false,
   1377                         false,
   1378                         true,
   1379                         -1));
   1380   }
   1381   {
   1382     struct ProductData lost_dec = cls->products[0];
   1383 
   1384     lost_dec.product.total_lost = 1;
   1385     TEST_RET_ON_FAIL (test_update_product (
   1386                         &cls->instance,
   1387                         &lost_dec,
   1388                         0,
   1389                         NULL,
   1390                         GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1391                         false,
   1392                         false,
   1393                         true,
   1394                         false,
   1395                         false,
   1396                         -1));
   1397   }
   1398   TEST_RET_ON_FAIL (test_lookup_product (&cls->instance,
   1399                                          &cls->products[0]));
   1400   TEST_RET_ON_FAIL (test_update_product (
   1401                       &cls->instance,
   1402                       &cls->products[1],
   1403                       0,
   1404                       NULL,
   1405                       GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1406                       false,
   1407                       true,
   1408                       false,
   1409                       false,
   1410                       false,
   1411                       -1));
   1412   /* Test collective product lookup */
   1413   TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   1414                                          &cls->products[1],
   1415                                          0,
   1416                                          NULL,
   1417                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   1418                                          false,
   1419                                          false,
   1420                                          -1));
   1421   TEST_RET_ON_FAIL (test_lookup_products (&cls->instance,
   1422                                           2,
   1423                                           cls->products));
   1424   /* Test locking */
   1425   uuid.value[0] = 0x1287346a;
   1426   if (0 != TALER_MERCHANTDB_lock_product (pg,
   1427                                           cls->instance.instance.id,
   1428                                           cls->products[0].id,
   1429                                           &uuid,
   1430                                           256,
   1431                                           0,
   1432                                           refund_deadline))
   1433   {
   1434     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1435                 "Lock product failed\n");
   1436     return 1;
   1437   }
   1438   if (1 != TALER_MERCHANTDB_lock_product (pg,
   1439                                           cls->instance.instance.id,
   1440                                           cls->products[0].id,
   1441                                           &uuid,
   1442                                           1,
   1443                                           0,
   1444                                           refund_deadline))
   1445   {
   1446     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1447                 "Lock product failed\n");
   1448     return 1;
   1449   }
   1450   /* Test product deletion */
   1451   TEST_RET_ON_FAIL (test_delete_product (&cls->instance,
   1452                                          &cls->products[1],
   1453                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   1454   /* Test double deletion fails */
   1455   TEST_RET_ON_FAIL (test_delete_product (&cls->instance,
   1456                                          &cls->products[1],
   1457                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   1458   TEST_RET_ON_FAIL (test_lookup_products (&cls->instance,
   1459                                           1,
   1460                                           cls->products));
   1461   /* Test unlocking */
   1462   if (1 != TALER_MERCHANTDB_unlock_inventory (pg,
   1463                                               &uuid))
   1464   {
   1465     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1466                 "Unlock inventory failed\n");
   1467     return 1;
   1468   }
   1469   if (0 != TALER_MERCHANTDB_unlock_inventory (pg,
   1470                                               &uuid))
   1471   {
   1472     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1473                 "Unlock inventory failed\n");
   1474     return 1;
   1475   }
   1476   TEST_RET_ON_FAIL (test_delete_product (&cls->instance,
   1477                                          &cls->products[0],
   1478                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   1479   TEST_RET_ON_FAIL (test_lookup_products (&cls->instance,
   1480                                           0,
   1481                                           NULL));
   1482   return 0;
   1483 }
   1484 
   1485 
   1486 /**
   1487  * Takes care of product testing.
   1488  *
   1489  * @return 0 on success, 1 otherwise.
   1490  */
   1491 static int
   1492 test_products (void)
   1493 {
   1494   struct TestProducts_Closure test_cls;
   1495   int test_result;
   1496 
   1497   pre_test_products (&test_cls);
   1498   test_result = run_test_products (&test_cls);
   1499   post_test_products (&test_cls);
   1500   return test_result;
   1501 }
   1502 
   1503 
   1504 /* ********** Orders ********** */
   1505 
   1506 
   1507 /**
   1508  * Container for order data
   1509  */
   1510 struct OrderData
   1511 {
   1512   /**
   1513    * The id of the order
   1514    */
   1515   const char *id;
   1516 
   1517   /**
   1518    * The pay deadline for the order
   1519    */
   1520   struct GNUNET_TIME_Timestamp pay_deadline;
   1521 
   1522   /**
   1523    * The contract of the order
   1524    */
   1525   json_t *contract;
   1526 
   1527   /**
   1528    * The claim token for the order.
   1529    */
   1530   struct TALER_ClaimTokenP claim_token;
   1531 };
   1532 
   1533 
   1534 /**
   1535  * Builds an order for testing.
   1536  *
   1537  * @param order_id the identifier to use for the order.
   1538  * @param order the container to fill with data.
   1539  */
   1540 static void
   1541 make_order (const char *order_id,
   1542             struct OrderData *order)
   1543 {
   1544   struct GNUNET_TIME_Timestamp refund_deadline;
   1545 
   1546   order->id = order_id;
   1547   order->contract = json_object ();
   1548   GNUNET_assert (NULL != order->contract);
   1549   order->pay_deadline = GNUNET_TIME_relative_to_timestamp (
   1550     GNUNET_TIME_UNIT_DAYS);
   1551   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
   1552                               &order->claim_token,
   1553                               sizeof (order->claim_token));
   1554   refund_deadline = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_WEEKS);
   1555   GNUNET_assert (0 ==
   1556                  json_object_set_new (order->contract,
   1557                                       "fulfillment_url",
   1558                                       json_string ("a")));
   1559   GNUNET_assert (0 ==
   1560                  json_object_set_new (order->contract,
   1561                                       "summary",
   1562                                       json_string ("Test order")));
   1563   GNUNET_assert (0 ==
   1564                  json_object_set_new (order->contract,
   1565                                       "order_id",
   1566                                       json_string (order_id)));
   1567   GNUNET_assert (0 ==
   1568                  json_object_set_new (
   1569                    order->contract,
   1570                    "pay_deadline",
   1571                    GNUNET_JSON_from_timestamp (order->pay_deadline))
   1572                  );
   1573   GNUNET_assert (0 ==
   1574                  json_object_set_new (order->contract,
   1575                                       "refund_deadline",
   1576                                       GNUNET_JSON_from_timestamp (
   1577                                         refund_deadline)));
   1578 }
   1579 
   1580 
   1581 /**
   1582  * Frees memory associated with an order.
   1583  *
   1584  * @param the order to free.
   1585  */
   1586 static void
   1587 free_order_data (struct OrderData *order)
   1588 {
   1589   json_decref (order->contract);
   1590 }
   1591 
   1592 
   1593 /**
   1594  * Tests inserting an order into the database.
   1595  *
   1596  * @param instance the instance to insert the order for.
   1597  * @param order the order to insert.
   1598  * @param expected_result the value we expect the db to return.
   1599  * @return 0 on success, 1 otherwise.
   1600  */
   1601 static int
   1602 test_insert_order (const struct InstanceData *instance,
   1603                    const struct OrderData *order,
   1604                    enum GNUNET_DB_QueryStatus expected_result)
   1605 {
   1606   struct TALER_MerchantPostDataHashP h_post;
   1607 
   1608   memset (&h_post,
   1609           42,
   1610           sizeof (h_post));
   1611   TEST_COND_RET_ON_FAIL (expected_result ==
   1612                          TALER_MERCHANTDB_insert_order (pg,
   1613                                                         instance->instance.id,
   1614                                                         order->id,
   1615                                                         NULL, /* session_id */
   1616                                                         &h_post,
   1617                                                         order->pay_deadline,
   1618                                                         &order->claim_token,
   1619                                                         order->contract,
   1620                                                         NULL,
   1621                                                         0),
   1622                          "Insert order failed\n");
   1623   return 0;
   1624 }
   1625 
   1626 
   1627 /**
   1628  * Tests looking up an order in the database.
   1629  *
   1630  * @param instance the instance to lookup from.
   1631  * @param order the order that should be looked up.
   1632  * @return 0 on success, 1 otherwise.
   1633  */
   1634 static int
   1635 test_lookup_order (const struct InstanceData *instance,
   1636                    const struct OrderData *order)
   1637 {
   1638   struct TALER_ClaimTokenP ct;
   1639   json_t *lookup_terms = NULL;
   1640   struct TALER_MerchantPostDataHashP oh;
   1641   struct TALER_MerchantPostDataHashP wh;
   1642 
   1643   memset (&wh,
   1644           42,
   1645           sizeof (wh));
   1646   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1647       TALER_MERCHANTDB_lookup_order (pg,
   1648                                      instance->instance.id,
   1649                                      order->id,
   1650                                      &ct,
   1651                                      &oh,
   1652                                      &lookup_terms))
   1653   {
   1654     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1655                 "Lookup order failed\n");
   1656     if (NULL != lookup_terms)
   1657       json_decref (lookup_terms);
   1658     return 1;
   1659   }
   1660   if ( (1 != json_equal (order->contract,
   1661                          lookup_terms)) ||
   1662        (0 != GNUNET_memcmp (&order->claim_token,
   1663                             &ct)) ||
   1664        (0 != GNUNET_memcmp (&oh,
   1665                             &wh)) )
   1666   {
   1667     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1668                 "Lookup order failed: incorrect order returned\n");
   1669     if (NULL != lookup_terms)
   1670       json_decref (lookup_terms);
   1671     return 1;
   1672   }
   1673   json_decref (lookup_terms);
   1674   return 0;
   1675 }
   1676 
   1677 
   1678 /**
   1679  * Closure for testing order lookup
   1680  */
   1681 struct TestLookupOrders_Closure
   1682 {
   1683   /**
   1684    * Number of orders to compare to
   1685    */
   1686   unsigned int orders_to_cmp_length;
   1687 
   1688   /**
   1689    * Pointer to (ordered) array of order ids
   1690    */
   1691   const struct OrderData *orders_to_cmp;
   1692 
   1693   /**
   1694    * Pointer to array of bools indicating matches in the correct index
   1695    */
   1696   bool *results_match;
   1697 
   1698   /**
   1699    * Total number of results returned
   1700    */
   1701   unsigned int results_length;
   1702 };
   1703 
   1704 
   1705 /**
   1706  * Called after @e test_lookup_orders.
   1707  *
   1708  * @param cls the lookup closure.
   1709  * @param order_id the identifier of the order found.
   1710  * @param order_serial the row number of the order found.
   1711  * @param timestamp when the order was added to the database.
   1712  */
   1713 static void
   1714 lookup_orders_cb (void *cls,
   1715                   const char *order_id,
   1716                   uint64_t order_serial,
   1717                   struct GNUNET_TIME_Timestamp timestamp)
   1718 {
   1719   struct TestLookupOrders_Closure *cmp = cls;
   1720   unsigned int i;
   1721 
   1722   if (NULL == cmp)
   1723     return;
   1724   i = cmp->results_length;
   1725   cmp->results_length += 1;
   1726   if (cmp->orders_to_cmp_length > i)
   1727   {
   1728     /* Compare the orders */
   1729     if (0 == strcmp (cmp->orders_to_cmp[i].id,
   1730                      order_id))
   1731       cmp->results_match[i] = true;
   1732     else
   1733       cmp->results_match[i] = false;
   1734   }
   1735 }
   1736 
   1737 
   1738 /**
   1739  * Tests looking up orders for an instance.
   1740  *
   1741  * @param instance the instance.
   1742  * @param filter the filters applied on the lookup.
   1743  * @param orders_length the number of orders we expect to find.
   1744  * @param orders the orders we expect to find.
   1745  * @return 0 on success, 1 otherwise.
   1746  */
   1747 static int
   1748 test_lookup_orders (const struct InstanceData *instance,
   1749                     const struct TALER_MERCHANTDB_OrderFilter *filter,
   1750                     unsigned int orders_length,
   1751                     const struct OrderData *orders)
   1752 {
   1753   bool results_match[GNUNET_NZL (orders_length)];
   1754   struct TestLookupOrders_Closure cls = {
   1755     .orders_to_cmp_length = orders_length,
   1756     .orders_to_cmp = orders,
   1757     .results_match = results_match,
   1758     .results_length = 0
   1759   };
   1760   memset (results_match,
   1761           0,
   1762           sizeof (bool) * orders_length);
   1763   if (0 > TALER_MERCHANTDB_lookup_orders (pg,
   1764                                           instance->instance.id,
   1765                                           filter,
   1766                                           &lookup_orders_cb,
   1767                                           &cls))
   1768   {
   1769     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1770                 "Lookup orders failed\n");
   1771     return 1;
   1772   }
   1773   if (orders_length != cls.results_length)
   1774   {
   1775     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1776                 "Lookup orders failed: incorrect number of results (%d)\n",
   1777                 cls.results_length);
   1778     return 1;
   1779   }
   1780   for (unsigned int i = 0; orders_length > i; ++i)
   1781   {
   1782     if (false == cls.results_match[i])
   1783     {
   1784       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1785                   "Lookup orders failed: mismatched data (index %d)\n",
   1786                   i);
   1787       return 1;
   1788     }
   1789   }
   1790   return 0;
   1791 }
   1792 
   1793 
   1794 /**
   1795  * Container for data used for looking up the row number of an order.
   1796  */
   1797 struct LookupOrderSerial_Closure
   1798 {
   1799   /**
   1800    * The order that is being looked up.
   1801    */
   1802   const struct OrderData *order;
   1803 
   1804   /**
   1805    * The serial of the order that was found.
   1806    */
   1807   uint64_t serial;
   1808 };
   1809 
   1810 
   1811 /**
   1812  * Called after @e test_lookup_orders.
   1813  *
   1814  * @param cls the lookup closure.
   1815  * @param order_id the identifier of the order found.
   1816  * @param order_serial the row number of the order found.
   1817  * @param timestamp when the order was added to the database.
   1818  */
   1819 static void
   1820 get_order_serial_cb (void *cls,
   1821                      const char *order_id,
   1822                      uint64_t order_serial,
   1823                      struct GNUNET_TIME_Timestamp timestamp)
   1824 {
   1825   struct LookupOrderSerial_Closure *lookup_cls = cls;
   1826   if (NULL == lookup_cls)
   1827     return;
   1828   if (0 == strcmp (lookup_cls->order->id,
   1829                    order_id))
   1830     lookup_cls->serial = order_serial;
   1831 }
   1832 
   1833 
   1834 /**
   1835  * Convenience function for getting the row number of an order.
   1836  *
   1837  * @param instance the instance to look up from.
   1838  * @param order the order to lookup the serial for.
   1839  * @return the row number of the order.
   1840  */
   1841 static uint64_t
   1842 get_order_serial (const struct InstanceData *instance,
   1843                   const struct OrderData *order)
   1844 {
   1845   struct LookupOrderSerial_Closure lookup_cls = {
   1846     .order = order,
   1847     .serial = 0
   1848   };
   1849   struct TALER_MERCHANTDB_OrderFilter filter = {
   1850     .paid = TALER_EXCHANGE_YNA_ALL,
   1851     .refunded = TALER_EXCHANGE_YNA_ALL,
   1852     .wired = TALER_EXCHANGE_YNA_ALL,
   1853     .date = GNUNET_TIME_UNIT_ZERO_TS,
   1854     .start_row = 0,
   1855     .delta = 256
   1856   };
   1857 
   1858   GNUNET_assert (0 < TALER_MERCHANTDB_lookup_orders (pg,
   1859                                                      instance->instance.id,
   1860                                                      &filter,
   1861                                                      &get_order_serial_cb,
   1862                                                      &lookup_cls));
   1863   GNUNET_assert (0 != lookup_cls.serial);
   1864 
   1865   return lookup_cls.serial;
   1866 }
   1867 
   1868 
   1869 /**
   1870  * Tests deleting an order from the database.
   1871  *
   1872  * @param instance the instance to delete the order from.
   1873  * @param order the order to delete.
   1874  * @param expected_result the result we expect to receive.
   1875  * @return 0 on success, 1 otherwise.
   1876  */
   1877 static int
   1878 test_delete_order (const struct InstanceData *instance,
   1879                    const struct OrderData *order,
   1880                    enum GNUNET_DB_QueryStatus expected_result)
   1881 {
   1882   TEST_COND_RET_ON_FAIL (expected_result ==
   1883                          TALER_MERCHANTDB_delete_order (pg,
   1884                                                         instance->instance.id,
   1885                                                         order->id,
   1886                                                         false),
   1887                          "Delete order failed\n");
   1888   return 0;
   1889 }
   1890 
   1891 
   1892 /**
   1893  * Test inserting contract terms for an order.
   1894  *
   1895  * @param instance the instance.
   1896  * @param order the order containing the contract terms.
   1897  * @param expected_result the result we expect to receive.
   1898  * @return 0 on success, 1 otherwise.
   1899  */
   1900 static int
   1901 test_insert_contract_terms (const struct InstanceData *instance,
   1902                             const struct OrderData *order,
   1903                             enum GNUNET_DB_QueryStatus expected_result)
   1904 {
   1905   uint64_t os;
   1906 
   1907   TEST_COND_RET_ON_FAIL (expected_result ==
   1908                          TALER_MERCHANTDB_insert_contract_terms (pg,
   1909                                                                  instance->instance.id,
   1910                                                                  order->id,
   1911                                                                  order->contract,
   1912                                                                  &os),
   1913                          "Insert contract terms failed\n");
   1914   return 0;
   1915 }
   1916 
   1917 
   1918 /**
   1919  * Test updating contract terms for an order.
   1920  *
   1921  * @param instance the instance.
   1922  * @param order the order containing the contract terms.
   1923  * @param expected_result the result we expect to receive.
   1924  * @return 0 on success, 1 otherwise.
   1925  */
   1926 static int
   1927 test_update_contract_terms (const struct InstanceData *instance,
   1928                             const struct OrderData *order,
   1929                             enum GNUNET_DB_QueryStatus expected_result)
   1930 {
   1931   TEST_COND_RET_ON_FAIL (expected_result ==
   1932                          TALER_MERCHANTDB_update_contract_terms (pg,
   1933                                                                  instance->instance.id,
   1934                                                                  order->id,
   1935                                                                  order->contract),
   1936                          "Update contract terms failed\n");
   1937   return 0;
   1938 }
   1939 
   1940 
   1941 /**
   1942  * Tests lookup of contract terms
   1943  *
   1944  * @param instance the instance to lookup from.
   1945  * @param order the order to lookup for.
   1946  * @return 0 on success, 1 otherwise.
   1947  */
   1948 static int
   1949 test_lookup_contract_terms (const struct InstanceData *instance,
   1950                             const struct OrderData *order)
   1951 {
   1952   json_t *contract = NULL;
   1953   uint64_t order_serial;
   1954 
   1955   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   1956       TALER_MERCHANTDB_lookup_contract_terms (pg,
   1957                                               instance->instance.id,
   1958                                               order->id,
   1959                                               &contract,
   1960                                               &order_serial,
   1961                                               NULL))
   1962   {
   1963     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1964                 "Lookup contract terms failed\n");
   1965     GNUNET_assert (NULL == contract);
   1966     return 1;
   1967   }
   1968   if (1 != json_equal (order->contract,
   1969                        contract))
   1970   {
   1971     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1972                 "Lookup contract terms failed: mismatched data\n");
   1973     json_decref (contract);
   1974     return 1;
   1975   }
   1976   json_decref (contract);
   1977   return 0;
   1978 }
   1979 
   1980 
   1981 /**
   1982  * Tests deleting contract terms for an order.
   1983  *
   1984  * @param instance the instance to delete from.
   1985  * @param order the order whose contract terms we should delete.
   1986  * @param legal_expiration how long we must wait after creating an order to delete it
   1987  * @param expected_result the result we expect to receive.
   1988  * @return 0 on success, 1 otherwise.
   1989  */
   1990 static int
   1991 test_delete_contract_terms (const struct InstanceData *instance,
   1992                             const struct OrderData *order,
   1993                             struct GNUNET_TIME_Relative legal_expiration,
   1994                             enum GNUNET_DB_QueryStatus expected_result)
   1995 {
   1996   TEST_COND_RET_ON_FAIL (expected_result ==
   1997                          TALER_MERCHANTDB_delete_contract_terms (pg,
   1998                                                                  instance->instance.id,
   1999                                                                  order->id,
   2000                                                                  legal_expiration),
   2001                          "Delete contract terms failed\n");
   2002   return 0;
   2003 }
   2004 
   2005 
   2006 /**
   2007  * Test marking a contract as paid in the database.
   2008  *
   2009  * @param instance the instance to use.
   2010  * @param order the order whose contract to use.
   2011  * @param expected_result the result we expect to receive.
   2012  * @return 0 on success, 1 otherwise.
   2013  */
   2014 static int
   2015 test_mark_contract_paid (const struct InstanceData *instance,
   2016                          const struct OrderData *order,
   2017                          enum GNUNET_DB_QueryStatus expected_result)
   2018 {
   2019   struct TALER_PrivateContractHashP h_contract_terms;
   2020 
   2021   GNUNET_assert (GNUNET_OK ==
   2022                  TALER_JSON_contract_hash (order->contract,
   2023                                            &h_contract_terms));
   2024   TEST_COND_RET_ON_FAIL (expected_result ==
   2025                          TALER_MERCHANTDB_mark_contract_paid (pg,
   2026                                                               instance->instance.id,
   2027                                                               &h_contract_terms,
   2028                                                               "test_orders_session",
   2029                                                               -1),
   2030                          "Mark contract paid failed\n");
   2031   return 0;
   2032 }
   2033 
   2034 
   2035 /**
   2036  * Tests looking up the status of an order.
   2037  *
   2038  * @param instance the instance to lookup from.
   2039  * @param order the order to lookup.
   2040  * @param expected_paid whether the order was paid or not.
   2041  * @return 0 on success, 1 otherwise.
   2042  */
   2043 static int
   2044 test_lookup_order_status (const struct InstanceData *instance,
   2045                           const struct OrderData *order,
   2046                           bool expected_paid)
   2047 {
   2048   struct TALER_PrivateContractHashP h_contract_terms_expected;
   2049   struct TALER_PrivateContractHashP h_contract_terms;
   2050   bool order_paid = false;
   2051 
   2052   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2053       TALER_MERCHANTDB_lookup_order_status (pg,
   2054                                             instance->instance.id,
   2055                                             order->id,
   2056                                             &h_contract_terms,
   2057                                             &order_paid))
   2058   {
   2059     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2060                 "Lookup order status failed\n");
   2061     return 1;
   2062   }
   2063   GNUNET_assert (GNUNET_OK ==
   2064                  TALER_JSON_contract_hash (order->contract,
   2065                                            &h_contract_terms_expected));
   2066   if ((expected_paid != order_paid) ||
   2067       (0 != GNUNET_memcmp (&h_contract_terms,
   2068                            &h_contract_terms_expected)))
   2069   {
   2070     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2071                 "Lookup order status/deposit failed: mismatched data\n");
   2072     return 1;
   2073   }
   2074   return 0;
   2075 }
   2076 
   2077 
   2078 /**
   2079  * Test looking up an order by its fulfillment.
   2080  *
   2081  * @param instance the instance to lookup from.
   2082  * @param order the order to lookup.
   2083  * @param the session id associated with the payment.
   2084  * @return 0 on success, 1 otherwise.
   2085  */
   2086 static int
   2087 test_lookup_order_by_fulfillment (const struct InstanceData *instance,
   2088                                   const struct OrderData *order,
   2089                                   const char *session_id)
   2090 {
   2091   char *order_id;
   2092   const char *fulfillment_url =
   2093     json_string_value (json_object_get (order->contract,
   2094                                         "fulfillment_url"));
   2095   GNUNET_assert (NULL != fulfillment_url);
   2096   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   2097       TALER_MERCHANTDB_lookup_order_by_fulfillment (pg,
   2098                                                     instance->instance.id,
   2099                                                     fulfillment_url,
   2100                                                     session_id,
   2101                                                     false,
   2102                                                     &order_id))
   2103   {
   2104     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2105                 "Lookup order by fulfillment failed\n");
   2106     GNUNET_free (order_id);
   2107     return 1;
   2108   }
   2109   if (0 != strcmp (order->id,
   2110                    order_id))
   2111   {
   2112     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2113                 "Lookup order by fulfillment failed\n");
   2114     GNUNET_free (order_id);
   2115     return 1;
   2116   }
   2117   GNUNET_free (order_id);
   2118   return 0;
   2119 }
   2120 
   2121 
   2122 /**
   2123  * Test looking up the status of an order.
   2124  *
   2125  * @param order_id the row of the order in the database.
   2126  * @param session_id the session id associated with the payment.
   2127  * @param expected_paid whether the order was paid or not.
   2128  * @param expected_wired whether the order was wired or not.
   2129  * @return 0 on success, 1 otherwise.
   2130  */
   2131 static int
   2132 test_lookup_payment_status (const char *instance_id,
   2133                             const char *order_id,
   2134                             const char *session_id,
   2135                             bool expected_paid,
   2136                             bool expected_wired)
   2137 {
   2138   bool paid;
   2139   bool wired;
   2140   bool matches;
   2141   uint64_t os;
   2142   int16_t choice_index;
   2143 
   2144   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   2145                          TALER_MERCHANTDB_lookup_contract_terms3 (pg,
   2146                                                                   instance_id,
   2147                                                                   order_id,
   2148                                                                   session_id,
   2149                                                                   NULL,
   2150                                                                   &os,
   2151                                                                   &paid,
   2152                                                                   &wired,
   2153                                                                   &matches,
   2154                                                                   NULL,
   2155                                                                   &choice_index),
   2156                          "Lookup payment status failed\n");
   2157   if ( (NULL != session_id) && (! matches) )
   2158   {
   2159     paid = false;
   2160     wired = false;
   2161   }
   2162   if (expected_wired != wired)
   2163   {
   2164     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2165                 "Lookup payment status failed: wired status is wrong\n");
   2166     return 1;
   2167   }
   2168   if (expected_paid != paid)
   2169   {
   2170     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2171                 "Lookup payment status failed: paid status is wrong\n");
   2172     return 1;
   2173   }
   2174   return 0;
   2175 }
   2176 
   2177 
   2178 /**
   2179  * Test marking an order as being wired.
   2180  *
   2181  * @param order_id the row of the order in the database.
   2182  * @param expected_result the result we expect the DB to return.
   2183  * @return 0 on success, 1 otherwise.
   2184  */
   2185 static int
   2186 test_mark_order_wired (uint64_t order_id,
   2187                        enum GNUNET_DB_QueryStatus expected_result)
   2188 {
   2189   TEST_COND_RET_ON_FAIL (expected_result ==
   2190                          TALER_MERCHANTDB_mark_order_wired (pg,
   2191                                                             order_id),
   2192                          "Mark order wired failed\n");
   2193   return 0;
   2194 }
   2195 
   2196 
   2197 /**
   2198  * Closure for order tests.
   2199  */
   2200 struct TestOrders_Closure
   2201 {
   2202   /**
   2203    * The instance to use for the order tests.
   2204    */
   2205   struct InstanceData instance;
   2206 
   2207   /**
   2208    * A product to use for the order tests.
   2209    */
   2210   struct ProductData product;
   2211 
   2212   /**
   2213    * The array of orders
   2214    */
   2215   struct OrderData orders[3];
   2216 };
   2217 
   2218 
   2219 /**
   2220  * Initializes order test data.
   2221  *
   2222  * @param cls the order test closure.
   2223  */
   2224 static void
   2225 pre_test_orders (struct TestOrders_Closure *cls)
   2226 {
   2227   /* Instance */
   2228   make_instance ("test_inst_orders",
   2229                  &cls->instance);
   2230 
   2231   /* Product */
   2232   make_product ("test_orders_pd_0",
   2233                 &cls->product);
   2234 
   2235   /* Orders */
   2236   make_order ("test_orders_od_0",
   2237               &cls->orders[0]);
   2238   make_order ("test_orders_od_1",
   2239               &cls->orders[1]);
   2240   make_order ("test_orders_od_2",
   2241               &cls->orders[2]);
   2242 
   2243   GNUNET_assert (0 ==
   2244                  json_object_set_new (cls->orders[1].contract,
   2245                                       "other_field",
   2246                                       json_string ("Second contract")));
   2247 
   2248   cls->orders[2].pay_deadline = GNUNET_TIME_UNIT_ZERO_TS;
   2249   GNUNET_assert (0 ==
   2250                  json_object_set_new (
   2251                    cls->orders[2].contract,
   2252                    "pay_deadline",
   2253                    GNUNET_JSON_from_timestamp (cls->orders[2].pay_deadline)));
   2254 }
   2255 
   2256 
   2257 /**
   2258  * Frees memory after order tests.
   2259  *
   2260  * @param cls the order test closure.
   2261  */
   2262 static void
   2263 post_test_orders (struct TestOrders_Closure *cls)
   2264 {
   2265   free_instance_data (&cls->instance);
   2266   free_product_data (&cls->product);
   2267   free_order_data (&cls->orders[0]);
   2268   free_order_data (&cls->orders[1]);
   2269   free_order_data (&cls->orders[2]);
   2270 }
   2271 
   2272 
   2273 /**
   2274  * Run the tests for orders.
   2275  *
   2276  * @param cls the order test closure.
   2277  * @return 0 on success, 1 on failure.
   2278  */
   2279 static int
   2280 run_test_orders (struct TestOrders_Closure *cls)
   2281 {
   2282   struct TALER_MERCHANTDB_OrderFilter filter = {
   2283     .paid = TALER_EXCHANGE_YNA_ALL,
   2284     .refunded = TALER_EXCHANGE_YNA_ALL,
   2285     .wired = TALER_EXCHANGE_YNA_ALL,
   2286     .date = GNUNET_TIME_UNIT_ZERO_TS,
   2287     .start_row = 0,
   2288     .delta = 8
   2289   };
   2290   uint64_t serial;
   2291 
   2292   /* Insert the instance */
   2293   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   2294                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2295   /* Test inserting an order */
   2296   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2297                                        &cls->orders[0],
   2298                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2299   /* Test double insert fails */
   2300   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2301                                        &cls->orders[0],
   2302                                        GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2303   /* Test lookup order */
   2304   TEST_RET_ON_FAIL (test_lookup_order (&cls->instance,
   2305                                        &cls->orders[0]));
   2306   /* Make sure it fails correctly for nonexistent orders */
   2307   {
   2308     struct TALER_MerchantPostDataHashP unused;
   2309 
   2310     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2311         TALER_MERCHANTDB_lookup_order (pg,
   2312                                        cls->instance.instance.id,
   2313                                        cls->orders[1].id,
   2314                                        NULL,
   2315                                        &unused,
   2316                                        NULL))
   2317     {
   2318       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2319                   "Lookup order failed\n");
   2320       return 1;
   2321     }
   2322   }
   2323   /* Test lookups on multiple orders */
   2324   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2325                                        &cls->orders[1],
   2326                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2327   serial = get_order_serial (&cls->instance,
   2328                              &cls->orders[0]);
   2329   TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   2330                                         &filter,
   2331                                         2,
   2332                                         cls->orders));
   2333   /* Test inserting contract terms */
   2334   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   2335                                                 &cls->orders[0],
   2336                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2337   /* Test double insert fails */
   2338   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   2339                                                 &cls->orders[0],
   2340                                                 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2341   /* Test order lock */
   2342   TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   2343                                          &cls->product,
   2344                                          0,
   2345                                          NULL,
   2346                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   2347                                          false,
   2348                                          false,
   2349                                          -1));
   2350   if (1 != TALER_MERCHANTDB_insert_order_lock (pg,
   2351                                                cls->instance.instance.id,
   2352                                                cls->orders[0].id,
   2353                                                cls->product.id,
   2354                                                5,
   2355                                                0))
   2356   {
   2357     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2358                 "Insert order lock failed\n");
   2359     return 1;
   2360   }
   2361   /* Test lookup contract terms */
   2362   TEST_RET_ON_FAIL (test_lookup_contract_terms (&cls->instance,
   2363                                                 &cls->orders[0]));
   2364   /* Test lookup fails for nonexistent contract terms */
   2365   {
   2366     json_t *lookup_contract = NULL;
   2367     uint64_t lookup_order_serial;
   2368 
   2369     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2370         TALER_MERCHANTDB_lookup_contract_terms (pg,
   2371                                                 cls->instance.instance.id,
   2372                                                 cls->orders[1].id,
   2373                                                 &lookup_contract,
   2374                                                 &lookup_order_serial,
   2375                                                 NULL))
   2376     {
   2377       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2378                   "Lookup contract terms failed\n");
   2379       GNUNET_assert (NULL == lookup_contract);
   2380       return 1;
   2381     }
   2382   }
   2383   /* Test update contract terms */
   2384   GNUNET_assert (0 ==
   2385                  json_object_set_new (cls->orders[0].contract,
   2386                                       "some_new_field",
   2387                                       json_string ("another value")));
   2388   TEST_RET_ON_FAIL (test_update_contract_terms (&cls->instance,
   2389                                                 &cls->orders[0],
   2390                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2391   TEST_RET_ON_FAIL (test_lookup_contract_terms (&cls->instance,
   2392                                                 &cls->orders[0]));
   2393   /* Test lookup order status */
   2394   TEST_RET_ON_FAIL (test_lookup_order_status (&cls->instance,
   2395                                               &cls->orders[0],
   2396                                               false));
   2397   {
   2398     struct TALER_PrivateContractHashP h_contract_terms;
   2399     bool order_paid = false;
   2400 
   2401     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2402         TALER_MERCHANTDB_lookup_order_status (pg,
   2403                                               cls->instance.instance.id,
   2404                                               cls->orders[1].id,
   2405                                               &h_contract_terms,
   2406                                               &order_paid))
   2407     {
   2408       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2409                   "Lookup order status failed\n");
   2410       return 1;
   2411     }
   2412   }
   2413   /* Test lookup payment status */
   2414   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2415                                                 cls->orders[0].id,
   2416                                                 NULL,
   2417                                                 false,
   2418                                                 false));
   2419   /* Test lookup order status fails for nonexistent order */
   2420   {
   2421     struct TALER_PrivateContractHashP h_contract_terms;
   2422     bool order_paid;
   2423 
   2424     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2425         TALER_MERCHANTDB_lookup_order_status (pg,
   2426                                               cls->instance.instance.id,
   2427                                               cls->orders[1].id,
   2428                                               &h_contract_terms,
   2429                                               &order_paid))
   2430     {
   2431       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2432                   "Lookup order status failed\n");
   2433       return 1;
   2434     }
   2435   }
   2436   /* Test marking contracts as paid */
   2437   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   2438                                              &cls->orders[0],
   2439                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2440   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2441                                                 cls->orders[0].id,
   2442                                                 NULL,
   2443                                                 true,
   2444                                                 false));
   2445   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2446                                                 cls->orders[0].id,
   2447                                                 "test_orders_session",
   2448                                                 true,
   2449                                                 false));
   2450   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2451                                                 cls->orders[0].id,
   2452                                                 "bad_session",
   2453                                                 false,
   2454                                                 false));
   2455   /* Test lookup order by fulfillment */
   2456   TEST_RET_ON_FAIL (test_lookup_order_by_fulfillment (&cls->instance,
   2457                                                       &cls->orders[0],
   2458                                                       "test_orders_session"));
   2459   {
   2460     char *order_id;
   2461     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2462         TALER_MERCHANTDB_lookup_order_by_fulfillment (pg,
   2463                                                       cls->instance.instance.id,
   2464                                                       "fulfillment_url",
   2465                                                       "test_orders_session",
   2466                                                       false,
   2467                                                       &order_id))
   2468     {
   2469       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2470                   "Lookup order by fulfillment failed\n");
   2471       GNUNET_free (order_id);
   2472       return 1;
   2473     }
   2474   }
   2475   /* Test mark as paid fails for nonexistent order */
   2476   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   2477                                              &cls->orders[1],
   2478                                              GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2479   TEST_RET_ON_FAIL (test_lookup_order_status (&cls->instance,
   2480                                               &cls->orders[0],
   2481                                               true));
   2482   filter.paid = TALER_EXCHANGE_YNA_YES;
   2483   TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   2484                                         &filter,
   2485                                         1,
   2486                                         cls->orders));
   2487   /* Test marking orders as wired */
   2488   TEST_RET_ON_FAIL (test_mark_order_wired (serial,
   2489                                            GNUNET_DB_STATUS_SUCCESS_ONE_RESULT))
   2490   ;
   2491   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2492                                                 cls->orders[0].id,
   2493                                                 NULL,
   2494                                                 true,
   2495                                                 true));
   2496   TEST_RET_ON_FAIL (test_mark_order_wired (1007,
   2497                                            GNUNET_DB_STATUS_SUCCESS_NO_RESULTS))
   2498   ;
   2499   /* If an order has been claimed and we aren't past
   2500      the pay deadline, we can't delete it. */
   2501   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2502                                        &cls->orders[0],
   2503                                        GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2504   /* Test we can't delete before the legal expiration */
   2505   TEST_RET_ON_FAIL (test_delete_contract_terms (&cls->instance,
   2506                                                 &cls->orders[0],
   2507                                                 GNUNET_TIME_UNIT_MONTHS,
   2508                                                 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2509   /* Test deleting contract terms */
   2510   TEST_RET_ON_FAIL (test_delete_contract_terms (&cls->instance,
   2511                                                 &cls->orders[0],
   2512                                                 GNUNET_TIME_UNIT_ZERO,
   2513                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2514   /* Test we can't delete something that doesn't exist */
   2515   TEST_RET_ON_FAIL (test_delete_contract_terms (&cls->instance,
   2516                                                 &cls->orders[0],
   2517                                                 GNUNET_TIME_UNIT_ZERO,
   2518                                                 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2519   /* Test delete order where we aren't past
   2520      the deadline, but the order is unclaimed. */
   2521   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2522                                        &cls->orders[1],
   2523                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2524   TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   2525                                         &filter,
   2526                                         0,
   2527                                         NULL));
   2528   /* Test we can't delete something that doesn't exist */
   2529   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2530                                        &cls->orders[1],
   2531                                        GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2532 
   2533   /* Test we can also delete a claimed order that's past the pay deadline. */
   2534   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2535                                        &cls->orders[2],
   2536                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2537   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   2538                                                 &cls->orders[2],
   2539                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2540   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2541                                        &cls->orders[2],
   2542                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2543   return 0;
   2544 }
   2545 
   2546 
   2547 /**
   2548  * Does all tasks for testing orders.
   2549  *
   2550  * @return 0 when successful, 1 otherwise.
   2551  */
   2552 static int
   2553 test_orders (void)
   2554 {
   2555   struct TestOrders_Closure test_cls;
   2556   int test_result;
   2557 
   2558   pre_test_orders (&test_cls);
   2559   test_result = run_test_orders (&test_cls);
   2560   post_test_orders (&test_cls);
   2561   return test_result;
   2562 }
   2563 
   2564 
   2565 /* ********** Deposits ********** */
   2566 
   2567 
   2568 /**
   2569  * A container for exchange signing key data.
   2570  */
   2571 struct ExchangeSignkeyData
   2572 {
   2573   /**
   2574    * The master private key of the exchange.
   2575    */
   2576   struct TALER_MasterPrivateKeyP master_priv;
   2577 
   2578   /**
   2579    * The master public key of the exchange.
   2580    */
   2581   struct TALER_MasterPublicKeyP master_pub;
   2582 
   2583   /**
   2584    * A signature made with the master keys.
   2585    */
   2586   struct TALER_MasterSignatureP master_sig;
   2587 
   2588   /**
   2589    * The private key of the exchange.
   2590    */
   2591   struct TALER_ExchangePrivateKeyP exchange_priv;
   2592 
   2593   /**
   2594    * The public key of the exchange.
   2595    */
   2596   struct TALER_ExchangePublicKeyP exchange_pub;
   2597 
   2598   /**
   2599    * When the signing key becomes valid.
   2600    */
   2601   struct GNUNET_TIME_Timestamp start_date;
   2602 
   2603   /**
   2604    * When the signing key stops being used.
   2605    */
   2606   struct GNUNET_TIME_Timestamp expire_date;
   2607 
   2608   /**
   2609    * When the signing key becomes invalid for proof.
   2610    */
   2611   struct GNUNET_TIME_Timestamp end_date;
   2612 };
   2613 
   2614 
   2615 /**
   2616  * Creates an exchange signing key.
   2617  *
   2618  * @param signkey the signing key data to fill.
   2619  */
   2620 static void
   2621 make_exchange_signkey (struct ExchangeSignkeyData *signkey)
   2622 {
   2623   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   2624 
   2625   GNUNET_CRYPTO_eddsa_key_create (&signkey->exchange_priv.eddsa_priv);
   2626   GNUNET_CRYPTO_eddsa_key_get_public (&signkey->exchange_priv.eddsa_priv,
   2627                                       &signkey->exchange_pub.eddsa_pub);
   2628   GNUNET_CRYPTO_eddsa_key_create (&signkey->master_priv.eddsa_priv);
   2629   GNUNET_CRYPTO_eddsa_key_get_public (&signkey->master_priv.eddsa_priv,
   2630                                       &signkey->master_pub.eddsa_pub);
   2631   signkey->start_date = now;
   2632   signkey->expire_date = now;
   2633   signkey->end_date = now;
   2634   TALER_exchange_offline_signkey_validity_sign (
   2635     &signkey->exchange_pub,
   2636     signkey->start_date,
   2637     signkey->expire_date,
   2638     signkey->end_date,
   2639     &signkey->master_priv,
   2640     &signkey->master_sig);
   2641 }
   2642 
   2643 
   2644 /**
   2645  * A container for deposit data.
   2646  */
   2647 struct DepositData
   2648 {
   2649   /**
   2650    * When the deposit was made.
   2651    */
   2652   struct GNUNET_TIME_Timestamp timestamp;
   2653 
   2654   /**
   2655    * Hash of the associated order's contract terms.
   2656    */
   2657   struct TALER_PrivateContractHashP h_contract_terms;
   2658 
   2659   /**
   2660    * Public key of the coin that has been deposited.
   2661    */
   2662   struct TALER_CoinSpendPublicKeyP coin_pub;
   2663 
   2664   /**
   2665    * Signature of the coin that has been deposited.
   2666    */
   2667   struct TALER_CoinSpendSignatureP coin_sig;
   2668 
   2669   /**
   2670    * URL of the exchange.
   2671    */
   2672   const char *exchange_url;
   2673 
   2674   /**
   2675    * Value of the coin with fees applied.
   2676    */
   2677   struct TALER_Amount amount_with_fee;
   2678 
   2679   /**
   2680    * Fee charged for deposit.
   2681    */
   2682   struct TALER_Amount deposit_fee;
   2683 
   2684   /**
   2685    * Fee to be charged in case of a refund.
   2686    */
   2687   struct TALER_Amount refund_fee;
   2688 
   2689   /**
   2690    * Fee charged after the money is wired.
   2691    */
   2692   struct TALER_Amount wire_fee;
   2693 
   2694   /**
   2695    * Hash of the wire details.
   2696    */
   2697   struct TALER_MerchantWireHashP h_wire;
   2698 
   2699   /**
   2700    * Signature the exchange made on this deposit.
   2701    */
   2702   struct TALER_ExchangeSignatureP exchange_sig;
   2703 
   2704 };
   2705 
   2706 
   2707 /**
   2708  * Generates deposit data for an order.
   2709  *
   2710  * @param instance the instance to make the deposit to.
   2711  * @param account the merchant account to use.
   2712  * @param order the order this deposit is for.
   2713  * @param signkey the signing key to use.
   2714  * @param deposit the deposit data to fill.
   2715  */
   2716 static void
   2717 make_deposit (const struct InstanceData *instance,
   2718               const struct TALER_MERCHANTDB_AccountDetails *account,
   2719               const struct OrderData *order,
   2720               const struct ExchangeSignkeyData *signkey,
   2721               struct DepositData *deposit)
   2722 {
   2723   struct TALER_CoinSpendPrivateKeyP coin_priv;
   2724   struct GNUNET_TIME_Timestamp now;
   2725   struct TALER_Amount amount_without_fee;
   2726 
   2727   now = GNUNET_TIME_timestamp_get ();
   2728   deposit->timestamp = now;
   2729   GNUNET_assert (GNUNET_OK ==
   2730                  TALER_JSON_contract_hash (order->contract,
   2731                                            &deposit->h_contract_terms));
   2732   GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv);
   2733   GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
   2734                                       &deposit->coin_pub.eddsa_pub);
   2735   deposit->exchange_url = "https://test-exchange/";
   2736   GNUNET_assert (GNUNET_OK ==
   2737                  TALER_string_to_amount ("EUR:50.00",
   2738                                          &deposit->amount_with_fee));
   2739   GNUNET_assert (GNUNET_OK ==
   2740                  TALER_string_to_amount ("EUR:1.00",
   2741                                          &deposit->deposit_fee));
   2742   GNUNET_assert (GNUNET_OK ==
   2743                  TALER_string_to_amount ("EUR:1.50",
   2744                                          &deposit->refund_fee));
   2745   GNUNET_assert (GNUNET_OK ==
   2746                  TALER_string_to_amount ("EUR:2.00",
   2747                                          &deposit->wire_fee));
   2748   GNUNET_assert (0 <=
   2749                  TALER_amount_subtract (&amount_without_fee,
   2750                                         &deposit->amount_with_fee,
   2751                                         &deposit->deposit_fee));
   2752   deposit->h_wire = account->h_wire;
   2753   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   2754                               &deposit->exchange_sig,
   2755                               sizeof (deposit->exchange_sig));
   2756   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   2757                               &deposit->coin_sig,
   2758                               sizeof (deposit->coin_sig));
   2759 }
   2760 
   2761 
   2762 /**
   2763  * Tests inserting an exchange signing key into the database.
   2764  *
   2765  * @param signkey the signing key to insert.
   2766  * @param expected_result the result we expect the database to return.
   2767  * @return 0 on success, 1 otherwise.
   2768  */
   2769 static int
   2770 test_insert_exchange_signkey (const struct ExchangeSignkeyData *signkey,
   2771                               enum GNUNET_DB_QueryStatus expected_result)
   2772 {
   2773   TEST_COND_RET_ON_FAIL (expected_result ==
   2774                          TALER_MERCHANTDB_insert_exchange_signkey (pg,
   2775                                                                    &signkey->master_pub,
   2776                                                                    &signkey->exchange_pub
   2777                                                                    ,
   2778                                                                    signkey->start_date,
   2779                                                                    signkey->expire_date,
   2780                                                                    signkey->end_date,
   2781                                                                    &signkey->master_sig),
   2782                          "Insert exchange signkey failed\n");
   2783   return 0;
   2784 }
   2785 
   2786 
   2787 /**
   2788  * Tests inserting a deposit into the database.
   2789  *
   2790  * @param instance the instance the deposit was made to.
   2791  * @param signkey the signing key used.
   2792  * @param deposit the deposit information to insert.
   2793  * @param expected_result the result we expect the database to return.
   2794  * @return 0 on success, 1 otherwise.
   2795  */
   2796 static int
   2797 test_insert_deposit (const struct InstanceData *instance,
   2798                      const struct ExchangeSignkeyData *signkey,
   2799                      const struct DepositData *deposit,
   2800                      enum GNUNET_DB_QueryStatus expected_result)
   2801 {
   2802   uint64_t row;
   2803   struct TALER_Amount awf;
   2804 
   2805   GNUNET_assert (0 <=
   2806                  TALER_amount_subtract (&awf,
   2807                                         &deposit->amount_with_fee,
   2808                                         &deposit->deposit_fee));
   2809   TEST_COND_RET_ON_FAIL (
   2810     GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   2811     TALER_MERCHANTDB_insert_deposit_confirmation (pg,
   2812                                                   instance->instance.id,
   2813                                                   deposit->timestamp,
   2814                                                   &deposit->h_contract_terms,
   2815                                                   deposit->exchange_url,
   2816                                                   deposit->timestamp,
   2817                                                   &awf,
   2818                                                   &deposit->wire_fee,
   2819                                                   &deposit->h_wire,
   2820                                                   &deposit->exchange_sig,
   2821                                                   &signkey->exchange_pub,
   2822                                                   &row),
   2823     "Insert deposit confirmation failed\n");
   2824   TEST_COND_RET_ON_FAIL (
   2825     expected_result ==
   2826     TALER_MERCHANTDB_insert_deposit (pg,
   2827                                      0,
   2828                                      row,
   2829                                      &deposit->coin_pub,
   2830                                      &deposit->coin_sig,
   2831                                      &deposit->amount_with_fee,
   2832                                      &deposit->deposit_fee,
   2833                                      &deposit->refund_fee,
   2834                                      GNUNET_TIME_absolute_get ()),
   2835     "Insert deposit failed\n");
   2836   return 0;
   2837 }
   2838 
   2839 
   2840 /**
   2841  * Closure for testing deposit lookup
   2842  */
   2843 struct TestLookupDeposits_Closure
   2844 {
   2845   /**
   2846    * Number of deposits to compare to
   2847    */
   2848   unsigned int deposits_to_cmp_length;
   2849 
   2850   /**
   2851    * Pointer to array of deposit data
   2852    */
   2853   const struct DepositData *deposits_to_cmp;
   2854 
   2855   /**
   2856    * Pointer to array of number of matches per deposit
   2857    */
   2858   unsigned int *results_matching;
   2859 
   2860   /**
   2861    * Total number of results returned
   2862    */
   2863   unsigned int results_length;
   2864 };
   2865 
   2866 
   2867 /**
   2868  * Called after 'test_lookup_deposits'.
   2869  *
   2870  * @param cls pointer to the test lookup closure.
   2871  * @param coin_pub public key of the coin deposited.
   2872  * @param amount_with_fee amount of the deposit with fees.
   2873  * @param deposit_fee fee charged for the deposit.
   2874  * @param refund_fee fee charged in case of a refund.
   2875  */
   2876 static void
   2877 lookup_deposits_cb (void *cls,
   2878                     const char *exchange_url,
   2879                     const struct TALER_CoinSpendPublicKeyP *coin_pub,
   2880                     const struct TALER_Amount *amount_with_fee,
   2881                     const struct TALER_Amount *deposit_fee,
   2882                     const struct TALER_Amount *refund_fee)
   2883 {
   2884   struct TestLookupDeposits_Closure *cmp = cls;
   2885   if (NULL == cmp)
   2886     return;
   2887   cmp->results_length += 1;
   2888   for (unsigned int i = 0; cmp->deposits_to_cmp_length > i; ++i)
   2889   {
   2890     if ((GNUNET_OK ==
   2891          TALER_amount_cmp_currency (
   2892            &cmp->deposits_to_cmp[i].amount_with_fee,
   2893            amount_with_fee)) &&
   2894         (0 ==
   2895          TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
   2896                            amount_with_fee)) &&
   2897         (GNUNET_OK ==
   2898          TALER_amount_cmp_currency (
   2899            &cmp->deposits_to_cmp[i].deposit_fee,
   2900            deposit_fee)) &&
   2901         (0 ==
   2902          TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
   2903                            deposit_fee)) &&
   2904         (GNUNET_OK ==
   2905          TALER_amount_cmp_currency (
   2906            &cmp->deposits_to_cmp[i].refund_fee,
   2907            refund_fee)) &&
   2908         (0 ==
   2909          TALER_amount_cmp (&cmp->deposits_to_cmp[i].refund_fee,
   2910                            refund_fee)))
   2911     {
   2912       cmp->results_matching[i] += 1;
   2913     }
   2914 
   2915   }
   2916 }
   2917 
   2918 
   2919 /**
   2920  * Tests looking up deposits from the database.
   2921  *
   2922  * @param instance the instance to lookup deposits from.
   2923  * @param h_contract_terms the contract terms that the deposits should have.
   2924  * @param deposits_length length of @e deposits.
   2925  * @param deposits the deposits we expect to be found.
   2926  * @return 0 on success, 1 otherwise.
   2927  */
   2928 static int
   2929 test_lookup_deposits (const struct InstanceData *instance,
   2930                       const struct TALER_PrivateContractHashP *h_contract_terms,
   2931                       unsigned int deposits_length,
   2932                       const struct DepositData *deposits)
   2933 {
   2934   unsigned int results_matching[GNUNET_NZL (deposits_length)];
   2935   struct TestLookupDeposits_Closure cmp = {
   2936     .deposits_to_cmp_length = deposits_length,
   2937     .deposits_to_cmp = deposits,
   2938     .results_matching = results_matching,
   2939     .results_length = 0
   2940   };
   2941   memset (results_matching,
   2942           0,
   2943           sizeof (unsigned int) * deposits_length);
   2944   TEST_COND_RET_ON_FAIL (0 <=
   2945                          TALER_MERCHANTDB_lookup_deposits (pg,
   2946                                                            instance->instance.id,
   2947                                                            h_contract_terms,
   2948                                                            &lookup_deposits_cb,
   2949                                                            &cmp),
   2950                          "Lookup deposits failed\n");
   2951   if (deposits_length != cmp.results_length)
   2952   {
   2953     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2954                 "Lookup deposits failed: incorrect number of results returned (%d)\n",
   2955                 cmp.results_length);
   2956     return 1;
   2957   }
   2958   for (unsigned int i = 0; deposits_length > i; ++i)
   2959   {
   2960     if (cmp.results_matching[i] != 1)
   2961     {
   2962       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2963                   "Lookup deposits failed: mismatched data\n");
   2964       return 1;
   2965     }
   2966   }
   2967   return 0;
   2968 }
   2969 
   2970 
   2971 /**
   2972  * Called after 'test_lookup_deposits_contract_and_coin'.
   2973  *
   2974  * @param cls pointer to the test lookup closure.
   2975  * @param exchange_url URL to the exchange
   2976  * @param amount_with_fee amount of the deposit with fees.
   2977  * @param deposit_fee fee charged for the deposit.
   2978  * @param refund_fee fee charged in case of a refund.
   2979  * @param wire_fee fee charged when the money is wired.
   2980  * @param h_wire hash of the wire transfer details.
   2981  * @param deposit_timestamp when the deposit was made.
   2982  * @param refund_deadline deadline for refunding the deposit.
   2983  * @param exchange_sig signature the exchange made on the deposit.
   2984  * @param exchange_pub public key of the exchange.
   2985  */
   2986 static void
   2987 lookup_deposits_contract_coin_cb (
   2988   void *cls,
   2989   const char *exchange_url,
   2990   const struct TALER_Amount *amount_with_fee,
   2991   const struct TALER_Amount *deposit_fee,
   2992   const struct TALER_Amount *refund_fee,
   2993   const struct TALER_Amount *wire_fee,
   2994   const struct TALER_MerchantWireHashP *h_wire,
   2995   struct GNUNET_TIME_Timestamp deposit_timestamp,
   2996   struct GNUNET_TIME_Timestamp refund_deadline,
   2997   const struct TALER_ExchangeSignatureP *exchange_sig,
   2998   const struct TALER_ExchangePublicKeyP *exchange_pub)
   2999 {
   3000   struct TestLookupDeposits_Closure *cmp = cls;
   3001 
   3002   if (NULL == cmp)
   3003     return;
   3004   cmp->results_length++;
   3005   for (unsigned int i = 0; cmp->deposits_to_cmp_length > i; ++i)
   3006   {
   3007     if ((GNUNET_TIME_timestamp_cmp (cmp->deposits_to_cmp[i].timestamp,
   3008                                     ==,
   3009                                     deposit_timestamp)) &&
   3010         (0 == strcmp (cmp->deposits_to_cmp[i].exchange_url,
   3011                       exchange_url)) &&
   3012         (GNUNET_OK == TALER_amount_cmp_currency (
   3013            &cmp->deposits_to_cmp[i].amount_with_fee,
   3014            amount_with_fee)) &&
   3015         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
   3016                                 amount_with_fee)) &&
   3017         (GNUNET_OK == TALER_amount_cmp_currency (
   3018            &cmp->deposits_to_cmp[i].deposit_fee,
   3019            deposit_fee)) &&
   3020         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
   3021                                 deposit_fee)) &&
   3022         (GNUNET_OK == TALER_amount_cmp_currency (
   3023            &cmp->deposits_to_cmp[i].refund_fee,
   3024            refund_fee)) &&
   3025         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].refund_fee,
   3026                                 refund_fee)) &&
   3027         (GNUNET_OK == TALER_amount_cmp_currency (
   3028            &cmp->deposits_to_cmp[i].wire_fee,
   3029            wire_fee)) &&
   3030         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].wire_fee,
   3031                                 wire_fee)) &&
   3032         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].h_wire,
   3033                              h_wire)) &&
   3034         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].exchange_sig,
   3035                              exchange_sig)))
   3036     {
   3037       cmp->results_matching[i]++;
   3038     }
   3039   }
   3040 }
   3041 
   3042 
   3043 /**
   3044  * Tests lookup of deposits by contract and coin.
   3045  *
   3046  * @param instance the instance to lookup from.
   3047  * @param h_contract the contract terms the deposits should have.
   3048  * @param coin_pub the public key of the coin the deposits should have.
   3049  * @param deposits_length length of @e deposits.
   3050  * @param deposits the deposits the db is expected to find.
   3051  * @return 0 on success, 1 otherwise.
   3052  */
   3053 static int
   3054 test_lookup_deposits_contract_and_coin (
   3055   const struct InstanceData *instance,
   3056   const struct TALER_PrivateContractHashP *h_contract,
   3057   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   3058   unsigned int deposits_length,
   3059   const struct DepositData *deposits)
   3060 {
   3061   unsigned int results_matching[deposits_length];
   3062   struct TestLookupDeposits_Closure cmp = {
   3063     .deposits_to_cmp_length = deposits_length,
   3064     .deposits_to_cmp = deposits,
   3065     .results_matching = results_matching,
   3066     .results_length = 0
   3067   };
   3068   memset (results_matching,
   3069           0,
   3070           sizeof (unsigned int) * deposits_length);
   3071   TEST_COND_RET_ON_FAIL (
   3072     GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   3073     TALER_MERCHANTDB_lookup_deposits_by_contract_and_coin (
   3074       pg,
   3075       instance->instance.id,
   3076       h_contract,
   3077       coin_pub,
   3078       &lookup_deposits_contract_coin_cb,
   3079       &cmp),
   3080     "Lookup deposits by contract and coin failed\n");
   3081   if (deposits_length != cmp.results_length)
   3082   {
   3083     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3084                 "Lookup deposits failed: incorrect number of results returned\n");
   3085     return 1;
   3086   }
   3087   for (unsigned int i = 0; deposits_length > i; ++i)
   3088   {
   3089     if (cmp.results_matching[i] != 1)
   3090     {
   3091       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3092                   "Lookup deposits failed: mismatched data\n");
   3093       return 1;
   3094     }
   3095   }
   3096   return 0;
   3097 }
   3098 
   3099 
   3100 /**
   3101  * Called after 'test_lookup_deposits_by_order'.
   3102  *
   3103  * @param cls pointer to the test lookup closure.
   3104  * @param deposit_serial row number of the deposit in the database.
   3105  * @param exchange_url URL to the exchange
   3106  * @param h_wire hash of the wire transfer details.
   3107  * @param deposit_timestamp when was the deposit made
   3108  * @param amount_with_fee amount of the deposit with fees.
   3109  * @param deposit_fee fee charged for the deposit.
   3110  * @param coin_pub public key of the coin deposited.
   3111  */
   3112 static void
   3113 lookup_deposits_order_cb (void *cls,
   3114                           uint64_t deposit_serial,
   3115                           const char *exchange_url,
   3116                           const struct TALER_MerchantWireHashP *h_wire,
   3117                           struct GNUNET_TIME_Timestamp deposit_timestamp,
   3118                           const struct TALER_Amount *amount_with_fee,
   3119                           const struct TALER_Amount *deposit_fee,
   3120                           const struct TALER_CoinSpendPublicKeyP *coin_pub)
   3121 {
   3122   struct TestLookupDeposits_Closure *cmp = cls;
   3123 
   3124   if (NULL == cmp)
   3125     return;
   3126   cmp->results_length += 1;
   3127   for (unsigned int i = 0; i < cmp->deposits_to_cmp_length; ++i)
   3128   {
   3129     if ((0 == strcmp (cmp->deposits_to_cmp[i].exchange_url,
   3130                       exchange_url)) &&
   3131         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].h_wire,
   3132                              h_wire)) &&
   3133         (GNUNET_OK == TALER_amount_cmp_currency (
   3134            &cmp->deposits_to_cmp[i].amount_with_fee,
   3135            amount_with_fee)) &&
   3136         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
   3137                                 amount_with_fee)) &&
   3138         (GNUNET_OK == TALER_amount_cmp_currency (
   3139            &cmp->deposits_to_cmp[i].deposit_fee,
   3140            deposit_fee)) &&
   3141         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
   3142                                 deposit_fee)) &&
   3143         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].coin_pub,
   3144                              coin_pub)))
   3145       cmp->results_matching[i] += 1;
   3146   }
   3147 }
   3148 
   3149 
   3150 /**
   3151  * Tests looking up deposits by associated order.
   3152  *
   3153  * @param order_serial row number of the order to lookup for.
   3154  * @param deposits_length length of @e deposits_length.
   3155  * @param deposits the deposits we expect to be found.
   3156  * @return 0 on success, 1 otherwise.
   3157  */
   3158 static int
   3159 test_lookup_deposits_by_order (uint64_t order_serial,
   3160                                unsigned int deposits_length,
   3161                                const struct DepositData *deposits)
   3162 {
   3163   unsigned int results_matching[deposits_length];
   3164   struct TestLookupDeposits_Closure cmp = {
   3165     .deposits_to_cmp_length = deposits_length,
   3166     .deposits_to_cmp = deposits,
   3167     .results_matching = results_matching,
   3168     .results_length = 0
   3169   };
   3170   memset (results_matching,
   3171           0,
   3172           sizeof (unsigned int) * deposits_length);
   3173   if (deposits_length !=
   3174       TALER_MERCHANTDB_lookup_deposits_by_order (pg,
   3175                                                  order_serial,
   3176                                                  &lookup_deposits_order_cb,
   3177                                                  &cmp))
   3178   {
   3179     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3180                 "Lookup deposits by order failed\n");
   3181     return 1;
   3182   }
   3183   if (deposits_length != cmp.results_length)
   3184   {
   3185     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3186                 "Lookup deposits by order failed: incorrect number of results\n");
   3187     return 1;
   3188   }
   3189   for (unsigned int i = 0; i < deposits_length; ++i)
   3190   {
   3191     if (1 != cmp.results_matching[i])
   3192     {
   3193       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3194                   "Lookup deposits by order failed: mismatched data\n");
   3195       return 1;
   3196     }
   3197   }
   3198   return 0;
   3199 }
   3200 
   3201 
   3202 /**
   3203  * Container for information for looking up the row number of a deposit.
   3204  */
   3205 struct LookupDepositSerial_Closure
   3206 {
   3207   /**
   3208    * The deposit we're looking for.
   3209    */
   3210   const struct DepositData *deposit;
   3211 
   3212   /**
   3213    * The serial found.
   3214    */
   3215   uint64_t serial;
   3216 };
   3217 
   3218 
   3219 /**
   3220  * Called after 'get_deposit_serial'.
   3221  *
   3222  * @param cls pointer to the test lookup closure.
   3223  * @param deposit_serial row number of the deposit in the database.
   3224  * @param exchange_url URL to the exchange
   3225  * @param h_wire hash of the wire transfer details.
   3226  * @param deposit_timestamp when was the deposit made.
   3227  * @param amount_with_fee amount of the deposit with fees.
   3228  * @param deposit_fee fee charged for the deposit.
   3229  * @param coin_pub public key of the coin deposited.
   3230  */
   3231 static void
   3232 get_deposit_serial_cb (void *cls,
   3233                        uint64_t deposit_serial,
   3234                        const char *exchange_url,
   3235                        const struct TALER_MerchantWireHashP *h_wire,
   3236                        struct GNUNET_TIME_Timestamp deposit_timestamp,
   3237                        const struct TALER_Amount *amount_with_fee,
   3238                        const struct TALER_Amount *deposit_fee,
   3239                        const struct TALER_CoinSpendPublicKeyP *coin_pub)
   3240 {
   3241   struct LookupDepositSerial_Closure *lookup_cls = cls;
   3242 
   3243   (void) deposit_timestamp;
   3244   if (NULL == lookup_cls)
   3245     return;
   3246   if ((0 == strcmp (lookup_cls->deposit->exchange_url,
   3247                     exchange_url)) &&
   3248       (0 == GNUNET_memcmp (&lookup_cls->deposit->h_wire,
   3249                            h_wire)) &&
   3250       (GNUNET_OK == TALER_amount_cmp_currency (
   3251          &lookup_cls->deposit->amount_with_fee,
   3252          amount_with_fee)) &&
   3253       (0 == TALER_amount_cmp (&lookup_cls->deposit->amount_with_fee,
   3254                               amount_with_fee)) &&
   3255       (GNUNET_OK == TALER_amount_cmp_currency (
   3256          &lookup_cls->deposit->deposit_fee,
   3257          deposit_fee)) &&
   3258       (0 == TALER_amount_cmp (&lookup_cls->deposit->deposit_fee,
   3259                               deposit_fee)) &&
   3260       (0 == GNUNET_memcmp (&lookup_cls->deposit->coin_pub,
   3261                            coin_pub)))
   3262     lookup_cls->serial = deposit_serial;
   3263 }
   3264 
   3265 
   3266 /**
   3267  * Convenience function to retrieve the row number of a deposit in the database.
   3268  *
   3269  * @param instance the instance to get deposits from.
   3270  * @param order the order associated with the deposit.
   3271  * @param deposit the deposit to lookup the serial for.
   3272  * @return the row number of the deposit.
   3273  */
   3274 static uint64_t
   3275 get_deposit_serial (const struct InstanceData *instance,
   3276                     const struct OrderData *order,
   3277                     const struct DepositData *deposit)
   3278 {
   3279   uint64_t order_serial = get_order_serial (instance,
   3280                                             order);
   3281   struct LookupDepositSerial_Closure lookup_cls = {
   3282     .deposit = deposit,
   3283     .serial = 0
   3284   };
   3285 
   3286   GNUNET_assert (0 <
   3287                  TALER_MERCHANTDB_lookup_deposits_by_order (pg,
   3288                                                             order_serial,
   3289                                                             &get_deposit_serial_cb,
   3290                                                             &lookup_cls));
   3291   GNUNET_assert (0 != lookup_cls.serial);
   3292 
   3293   return lookup_cls.serial;
   3294 }
   3295 
   3296 
   3297 /**
   3298  * Closure for deposit tests.
   3299  */
   3300 struct TestDeposits_Closure
   3301 {
   3302   /**
   3303    * The instance settings
   3304    */
   3305   struct InstanceData instance;
   3306 
   3307   /**
   3308    * The merchant account
   3309    */
   3310   struct TALER_MERCHANTDB_AccountDetails account;
   3311 
   3312   /**
   3313    * The exchange signing key
   3314    */
   3315   struct ExchangeSignkeyData signkey;
   3316 
   3317   /**
   3318    * The order data
   3319    */
   3320   struct OrderData orders[2];
   3321 
   3322   /**
   3323    * The array of deposits
   3324    */
   3325   struct DepositData deposits[3];
   3326 };
   3327 
   3328 
   3329 /**
   3330  * Initializes data for testing deposits.
   3331  *
   3332  * @param cls the test closure to initialize.
   3333  */
   3334 static void
   3335 pre_test_deposits (struct TestDeposits_Closure *cls)
   3336 {
   3337   /* Instance */
   3338   make_instance ("test_inst_deposits",
   3339                  &cls->instance);
   3340 
   3341   /* Account */
   3342   make_account (&cls->account);
   3343   cls->account.instance_id = cls->instance.instance.id;
   3344   /* Signing key */
   3345   make_exchange_signkey (&cls->signkey);
   3346 
   3347   /* Order */
   3348   make_order ("test_deposits_od_1",
   3349               &cls->orders[0]);
   3350   make_order ("test_deposits_od_2",
   3351               &cls->orders[1]);
   3352 
   3353   /* Deposit */
   3354   make_deposit (&cls->instance,
   3355                 &cls->account,
   3356                 &cls->orders[0],
   3357                 &cls->signkey,
   3358                 &cls->deposits[0]);
   3359   make_deposit (&cls->instance,
   3360                 &cls->account,
   3361                 &cls->orders[0],
   3362                 &cls->signkey,
   3363                 &cls->deposits[1]);
   3364   GNUNET_assert (GNUNET_OK ==
   3365                  TALER_string_to_amount ("EUR:29.00",
   3366                                          &cls->deposits[1].amount_with_fee));
   3367   make_deposit (&cls->instance,
   3368                 &cls->account,
   3369                 &cls->orders[1],
   3370                 &cls->signkey,
   3371                 &cls->deposits[2]);
   3372 }
   3373 
   3374 
   3375 /**
   3376  * Cleans up memory after testing deposits.
   3377  *
   3378  * @param cls the closure containing memory to free.
   3379  */
   3380 static void
   3381 post_test_deposits (struct TestDeposits_Closure *cls)
   3382 {
   3383   free_instance_data (&cls->instance);
   3384   json_decref (cls->orders[0].contract);
   3385   json_decref (cls->orders[1].contract);
   3386 }
   3387 
   3388 
   3389 /**
   3390  * Runs tests for deposits.
   3391  *
   3392  * @param cls the closure containing test data.
   3393  * @return 0 on success, 1 otherwise.
   3394  */
   3395 static int
   3396 run_test_deposits (struct TestDeposits_Closure *cls)
   3397 {
   3398   /* Insert the instance */
   3399   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   3400                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3401   /* Insert an account */
   3402   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   3403                                          &cls->account,
   3404                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3405   /* Insert a signing key */
   3406   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   3407                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3408   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   3409                                                   GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   3410   /* Insert an order */
   3411   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   3412                                        &cls->orders[0],
   3413                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3414   /* Insert contract terms */
   3415   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   3416                                                 &cls->orders[0],
   3417                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3418   /* Test inserting a deposit */
   3419   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3420                                          &cls->signkey,
   3421                                          &cls->deposits[0],
   3422                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3423   /* Test double inserts are idempotent */
   3424   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3425                                          &cls->signkey,
   3426                                          &cls->deposits[0],
   3427                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   3428   /* Test lookup deposits */
   3429   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3430                                           &cls->deposits[0].h_contract_terms,
   3431                                           1,
   3432                                           cls->deposits));
   3433   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3434                                           &cls->deposits[2].h_contract_terms,
   3435                                           0,
   3436                                           NULL));
   3437   /* Test lookup deposits by contract and coins */
   3438   TEST_RET_ON_FAIL (test_lookup_deposits_contract_and_coin (
   3439                       &cls->instance,
   3440                       &cls->deposits[0].h_contract_terms,
   3441                       &cls->deposits[0].coin_pub,
   3442                       1,
   3443                       cls->deposits));
   3444   /* Test multiple deposits */
   3445   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3446                                          &cls->signkey,
   3447                                          &cls->deposits[1],
   3448                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3449   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   3450                                        &cls->orders[1],
   3451                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3452   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   3453                                                 &cls->orders[1],
   3454                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3455   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3456                                          &cls->signkey,
   3457                                          &cls->deposits[2],
   3458                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3459   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3460                                           &cls->deposits[0].h_contract_terms,
   3461                                           2,
   3462                                           cls->deposits));
   3463   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3464                                           &cls->deposits[2].h_contract_terms,
   3465                                           1,
   3466                                           &cls->deposits[2]));
   3467   /* Test lookup deposits by order */
   3468   {
   3469     uint64_t order_serial = get_order_serial (&cls->instance,
   3470                                               &cls->orders[0]);
   3471     TEST_RET_ON_FAIL (test_lookup_deposits_by_order (order_serial,
   3472                                                      2,
   3473                                                      cls->deposits));
   3474     order_serial = get_order_serial (&cls->instance,
   3475                                      &cls->orders[1]);
   3476     TEST_RET_ON_FAIL (test_lookup_deposits_by_order (order_serial,
   3477                                                      1,
   3478                                                      &cls->deposits[2]));
   3479   }
   3480   return 0;
   3481 }
   3482 
   3483 
   3484 /**
   3485  * Handles functionality for testing deposits.
   3486  *
   3487  * @return 0 on success, 1 otherwise.
   3488  */
   3489 static int
   3490 test_deposits (void)
   3491 {
   3492   struct TestDeposits_Closure test_cls;
   3493   int test_result;
   3494 
   3495   pre_test_deposits (&test_cls);
   3496   test_result = run_test_deposits (&test_cls);
   3497   post_test_deposits (&test_cls);
   3498   return test_result;
   3499 }
   3500 
   3501 
   3502 /* *********** Transfers ********** */
   3503 
   3504 
   3505 /**
   3506  * Container for wire fee data for an exchange.
   3507  */
   3508 struct WireFeeData
   3509 {
   3510   /**
   3511    * The method used.
   3512    */
   3513   const char *wire_method;
   3514 
   3515   /**
   3516    * Hash of the wire method.
   3517    */
   3518   struct GNUNET_HashCode h_wire_method;
   3519 
   3520   /**
   3521    * Wire fees charged.
   3522    */
   3523   struct TALER_WireFeeSet fees;
   3524 
   3525   /**
   3526    * Start date of the wire fee.
   3527    */
   3528   struct GNUNET_TIME_Timestamp wire_fee_start;
   3529 
   3530   /**
   3531    * End date of the wire fee.
   3532    */
   3533   struct GNUNET_TIME_Timestamp wire_fee_end;
   3534 
   3535   /**
   3536    * Signature on the wire fee.
   3537    */
   3538   struct TALER_MasterSignatureP fee_sig;
   3539 };
   3540 
   3541 
   3542 /**
   3543  * Creates data for an exchange wire fee.
   3544  *
   3545  * @param signkey the exchange signing key data.
   3546  * @param wire_fee where to store the wire fee data.
   3547  */
   3548 static void
   3549 make_wire_fee (const struct ExchangeSignkeyData *signkey,
   3550                struct WireFeeData *wire_fee)
   3551 {
   3552   wire_fee->wire_method = "wire-method";
   3553   GNUNET_CRYPTO_hash (wire_fee->wire_method,
   3554                       strlen (wire_fee->wire_method) + 1,
   3555                       &wire_fee->h_wire_method);
   3556   GNUNET_assert (GNUNET_OK ==
   3557                  TALER_string_to_amount ("EUR:0.49",
   3558                                          &wire_fee->fees.wire));
   3559   GNUNET_assert (GNUNET_OK ==
   3560                  TALER_string_to_amount ("EUR:0.49",
   3561                                          &wire_fee->fees.closing));
   3562   wire_fee->wire_fee_start = GNUNET_TIME_timestamp_get ();
   3563   wire_fee->wire_fee_end = GNUNET_TIME_relative_to_timestamp (
   3564     GNUNET_TIME_UNIT_MONTHS);
   3565   TALER_exchange_offline_wire_fee_sign (
   3566     wire_fee->wire_method,
   3567     wire_fee->wire_fee_start,
   3568     wire_fee->wire_fee_end,
   3569     &wire_fee->fees,
   3570     &signkey->master_priv,
   3571     &wire_fee->fee_sig);
   3572 }
   3573 
   3574 
   3575 /**
   3576  * Container for wire transfer data.
   3577  */
   3578 struct TransferData
   3579 {
   3580   /**
   3581    * Id of the transfer.
   3582    */
   3583   struct TALER_WireTransferIdentifierRawP wtid;
   3584 
   3585   /**
   3586    * The main data for the transfer.
   3587    */
   3588   struct TALER_EXCHANGE_TransferData data;
   3589 
   3590   /**
   3591    * URL to the exchange the transfer was made through.
   3592    */
   3593   const char *exchange_url;
   3594 
   3595   /**
   3596    * How much the fee for the deposit was.
   3597    */
   3598   struct TALER_Amount deposit_fee;
   3599 
   3600   /**
   3601    * Whether the transfer has been confirmed.
   3602    */
   3603   bool confirmed;
   3604 
   3605   /**
   3606    * Whether the transfer has been verified.
   3607    */
   3608   bool verified;
   3609 };
   3610 
   3611 
   3612 /**
   3613  * Creates a transfer for use with testing.
   3614  *
   3615  * @param deposits_length length of @e deposits.
   3616  * @param deposits list of deposits to combine into one transfer.
   3617  * @param transfer where to write the transfer data.
   3618  */
   3619 static void
   3620 make_transfer (const struct ExchangeSignkeyData *signkey,
   3621                unsigned int deposits_length,
   3622                const struct DepositData deposits[static deposits_length],
   3623                struct TransferData *transfer)
   3624 {
   3625   struct TALER_TrackTransferDetails *details = NULL;
   3626 
   3627   GNUNET_CRYPTO_seed_weak_random (585);
   3628   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   3629                               &transfer->wtid,
   3630                               sizeof (struct TALER_WireTransferIdentifierRawP));
   3631   transfer->exchange_url = deposits[0].exchange_url;
   3632   transfer->verified = false;
   3633   transfer->confirmed = false;
   3634   transfer->data.details_length = 0;
   3635   GNUNET_assert (GNUNET_OK ==
   3636                  TALER_amount_set_zero (deposits[0].amount_with_fee.currency,
   3637                                         &transfer->data.total_amount));
   3638   GNUNET_assert (GNUNET_OK ==
   3639                  TALER_amount_set_zero (deposits[0].amount_with_fee.currency,
   3640                                         &transfer->deposit_fee));
   3641   for (unsigned int i = 0; i < deposits_length; ++i)
   3642   {
   3643     GNUNET_array_grow (details,
   3644                        transfer->data.details_length,
   3645                        i + 1);
   3646     details[i].h_contract_terms = deposits[i].h_contract_terms;
   3647     details[i].coin_pub = deposits[i].coin_pub;
   3648     details[i].coin_value = deposits[i].amount_with_fee;
   3649     details[i].coin_fee = deposits[i].deposit_fee;
   3650     GNUNET_assert (0 <=
   3651                    TALER_amount_add (&transfer->data.total_amount,
   3652                                      &transfer->data.total_amount,
   3653                                      &deposits[i].amount_with_fee));
   3654     GNUNET_assert (0 <=
   3655                    TALER_amount_add (&transfer->deposit_fee,
   3656                                      &transfer->deposit_fee,
   3657                                      &deposits[i].deposit_fee));
   3658   }
   3659   transfer->data.exchange_pub = signkey->exchange_pub;
   3660   transfer->data.execution_time = GNUNET_TIME_timestamp_get ();
   3661   transfer->data.details = details;
   3662   GNUNET_assert (GNUNET_OK ==
   3663                  TALER_string_to_amount ("EUR:0.50",
   3664                                          &transfer->data.wire_fee));
   3665 }
   3666 
   3667 
   3668 /**
   3669  * Closure for testing 'lookup_transfer_summary'
   3670  */
   3671 struct TestLookupTransferSummary_Closure
   3672 {
   3673   /**
   3674    * Id of the order the transfer was made for.
   3675    */
   3676   const char *order_id;
   3677 
   3678   /**
   3679    * The value of the deposit made.
   3680    */
   3681   const struct TALER_Amount *deposit_value;
   3682 
   3683   /**
   3684    * The fee on the deposit made.
   3685    */
   3686   const struct TALER_Amount *deposit_fee;
   3687 
   3688   /**
   3689    * 0 if the comparison is true, 1 if false.
   3690    */
   3691   int result;
   3692 };
   3693 
   3694 
   3695 /**
   3696  * Called after 'test_lookup_transfer_summary'.
   3697  *
   3698  * @param cls pointer to 'TestLookupTransferSummary_Closure'.
   3699  * @param order_id id of the order the transfer was made for.
   3700  * @param deposit_value the value of the deposit made.
   3701  * @param deposit_fee the fee on the deposit made.
   3702  */
   3703 static void
   3704 lookup_transfer_summary_cb (void *cls,
   3705                             const char *order_id,
   3706                             const struct TALER_Amount *deposit_value,
   3707                             const struct TALER_Amount *deposit_fee)
   3708 {
   3709   struct TestLookupTransferSummary_Closure *cmp = cls;
   3710   if (NULL == cmp)
   3711     return;
   3712   if ((0 == strcmp (cmp->order_id,
   3713                     order_id)) &&
   3714       (GNUNET_OK == TALER_amount_cmp_currency (cmp->deposit_value,
   3715                                                deposit_value)) &&
   3716       (0 == TALER_amount_cmp (cmp->deposit_value,
   3717                               deposit_value)) &&
   3718       (GNUNET_OK == TALER_amount_cmp_currency (cmp->deposit_fee,
   3719                                                deposit_fee)) &&
   3720       (0 == TALER_amount_cmp (cmp->deposit_fee,
   3721                               deposit_fee)))
   3722     cmp->result = 0;
   3723   else
   3724     cmp->result = 1;
   3725 }
   3726 
   3727 
   3728 /**
   3729  * Tests looking up a transfer's summary.
   3730  *
   3731  * @param exchange_url url to the exchange for the transfer.
   3732  * @param wtid identifier of the transfer.
   3733  * @param expected_order_id the id of the order associated with the transfer.
   3734  * @param expected_deposit_value the amount of the deposit made for the transfer.
   3735  * @param expected_deposit_fee the fee on the deposit made for the transfer.
   3736  * @return 1 on success, 0 otherwise.
   3737  */
   3738 static int
   3739 test_lookup_transfer_summary (
   3740   const char *exchange_url,
   3741   const struct TALER_WireTransferIdentifierRawP *wtid,
   3742   const char *expected_order_id,
   3743   const struct TALER_Amount *expected_deposit_value,
   3744   const struct TALER_Amount *expected_deposit_fee)
   3745 {
   3746   struct TestLookupTransferSummary_Closure cmp = {
   3747     .order_id = expected_order_id,
   3748     .deposit_value = expected_deposit_value,
   3749     .deposit_fee = expected_deposit_fee,
   3750     .result = 0
   3751   };
   3752   if (1 != TALER_MERCHANTDB_lookup_transfer_summary (pg,
   3753                                                      exchange_url,
   3754                                                      wtid,
   3755                                                      &lookup_transfer_summary_cb,
   3756                                                      &cmp))
   3757   {
   3758     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3759                 "Lookup transfer summary failed\n");
   3760     return 1;
   3761   }
   3762   if (0 != cmp.result)
   3763   {
   3764     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3765                 "Lookup transfer summary failed: mismatched data\n");
   3766     return 1;
   3767   }
   3768   return 0;
   3769 }
   3770 
   3771 
   3772 /**
   3773  * Closure for testing 'lookup_transfer_details'.
   3774  */
   3775 struct TestLookupTransferDetails_Closure
   3776 {
   3777   /**
   3778    * Length of @e details_to_cmp.
   3779    */
   3780   unsigned int details_to_cmp_length;
   3781 
   3782   /**
   3783    * The details we expect to find.
   3784    */
   3785   const struct TALER_TrackTransferDetails *details_to_cmp;
   3786 
   3787   /**
   3788    * Number of results matching each detail in @e details_to_cmp.
   3789    */
   3790   unsigned int *results_matching;
   3791 
   3792   /**
   3793    * Total number of results found.
   3794    */
   3795   unsigned int results_length;
   3796 };
   3797 
   3798 
   3799 /**
   3800  * Called after 'test_lookup_transfer_details'.
   3801  *
   3802  * @param cls pointer to 'TestLookupTransferDetails_Closure'.
   3803  * @param current_offset offset within transfer details.
   3804  * @param details the details that were found.
   3805  */
   3806 static void
   3807 lookup_transfer_details_cb (void *cls,
   3808                             unsigned int current_offset,
   3809                             const struct TALER_TrackTransferDetails *details)
   3810 {
   3811   struct TestLookupTransferDetails_Closure *cmp = cls;
   3812   if (NULL == cmp)
   3813     return;
   3814   for (unsigned int i = 0; cmp->details_to_cmp_length > i; ++i)
   3815   {
   3816     if ((0 == GNUNET_memcmp (&cmp->details_to_cmp[i].h_contract_terms,
   3817                              &details->h_contract_terms)) &&
   3818         (0 == GNUNET_memcmp (&cmp->details_to_cmp[i].coin_pub,
   3819                              &details->coin_pub)) &&
   3820         (GNUNET_OK == TALER_amount_cmp_currency (
   3821            &cmp->details_to_cmp[i].coin_value,
   3822            &details->coin_value)) &&
   3823         (0 == TALER_amount_cmp (&cmp->details_to_cmp[i].coin_value,
   3824                                 &details->coin_value)) &&
   3825         (GNUNET_OK == TALER_amount_cmp_currency (
   3826            &cmp->details_to_cmp[i].coin_fee,
   3827            &details->coin_fee)) &&
   3828         (0 == TALER_amount_cmp (&cmp->details_to_cmp[i].coin_fee,
   3829                                 &details->coin_fee)))
   3830     {
   3831       cmp->results_matching[i] += 1;
   3832     }
   3833   }
   3834   cmp->results_length += 1;
   3835 }
   3836 
   3837 
   3838 /**
   3839  * Tests looking up details for a wire transfer.
   3840  *
   3841  * @param exchange_url url to the exchange.
   3842  * @param wtid id of the transfer.
   3843  * @param details_length the length of @e details.
   3844  * @param details the details we expect to be returned.
   3845  * @return 1 on success, 0 otherwise.
   3846  */
   3847 static int
   3848 test_lookup_transfer_details (
   3849   const char *exchange_url,
   3850   const struct TALER_WireTransferIdentifierRawP *wtid,
   3851   unsigned int details_length,
   3852   const struct TALER_TrackTransferDetails *details)
   3853 {
   3854   unsigned int results_matching[details_length];
   3855   struct TestLookupTransferDetails_Closure cmp = {
   3856     .details_to_cmp_length = details_length,
   3857     .details_to_cmp = details,
   3858     .results_matching = results_matching,
   3859     .results_length = 0
   3860   };
   3861   memset (results_matching,
   3862           0,
   3863           sizeof (unsigned int) * details_length);
   3864   if (1 != TALER_MERCHANTDB_lookup_transfer_details (pg,
   3865                                                      exchange_url,
   3866                                                      wtid,
   3867                                                      &lookup_transfer_details_cb,
   3868                                                      &cmp))
   3869   {
   3870     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3871                 "Lookup transfer details failed\n");
   3872     return 1;
   3873   }
   3874   if (details_length != cmp.results_length)
   3875   {
   3876     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3877                 "Lookup transfer details failed: incorrect number of results (%d)\n",
   3878                 cmp.results_length);
   3879     return 1;
   3880   }
   3881   for (unsigned int i = 0; details_length > i; ++i)
   3882   {
   3883     if (1 != cmp.results_matching[i])
   3884     {
   3885       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3886                   "Lookup transfer details failed: mismatched data\n");
   3887       return 1;
   3888     }
   3889   }
   3890   return 0;
   3891 }
   3892 
   3893 
   3894 /**
   3895  * Closure for 'lookup_transfer_details_by_order'.
   3896  */
   3897 struct TestLookupTransferDetailsByOrder_Closure
   3898 {
   3899   /**
   3900    * Length of @e transfers_to_cmp.
   3901    */
   3902   unsigned int transfers_to_cmp_length;
   3903 
   3904   /**
   3905    * List of transfers that we expect to find.
   3906    */
   3907   const struct TransferData *transfers_to_cmp;
   3908 
   3909   /**
   3910    * How many results match the corresponding element of @e transfers_to_cmp.
   3911    */
   3912   unsigned int *results_matching;
   3913 
   3914   /**
   3915    * Total number of results found.
   3916    */
   3917   unsigned int results_length;
   3918 };
   3919 
   3920 
   3921 /**
   3922  * Called after 'test_lookup_transfer_details_by_order'.
   3923  *
   3924  * @param cls pointer to 'TestLookupTransferDetailsByOrder_Closure'.
   3925  * @param wtid identifier of the transfer found.
   3926  * @param exchange_url exchange url of the transfer found.
   3927  * @param execution_time when the transfer found occurred.
   3928  * @param deposit_value amount of the deposit for the transfer found.
   3929  * @param deposit_fee amount of the fee for the deposit of the transfer.
   3930  * @param transfer_confirmed did the merchant confirm that a wire transfer with
   3931  *        @a wtid over the total amount happened?
   3932  */
   3933 static void
   3934 lookup_transfer_details_order_cb (
   3935   void *cls,
   3936   const struct TALER_WireTransferIdentifierRawP *wtid,
   3937   const char *exchange_url,
   3938   struct GNUNET_TIME_Timestamp execution_time,
   3939   const struct TALER_Amount *deposit_value,
   3940   const struct TALER_Amount *deposit_fee,
   3941   bool transfer_confirmed,
   3942   uint64_t expected_transfer_serial_id)
   3943 {
   3944   struct TestLookupTransferDetailsByOrder_Closure *cmp = cls;
   3945 
   3946   if (NULL == cmp)
   3947     return;
   3948   cmp->results_length += 1;
   3949   for (unsigned int i = 0; i < cmp->transfers_to_cmp_length; ++i)
   3950   {
   3951     /* Right now lookup_transfer_details_by_order leaves execution_time
   3952        uninitialized */
   3953     if ((0 == GNUNET_memcmp (&cmp->transfers_to_cmp[i].wtid,
   3954                              wtid)) &&
   3955         (0 == strcmp (cmp->transfers_to_cmp[i].exchange_url,
   3956                       exchange_url)) &&
   3957         (GNUNET_OK ==
   3958          TALER_amount_cmp_currency (
   3959            &cmp->transfers_to_cmp[i].data.total_amount,
   3960            deposit_value)) &&
   3961         (0 ==
   3962          TALER_amount_cmp (&cmp->transfers_to_cmp[i].data.total_amount,
   3963                            deposit_value)) &&
   3964         (GNUNET_OK ==
   3965          TALER_amount_cmp_currency (
   3966            &cmp->transfers_to_cmp[i].deposit_fee,
   3967            deposit_fee)) &&
   3968         (0 ==
   3969          TALER_amount_cmp (&cmp->transfers_to_cmp[i].deposit_fee,
   3970                            deposit_fee)) )
   3971       cmp->results_matching[i] += 1;
   3972   }
   3973 }
   3974 
   3975 
   3976 /**
   3977  * Tests looking up wire transfers associated with an order.
   3978  *
   3979  * @param order_serial the order to be queried.
   3980  * @param transfers_length length of @e transfers.
   3981  * @param transfers the transfers we expect to be found.
   3982  * @return 0 on success, 1 otherwise.
   3983  */
   3984 static int
   3985 test_lookup_transfer_details_by_order (
   3986   uint64_t order_serial,
   3987   unsigned int transfers_length,
   3988   const struct TransferData *transfers)
   3989 {
   3990   unsigned int results_matching[transfers_length];
   3991   struct TestLookupTransferDetailsByOrder_Closure cmp = {
   3992     .transfers_to_cmp_length = transfers_length,
   3993     .transfers_to_cmp = transfers,
   3994     .results_matching = results_matching,
   3995     .results_length = 0
   3996   };
   3997   memset (results_matching,
   3998           0,
   3999           sizeof (unsigned int) * transfers_length);
   4000   if (transfers_length !=
   4001       TALER_MERCHANTDB_lookup_transfer_details_by_order (
   4002         pg,
   4003         order_serial,
   4004         &lookup_transfer_details_order_cb,
   4005         &cmp))
   4006   {
   4007     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4008                 "Lookup transfer details by order failed\n");
   4009     return 1;
   4010   }
   4011   if (transfers_length != cmp.results_length)
   4012   {
   4013     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4014                 "Lookup transfer details by order failed: incorrect number of results\n");
   4015     return 1;
   4016   }
   4017   for (unsigned int i = 0; i < transfers_length; ++i)
   4018   {
   4019     if (1 != cmp.results_matching[i])
   4020     {
   4021       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4022                   "Lookup transfer details by order failed: mismatched data\n");
   4023       return 1;
   4024     }
   4025   }
   4026   return 0;
   4027 }
   4028 
   4029 
   4030 /**
   4031  * Tests inserting wire fee data for an exchange.
   4032  *
   4033  * @param signkey the signing key for the exchange.
   4034  * @param wire_fee the wire fee data.
   4035  * @param expected_result what the database should return.
   4036  * @return 0 on success, 1 otherwise.
   4037  */
   4038 static int
   4039 test_insert_wire_fee (const struct ExchangeSignkeyData *signkey,
   4040                       const struct WireFeeData *wire_fee,
   4041                       enum GNUNET_DB_QueryStatus expected_result)
   4042 {
   4043   TEST_COND_RET_ON_FAIL (expected_result ==
   4044                          TALER_MERCHANTDB_store_wire_fee_by_exchange (
   4045                            pg,
   4046                            &signkey->master_pub,
   4047                            &wire_fee->h_wire_method,
   4048                            &wire_fee->fees,
   4049                            wire_fee->wire_fee_start,
   4050                            wire_fee->wire_fee_end,
   4051                            &wire_fee->fee_sig),
   4052                          "Store wire fee by exchange failed\n");
   4053   return 0;
   4054 }
   4055 
   4056 
   4057 /**
   4058  * Tests looking up wire fee data for an exchange.
   4059  *
   4060  * @param signkey the signing key to use for lookup.
   4061  * @param wire_fee_data the wire fee data we expect to find.
   4062  * @return 0 on success, 1 otherwise.
   4063  */
   4064 static int
   4065 test_lookup_wire_fee (const struct ExchangeSignkeyData *signkey,
   4066                       const struct WireFeeData *wire_fee_data)
   4067 {
   4068   struct TALER_WireFeeSet fees;
   4069   struct GNUNET_TIME_Timestamp start_date;
   4070   struct GNUNET_TIME_Timestamp end_date;
   4071   struct TALER_MasterSignatureP master_sig;
   4072   if (1 != TALER_MERCHANTDB_lookup_wire_fee (pg,
   4073                                              &signkey->master_pub,
   4074                                              wire_fee_data->wire_method,
   4075                                              GNUNET_TIME_timestamp_get (),
   4076                                              &fees,
   4077                                              &start_date,
   4078                                              &end_date,
   4079                                              &master_sig))
   4080   {
   4081     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4082                 "Lookup wire fee failed\n");
   4083     return 1;
   4084   }
   4085   if ((0 !=
   4086        TALER_wire_fee_set_cmp (&wire_fee_data->fees,
   4087                                &fees)) ||
   4088       (GNUNET_TIME_timestamp_cmp (wire_fee_data->wire_fee_start,
   4089                                   !=,
   4090                                   start_date)) ||
   4091       (GNUNET_TIME_timestamp_cmp (wire_fee_data->wire_fee_end,
   4092                                   !=,
   4093                                   end_date)) ||
   4094       (0 != GNUNET_memcmp (&wire_fee_data->fee_sig,
   4095                            &master_sig)))
   4096   {
   4097     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4098                 "Lookup wire fee failed: mismatched data\n");
   4099     return 1;
   4100   }
   4101   return 0;
   4102 }
   4103 
   4104 
   4105 /**
   4106  * Closure for 'lookup_transfers'.
   4107  */
   4108 struct TestLookupTransfers_Closure
   4109 {
   4110   /**
   4111    * Length of @e transfers_to_cmp.
   4112    */
   4113   unsigned int transfers_to_cmp_length;
   4114 
   4115   /**
   4116    * The transfers we expect to find.
   4117    */
   4118   const struct TransferData *transfers_to_cmp;
   4119 
   4120   /**
   4121    * Number of results matching each transfer.
   4122    */
   4123   unsigned int *results_matching;
   4124 
   4125   /**
   4126    * Total number of results found.
   4127    */
   4128   unsigned int results_length;
   4129 };
   4130 
   4131 
   4132 /**
   4133  * Function called after 'test_lookup_transfers'.
   4134  *
   4135  * @param cls pointer to 'TestLookupTransfers_Closure'.
   4136  * @param credit_amount how much was wired to the merchant (minus fees)
   4137  * @param wtid wire transfer identifier
   4138  * @param payto_uri target account that received the wire transfer
   4139  * @param exchange_url base URL of the exchange that made the wire transfer
   4140  * @param transfer_serial_id serial number identifying the transfer in the backend
   4141  * @param expected_transfer_serial_id serial number identifying the expected transfer in the backend, 0 if not @a expected
   4142  * @param execution_time when did the exchange make the transfer, #GNUNET_TIME_UNIT_FOREVER_TS
   4143  *           if it did not yet happen
   4144  * @param expected true if the merchant acknowledged the wire transfer reception
   4145  */
   4146 static void
   4147 lookup_transfers_cb (void *cls,
   4148                      const struct TALER_Amount *credit_amount,
   4149                      const struct TALER_WireTransferIdentifierRawP *wtid,
   4150                      struct TALER_FullPayto payto_uri,
   4151                      const char *exchange_url,
   4152                      uint64_t transfer_serial_id,
   4153                      uint64_t expected_transfer_serial_id,
   4154                      struct GNUNET_TIME_Absolute execution_time,
   4155                      bool expected)
   4156 {
   4157   struct TestLookupTransfers_Closure *cmp = cls;
   4158   if (NULL == cmp)
   4159     return;
   4160   for (unsigned int i = 0; cmp->transfers_to_cmp_length > i; ++i)
   4161   {
   4162     if ( (GNUNET_OK ==
   4163           TALER_amount_cmp_currency (
   4164             &cmp->transfers_to_cmp[i].data.total_amount,
   4165             credit_amount)) &&
   4166          (0 == TALER_amount_cmp (&cmp->transfers_to_cmp[i].data.total_amount,
   4167                                  credit_amount)) )
   4168     {
   4169       cmp->results_matching[i]++;
   4170     }
   4171   }
   4172   cmp->results_length++;
   4173 }
   4174 
   4175 
   4176 /**
   4177  * Tests looking up transfers from the database.
   4178  *
   4179  * @param instance the instance to lookup from.
   4180  * @param account the account the transfer was made to.
   4181  * @param before do not return transfers before this time.
   4182  * @param after do not return transfers after this time.
   4183  * @param limit maximum number of transfers to return.
   4184  * @param offset row in the database to start with.
   4185  * @param filter_verified how to filter verified transfers.
   4186  * @param transfers_length length of @e transfers.
   4187  * @param transfers the transfers we expect to find.
   4188  * @return 0 on success, 1 otherwise.
   4189  */
   4190 static int
   4191 test_lookup_transfers (const struct InstanceData *instance,
   4192                        const struct TALER_MERCHANTDB_AccountDetails *account,
   4193                        struct GNUNET_TIME_Timestamp before,
   4194                        struct GNUNET_TIME_Timestamp after,
   4195                        int64_t limit,
   4196                        uint64_t offset,
   4197                        unsigned int transfers_length,
   4198                        const struct TransferData *transfers)
   4199 {
   4200   unsigned int results_matching[transfers_length];
   4201   struct TestLookupTransfers_Closure cmp = {
   4202     .transfers_to_cmp_length = transfers_length,
   4203     .transfers_to_cmp = transfers,
   4204     .results_matching = results_matching,
   4205     .results_length = 0
   4206   };
   4207   memset (results_matching,
   4208           0,
   4209           sizeof (unsigned int) * transfers_length);
   4210   if (1 != TALER_MERCHANTDB_lookup_transfers (pg,
   4211                                               instance->instance.id,
   4212                                               account->payto_uri,
   4213                                               before,
   4214                                               after,
   4215                                               limit,
   4216                                               offset,
   4217                                               TALER_EXCHANGE_YNA_ALL,
   4218                                               &lookup_transfers_cb,
   4219                                               &cmp))
   4220   {
   4221     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4222                 "Lookup transfers failed\n");
   4223     return 1;
   4224   }
   4225   if (transfers_length != cmp.results_length)
   4226   {
   4227     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4228                 "Lookup transfers failed: incorrect number of results\n");
   4229     return 1;
   4230   }
   4231   for (unsigned int i = 0; transfers_length > i; ++i)
   4232   {
   4233     if (1 != cmp.results_matching[i])
   4234     {
   4235       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4236                   "Lookup transfers failed: mismatched data\n");
   4237       return 1;
   4238     }
   4239   }
   4240   return 0;
   4241 }
   4242 
   4243 
   4244 /**
   4245  * Tests inserting a transfer into the database.
   4246  *
   4247  * @param instance the instance to use.
   4248  * @param account the account to transfer to.
   4249  * @param transfer the transfer to insert.
   4250  * @param expected_result the result we expect the db to return.
   4251  * @return 0 on success, 1 otherwise.
   4252  */
   4253 static int
   4254 test_insert_transfer (const struct InstanceData *instance,
   4255                       const struct TALER_MERCHANTDB_AccountDetails *account,
   4256                       const struct TransferData *transfer,
   4257                       enum GNUNET_DB_QueryStatus expected_result)
   4258 {
   4259   bool no_instance;
   4260   bool no_account;
   4261   bool conflict;
   4262 
   4263   TEST_COND_RET_ON_FAIL (expected_result ==
   4264                          TALER_MERCHANTDB_insert_transfer (pg,
   4265                                                            instance->instance.id,
   4266                                                            transfer->exchange_url,
   4267                                                            &transfer->wtid,
   4268                                                            &transfer->data.total_amount,
   4269                                                            account->payto_uri,
   4270                                                            transfer->confirmed,
   4271                                                            &no_instance,
   4272                                                            &no_account,
   4273                                                            &conflict),
   4274                          "Insert transfer failed\n");
   4275   return 0;
   4276 }
   4277 
   4278 
   4279 /**
   4280  * Tests linking a deposit to a transfer.
   4281  *
   4282  * @param instance the instance that the deposit and transfer are for.
   4283  * @param signkey the signing used on the deposit.
   4284  * @param order the order the deposit and transfer were made for.
   4285  * @param transfer the transfer.
   4286  * @param expected_result the result the database should return.
   4287  * @param expected_cleared clearance status the database should return.
   4288  * @return 0 on success, 1 otherwise.
   4289  */
   4290 static int
   4291 test_insert_deposit_to_transfer (const struct InstanceData *instance,
   4292                                  const struct ExchangeSignkeyData *signkey,
   4293                                  const struct OrderData *order,
   4294                                  const struct DepositData *deposit,
   4295                                  const struct TransferData *transfer,
   4296                                  enum GNUNET_DB_QueryStatus expected_result,
   4297                                  bool expect_cleared)
   4298 {
   4299   const struct TALER_EXCHANGE_DepositData deposit_data = {
   4300     .exchange_pub = signkey->exchange_pub,
   4301     .exchange_sig = deposit->exchange_sig,
   4302     .wtid = transfer->wtid,
   4303     .execution_time = transfer->data.execution_time,
   4304     .coin_contribution = deposit->amount_with_fee
   4305   };
   4306   uint64_t deposit_serial = get_deposit_serial (instance,
   4307                                                 order,
   4308                                                 deposit);
   4309 
   4310   TEST_COND_RET_ON_FAIL (expected_result ==
   4311                          TALER_MERCHANTDB_insert_deposit_to_transfer (
   4312                            pg,
   4313                            deposit_serial,
   4314                            &deposit->h_wire,
   4315                            deposit->exchange_url,
   4316                            &deposit_data),
   4317                          "insert deposit to transfer failed\n");
   4318   return 0;
   4319 }
   4320 
   4321 
   4322 /**
   4323  * Inserts details for a transfer into the database.
   4324  *
   4325  * @param instance the instance the transfer is in.
   4326  * @param account the destination account for the transfer.
   4327  * @param transfer the transfer we are adding details to.
   4328  * @param expected_result the result expected from the db.
   4329  * @return 0 on success, 1 otherwise.
   4330  */
   4331 static int
   4332 test_insert_transfer_details (
   4333   const struct InstanceData *instance,
   4334   const struct TALER_MERCHANTDB_AccountDetails *account,
   4335   const struct TransferData *transfer,
   4336   enum GNUNET_DB_QueryStatus expected_result)
   4337 {
   4338   TEST_COND_RET_ON_FAIL (expected_result ==
   4339                          TALER_MERCHANTDB_insert_transfer_details (
   4340                            pg,
   4341                            instance->instance.id,
   4342                            transfer->exchange_url,
   4343                            account->payto_uri,
   4344                            &transfer->wtid,
   4345                            &transfer->data),
   4346                          "Insert transfer details failed\n");
   4347   return 0;
   4348 }
   4349 
   4350 
   4351 /**
   4352  * Container for data used when testing transfers.
   4353  */
   4354 struct TestTransfers_Closure
   4355 {
   4356   /**
   4357    * The instance.
   4358    */
   4359   struct InstanceData instance;
   4360 
   4361   /**
   4362    * The account.
   4363    */
   4364   struct TALER_MERCHANTDB_AccountDetails account;
   4365 
   4366   /**
   4367    * The exchange signing key.
   4368    */
   4369   struct ExchangeSignkeyData signkey;
   4370 
   4371   /**
   4372    * The order data.
   4373    */
   4374   struct OrderData order;
   4375 
   4376   /**
   4377    * The deposit data.
   4378    */
   4379   struct DepositData deposit;
   4380 
   4381   /**
   4382    * Wire fee data.
   4383    */
   4384   struct WireFeeData wire_fee[2];
   4385 
   4386   /**
   4387    * The transfers.
   4388    */
   4389   struct TransferData transfers[1];
   4390 };
   4391 
   4392 
   4393 /**
   4394  * Prepares for testing transfers.
   4395  *
   4396  * @param cls the test data.
   4397  */
   4398 static void
   4399 pre_test_transfers (struct TestTransfers_Closure *cls)
   4400 {
   4401   /* Instance */
   4402   make_instance ("test_inst_transfers",
   4403                  &cls->instance);
   4404 
   4405   /* Account */
   4406   make_account (&cls->account);
   4407   cls->account.instance_id = cls->instance.instance.id;
   4408   /* Order */
   4409   make_order ("test_transfers_od_1",
   4410               &cls->order);
   4411 
   4412   /* Signing key */
   4413   make_exchange_signkey (&cls->signkey);
   4414 
   4415   /* Deposit */
   4416   make_deposit (&cls->instance,
   4417                 &cls->account,
   4418                 &cls->order,
   4419                 &cls->signkey,
   4420                 &cls->deposit);
   4421 
   4422   /* Wire fee */
   4423   make_wire_fee (&cls->signkey,
   4424                  &cls->wire_fee[0]);
   4425   make_wire_fee (&cls->signkey,
   4426                  &cls->wire_fee[1]);
   4427   cls->wire_fee[1].wire_method = "wire-method-2";
   4428   GNUNET_CRYPTO_hash (cls->wire_fee[1].wire_method,
   4429                       strlen (cls->wire_fee[1].wire_method) + 1,
   4430                       &cls->wire_fee[1].h_wire_method);
   4431 
   4432   /* Transfers */
   4433   make_transfer (&cls->signkey,
   4434                  1,
   4435                  &cls->deposit,
   4436                  &cls->transfers[0]);
   4437   cls->transfers[0].confirmed = true;
   4438 }
   4439 
   4440 
   4441 /**
   4442  * Cleans up after testing transfers.
   4443  *
   4444  * @param cls the test data.
   4445  */
   4446 static void
   4447 post_test_transfers (struct TestTransfers_Closure *cls)
   4448 {
   4449   GNUNET_array_grow (cls->transfers->data.details,
   4450                      cls->transfers->data.details_length,
   4451                      0);
   4452   free_instance_data (&cls->instance);
   4453   free_order_data (&cls->order);
   4454 }
   4455 
   4456 
   4457 /**
   4458  * Runs the tests for transfers.
   4459  *
   4460  * @param cls the test data.
   4461  * @return 0 on success, 1 otherwise.
   4462  */
   4463 static int
   4464 run_test_transfers (struct TestTransfers_Closure *cls)
   4465 {
   4466   uint64_t order_serial;
   4467   struct TALER_WireFeeSet fees;
   4468 
   4469   /* Test lookup wire fee fails when it isn't in the db */
   4470   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS ==
   4471                          TALER_MERCHANTDB_lookup_wire_fee (pg,
   4472                                                            &cls->signkey.master_pub,
   4473                                                            cls->wire_fee[0].wire_method,
   4474                                                            GNUNET_TIME_timestamp_get (),
   4475                                                            &fees,
   4476                                                            NULL,
   4477                                                            NULL,
   4478                                                            NULL),
   4479                          "Lookup wire fee failed\n");
   4480   /* Test store wire fee by exchange */
   4481   TEST_RET_ON_FAIL (test_insert_wire_fee (&cls->signkey,
   4482                                           &cls->wire_fee[0],
   4483                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4484   /* Test double insertion fails */
   4485   TEST_RET_ON_FAIL (test_insert_wire_fee (&cls->signkey,
   4486                                           &cls->wire_fee[0],
   4487                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   4488   /* Test lookup wire fee by exchange */
   4489   TEST_RET_ON_FAIL (test_lookup_wire_fee (&cls->signkey,
   4490                                           &cls->wire_fee[0]));
   4491   /* Test different wire fees for different methods. */
   4492   TEST_RET_ON_FAIL (test_insert_wire_fee (&cls->signkey,
   4493                                           &cls->wire_fee[1],
   4494                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4495   TEST_RET_ON_FAIL (test_lookup_wire_fee (&cls->signkey,
   4496                                           &cls->wire_fee[1]));
   4497   /* Insert the instance */
   4498   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   4499                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4500   /* Insert the account */
   4501   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   4502                                          &cls->account,
   4503                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4504   /* Insert a signing key */
   4505   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   4506                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4507   /* Insert an order */
   4508   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   4509                                        &cls->order,
   4510                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4511   /* Insert contract terms */
   4512   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   4513                                                 &cls->order,
   4514                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4515   order_serial = get_order_serial (&cls->instance,
   4516                                    &cls->order);
   4517   /* Insert the deposit */
   4518   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   4519                                          &cls->signkey,
   4520                                          &cls->deposit,
   4521                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4522   /* Insert the transfer */
   4523   TEST_RET_ON_FAIL (test_insert_transfer (&cls->instance,
   4524                                           &cls->account,
   4525                                           &cls->transfers[0],
   4526                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4527   TEST_RET_ON_FAIL (test_insert_transfer (&cls->instance,
   4528                                           &cls->account,
   4529                                           &cls->transfers[0],
   4530                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT))
   4531   ;
   4532   TEST_RET_ON_FAIL (test_insert_deposit_to_transfer (&cls->instance,
   4533                                                      &cls->signkey,
   4534                                                      &cls->order,
   4535                                                      &cls->deposit,
   4536                                                      &cls->transfers[0],
   4537                                                      GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   4538                                                      false));
   4539   TEST_RET_ON_FAIL (test_insert_deposit_to_transfer (&cls->instance,
   4540                                                      &cls->signkey,
   4541                                                      &cls->order,
   4542                                                      &cls->deposit,
   4543                                                      &cls->transfers[0],
   4544                                                      GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   4545                                                      false));
   4546   TEST_RET_ON_FAIL (test_insert_transfer_details (&cls->instance,
   4547                                                   &cls->account,
   4548                                                   &cls->transfers[0],
   4549                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4550   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   4551                                                 cls->order.id,
   4552                                                 NULL,
   4553                                                 false,
   4554                                                 false));
   4555   TEST_RET_ON_FAIL (test_insert_deposit_to_transfer (&cls->instance,
   4556                                                      &cls->signkey,
   4557                                                      &cls->order,
   4558                                                      &cls->deposit,
   4559                                                      &cls->transfers[0],
   4560                                                      GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   4561                                                      true));
   4562 
   4563   TEST_RET_ON_FAIL (test_lookup_transfer_summary (cls->deposit.exchange_url,
   4564                                                   &cls->transfers[0].wtid,
   4565                                                   cls->order.id,
   4566                                                   &cls->deposit.amount_with_fee,
   4567                                                   &cls->deposit.deposit_fee));
   4568   TEST_RET_ON_FAIL (test_lookup_transfer_details (cls->deposit.exchange_url,
   4569                                                   &cls->transfers[0].wtid,
   4570                                                   1,
   4571                                                   &cls->transfers[0].data.
   4572                                                   details[0]));
   4573   TEST_RET_ON_FAIL (test_lookup_transfer_details_by_order (order_serial,
   4574                                                            1,
   4575                                                            &cls->transfers[0]));
   4576   TEST_RET_ON_FAIL (test_lookup_transfers (&cls->instance,
   4577                                            &cls->account,
   4578                                            GNUNET_TIME_UNIT_FOREVER_TS,
   4579                                            GNUNET_TIME_UNIT_ZERO_TS,
   4580                                            8,
   4581                                            0,
   4582                                            1,
   4583                                            &cls->transfers[0]));
   4584   return 0;
   4585 }
   4586 
   4587 
   4588 /**
   4589  * Takes care of all work for testing transfers.
   4590  *
   4591  * @return 0 on success, 1 otherwise.
   4592  */
   4593 static int
   4594 test_transfers (void)
   4595 {
   4596   struct TestTransfers_Closure test_cls;
   4597   int test_result;
   4598 
   4599   pre_test_transfers (&test_cls);
   4600   test_result = run_test_transfers (&test_cls);
   4601   post_test_transfers (&test_cls);
   4602   return test_result;
   4603 }
   4604 
   4605 
   4606 /**
   4607  * Closure for testing lookup_refunds.
   4608  */
   4609 struct TestLookupRefunds_Closure
   4610 {
   4611   /**
   4612    * Length of @e coin_pub_to_cmp and @e refund_amount_to_cmp.
   4613    */
   4614   unsigned int refunds_to_cmp_length;
   4615 
   4616   /**
   4617    * Public keys of the refunded coins.
   4618    */
   4619   const struct TALER_CoinSpendPublicKeyP *coin_pub_to_cmp;
   4620 
   4621   /**
   4622    * Amount of each refund.
   4623    */
   4624   const struct TALER_Amount *refund_amount_to_cmp;
   4625 
   4626   /**
   4627    * Number of results matching each refund provided.
   4628    */
   4629   unsigned int *results_matching;
   4630 
   4631   /**
   4632    * Total number of results returned;
   4633    */
   4634   unsigned int results_length;
   4635 };
   4636 
   4637 
   4638 /**
   4639  * Called after test_lookup_refunds.
   4640  * @param cls pointer to a TestLookupRefunds_Closure.
   4641  * @param coin_pub the public key of the coin for the refund found.
   4642  * @param refund_amount the amount of the refund found.
   4643  */
   4644 static void
   4645 lookup_refunds_cb (void *cls,
   4646                    const struct TALER_CoinSpendPublicKeyP *coin_pub,
   4647                    const struct TALER_Amount *refund_amount)
   4648 {
   4649   struct TestLookupRefunds_Closure *cmp = cls;
   4650   if (NULL == cmp)
   4651     return;
   4652   cmp->results_length += 1;
   4653   for (unsigned int i = 0; cmp->refunds_to_cmp_length > i; ++i)
   4654   {
   4655     if ((0 == GNUNET_memcmp (&cmp->coin_pub_to_cmp[i],
   4656                              coin_pub)) &&
   4657         (GNUNET_OK == TALER_amount_cmp_currency (&cmp->refund_amount_to_cmp[i],
   4658                                                  refund_amount)) &&
   4659         (0 == TALER_amount_cmp (&cmp->refund_amount_to_cmp[i],
   4660                                 refund_amount)))
   4661     {
   4662       cmp->results_matching[i] += 1;
   4663     }
   4664   }
   4665 }
   4666 
   4667 
   4668 /**
   4669  * Tests looking up refunds from the database.
   4670  * @param instance the instance to look up refunds for.
   4671  * @param h_contract_terms hash of the contract terms the refunds are for.
   4672  * @param refunds_length length of @e coin_pubs and @e refund_amounts.
   4673  * @param coin_pubs the public keys of the coins that were refunded.
   4674  * @param refund_amounts the amounts of the coins that were refunded.
   4675  *
   4676  * @return 0 on success, 1 otherwise.
   4677  */
   4678 static int
   4679 test_lookup_refunds (const struct InstanceData *instance,
   4680                      const struct TALER_PrivateContractHashP *h_contract_terms,
   4681                      unsigned int refunds_length,
   4682                      const struct TALER_CoinSpendPublicKeyP *coin_pubs,
   4683                      const struct TALER_Amount *refund_amounts)
   4684 {
   4685   unsigned int results_matching[refunds_length];
   4686   struct TestLookupRefunds_Closure cmp = {
   4687     .refunds_to_cmp_length = refunds_length,
   4688     .coin_pub_to_cmp = coin_pubs,
   4689     .refund_amount_to_cmp = refund_amounts,
   4690     .results_matching = results_matching,
   4691     .results_length = 0
   4692   };
   4693   memset (results_matching, 0, sizeof (unsigned int) * refunds_length);
   4694   if (1 != TALER_MERCHANTDB_lookup_refunds (pg,
   4695                                             instance->instance.id,
   4696                                             h_contract_terms,
   4697                                             &lookup_refunds_cb,
   4698                                             &cmp))
   4699   {
   4700     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4701                 "Lookup refunds failed\n");
   4702     return 1;
   4703   }
   4704   if (refunds_length != cmp.results_length)
   4705   {
   4706     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4707                 "Lookup refunds failed: incorrect number of results returned\n")
   4708     ;
   4709     return 1;
   4710   }
   4711   for (unsigned int i = 0; refunds_length > i; ++i)
   4712   {
   4713     if (1 != cmp.results_matching[i])
   4714     {
   4715       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4716                   "Lookup refunds failed: mismatched data\n");
   4717       return 1;
   4718     }
   4719   }
   4720   return 0;
   4721 }
   4722 
   4723 
   4724 /**
   4725  * Container for refund data.
   4726  */
   4727 struct RefundData
   4728 {
   4729   /**
   4730    * When the refund occurred.
   4731    */
   4732   struct GNUNET_TIME_Timestamp timestamp;
   4733 
   4734   /**
   4735    * Reason for the refund.
   4736    */
   4737   const char *reason;
   4738 
   4739   /**
   4740    * Amount of the refund.
   4741    */
   4742   struct TALER_Amount refund_amount;
   4743 
   4744   /**
   4745    * Public key of the coin that was refunded.
   4746    */
   4747   const struct TALER_CoinSpendPublicKeyP *coin_pub;
   4748 
   4749   /**
   4750    * URL to the exchange that did the refund.
   4751    */
   4752   const char *exchange_url;
   4753 };
   4754 
   4755 
   4756 /**
   4757  * Creates a refund for testing with.
   4758  * @param deposit the deposit being refunded.
   4759  * @param refund the data to set.
   4760  */
   4761 static void
   4762 make_refund (const struct DepositData *deposit,
   4763              struct RefundData *refund)
   4764 {
   4765   refund->timestamp = GNUNET_TIME_timestamp_get ();
   4766   refund->reason = "some reason";
   4767   refund->refund_amount = deposit->amount_with_fee;
   4768   refund->coin_pub = &deposit->coin_pub;
   4769   refund->exchange_url = deposit->exchange_url;
   4770 }
   4771 
   4772 
   4773 /**
   4774  * Container for proof of a refund.
   4775  */
   4776 struct RefundProofData
   4777 {
   4778   /**
   4779    * Fee charged for the refund.
   4780    */
   4781   struct TALER_Amount refund_fee;
   4782 
   4783   /**
   4784    * The exchange's signature on the refund.
   4785    */
   4786   struct TALER_ExchangeSignatureP exchange_sig;
   4787 };
   4788 
   4789 
   4790 /**
   4791  * Closure for testing lookup_refunds_detailed.
   4792  */
   4793 struct TestLookupRefundsDetailed_Closure
   4794 {
   4795   /**
   4796    * Length of @e refunds_to_cmp.
   4797    */
   4798   unsigned int refunds_to_cmp_length;
   4799 
   4800   /**
   4801    * The refunds we expect to find.
   4802    */
   4803   const struct RefundData *refunds_to_cmp;
   4804 
   4805   /**
   4806    * Whether to compare the timestamps or not (if we don't have direct control
   4807    * of the timestamps, there will be differences on the order of microseconds
   4808    * that can be ignored).
   4809    */
   4810   bool cmp_timestamps;
   4811 
   4812   /**
   4813    * The number of results matching each refund.
   4814    */
   4815   unsigned int *results_matching;
   4816 
   4817   /**
   4818    * The total number of results from the db.
   4819    */
   4820   unsigned int results_length;
   4821 };
   4822 
   4823 
   4824 /**
   4825  * Called after test_lookup_refunds_detailed.
   4826  * @param cls pointer to a TestLookupRefundsDetailed_Closure.
   4827  * @param refund_serial unique serial number of the refund
   4828  * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
   4829  * @param coin_pub public coin from which the refund comes from
   4830  * @param exchange_url URL of the exchange that issued @a coin_pub
   4831  * @param rtransaction_id identificator of the refund
   4832  * @param reason human-readable explanation of the refund
   4833  * @param refund_amount refund amount which is being taken from @a coin_pub
   4834  * @param pending true if this refund has not been processed by the wallet/exchange
   4835  */
   4836 static void
   4837 lookup_refunds_detailed_cb (void *cls,
   4838                             uint64_t refund_serial,
   4839                             struct GNUNET_TIME_Timestamp timestamp,
   4840                             const struct TALER_CoinSpendPublicKeyP *coin_pub,
   4841                             const char *exchange_url,
   4842                             uint64_t rtransaction_id,
   4843                             const char *reason,
   4844                             const struct TALER_Amount *refund_amount,
   4845                             bool pending)
   4846 {
   4847   struct TestLookupRefundsDetailed_Closure *cmp = cls;
   4848   if (NULL == cmp)
   4849     return;
   4850   cmp->results_length += 1;
   4851   for (unsigned int i = 0; cmp->refunds_to_cmp_length > i; ++i)
   4852   {
   4853     if (((GNUNET_TIME_timestamp_cmp (cmp->refunds_to_cmp[i].timestamp,
   4854                                      ==,
   4855                                      timestamp)) ||
   4856          ! cmp->cmp_timestamps) &&
   4857         (0 == GNUNET_memcmp (cmp->refunds_to_cmp[i].coin_pub,
   4858                              coin_pub)) &&
   4859         (0 == strcmp (cmp->refunds_to_cmp[i].exchange_url,
   4860                       exchange_url)) &&
   4861         (0 == strcmp (cmp->refunds_to_cmp[i].reason,
   4862                       reason)) &&
   4863         (GNUNET_OK ==
   4864          TALER_amount_cmp_currency (
   4865            &cmp->refunds_to_cmp[i].refund_amount,
   4866            refund_amount)) &&
   4867         (0 == TALER_amount_cmp (&cmp->refunds_to_cmp[i].refund_amount,
   4868                                 refund_amount)))
   4869     {
   4870       cmp->results_matching[i] += 1;
   4871     }
   4872   }
   4873 }
   4874 
   4875 
   4876 /**
   4877  * Tests looking up refunds with details from the database.
   4878  * @param instance the instance to lookup from.
   4879  * @param h_contract_terms the contract terms the refunds were made for.
   4880  * @param cmp_timestamps whether to compare timestamps or not.
   4881  * @param refunds_length length of @e refunds.
   4882  * @param refunds the refunds we expect to be returned.
   4883  *
   4884  * @return 0 on success, 1 otherwise.
   4885  */
   4886 static int
   4887 test_lookup_refunds_detailed (
   4888   const struct InstanceData *instance,
   4889   const struct TALER_PrivateContractHashP *h_contract_terms,
   4890   bool cmp_timestamps,
   4891   unsigned int refunds_length,
   4892   const struct RefundData *refunds)
   4893 {
   4894   unsigned int results_matching[refunds_length];
   4895   struct TestLookupRefundsDetailed_Closure cmp = {
   4896     .refunds_to_cmp_length = refunds_length,
   4897     .refunds_to_cmp = refunds,
   4898     .cmp_timestamps = cmp_timestamps,
   4899     .results_matching = results_matching,
   4900     .results_length = 0
   4901   };
   4902   memset (results_matching, 0, sizeof (unsigned int) * refunds_length);
   4903   if (0 > TALER_MERCHANTDB_lookup_refunds_detailed (pg,
   4904                                                     instance->instance.id,
   4905                                                     h_contract_terms,
   4906                                                     &lookup_refunds_detailed_cb,
   4907                                                     &cmp))
   4908   {
   4909     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4910                 "Lookup refunds detailed failed\n");
   4911     return 1;
   4912   }
   4913   if (refunds_length != cmp.results_length)
   4914   {
   4915     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4916                 "Lookup refunds detailed failed: incorrect number of results\n")
   4917     ;
   4918     return 1;
   4919   }
   4920   for (unsigned int i = 0; refunds_length > i; ++i)
   4921   {
   4922     if (1 != cmp.results_matching[i])
   4923     {
   4924       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4925                   "Lookup refunds detailed failed: mismatched data\n");
   4926       return 1;
   4927     }
   4928   }
   4929   return 0;
   4930 }
   4931 
   4932 
   4933 /**
   4934  * Closure for get_refund_serial.
   4935  */
   4936 struct LookupRefundSerial_Closure
   4937 {
   4938   /**
   4939    * The refund we are looking up the id for.
   4940    */
   4941   const struct RefundData *refund;
   4942 
   4943   /**
   4944    * The row number found.
   4945    */
   4946   uint64_t serial;
   4947 };
   4948 
   4949 
   4950 /**
   4951  * Called after get_refund_serial.
   4952  * @param cls pointer to a LookupRefundSerial_Closure.
   4953  * @param refund_serial unique serial number of the refund
   4954  * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
   4955  * @param coin_pub public coin from which the refund comes from
   4956  * @param exchange_url URL of the exchange that issued @a coin_pub
   4957  * @param rtransaction_id identificator of the refund
   4958  * @param reason human-readable explanation of the refund
   4959  * @param refund_amount refund amount which is being taken from @a coin_pub
   4960  * @param pending true if this refund has not been processed by the wallet/exchange
   4961  */
   4962 static void
   4963 get_refund_serial_cb (void *cls,
   4964                       uint64_t refund_serial,
   4965                       struct GNUNET_TIME_Timestamp timestamp,
   4966                       const struct TALER_CoinSpendPublicKeyP *coin_pub,
   4967                       const char *exchange_url,
   4968                       uint64_t rtransaction_id,
   4969                       const char *reason,
   4970                       const struct TALER_Amount *refund_amount,
   4971                       bool pending)
   4972 {
   4973   struct LookupRefundSerial_Closure *lookup_cls = cls;
   4974   if (NULL == lookup_cls)
   4975     return;
   4976   if ((GNUNET_TIME_timestamp_cmp (lookup_cls->refund->timestamp,
   4977                                   ==,
   4978                                   timestamp)) &&
   4979       (0 == GNUNET_memcmp (lookup_cls->refund->coin_pub,
   4980                            coin_pub)) &&
   4981       (0 == strcmp (lookup_cls->refund->exchange_url,
   4982                     exchange_url)) &&
   4983       (0 == strcmp (lookup_cls->refund->reason,
   4984                     reason)) &&
   4985       (GNUNET_OK ==
   4986        TALER_amount_cmp_currency (
   4987          &lookup_cls->refund->refund_amount,
   4988          refund_amount)) &&
   4989       (0 == TALER_amount_cmp (&lookup_cls->refund->refund_amount,
   4990                               refund_amount)))
   4991     lookup_cls->serial = refund_serial;
   4992 }
   4993 
   4994 
   4995 /**
   4996  * Utility function for getting the database row number of a refund.
   4997  * @param instance the instance associated with the refund.
   4998  * @param h_contract_terms the contract terms the refund was made with.
   4999  * @param refund the refund we are querying the row number of.
   5000  *
   5001  * @return the row number of the refund.
   5002  */
   5003 static uint64_t
   5004 get_refund_serial (const struct InstanceData *instance,
   5005                    const struct TALER_PrivateContractHashP *h_contract_terms,
   5006                    const struct RefundData *refund)
   5007 {
   5008   struct LookupRefundSerial_Closure lookup_cls = {
   5009     .refund = refund,
   5010     .serial = 0
   5011   };
   5012 
   5013   GNUNET_assert (0 < TALER_MERCHANTDB_lookup_refunds_detailed (pg,
   5014                                                                instance->instance.id,
   5015                                                                h_contract_terms,
   5016                                                                &get_refund_serial_cb,
   5017                                                                &lookup_cls));
   5018   GNUNET_assert (0 != lookup_cls.serial);
   5019 
   5020   return lookup_cls.serial;
   5021 }
   5022 
   5023 
   5024 /**
   5025  * Tests looking up proof of a refund.
   5026  * @param refund_serial the row number of the refund.
   5027  * @param expected_exchange_sig the exchange signature we are expecting.
   5028  * @param expected_exchange_pub the exchange public key we are expecting.
   5029  *
   5030  * @return 0 on success, 1 otherwise.
   5031  */
   5032 static int
   5033 test_lookup_refund_proof (uint64_t refund_serial,
   5034                           const struct
   5035                           TALER_ExchangeSignatureP *expected_exchange_sig,
   5036                           const struct
   5037                           TALER_ExchangePublicKeyP *expected_exchange_pub)
   5038 {
   5039   struct TALER_ExchangeSignatureP exchange_sig;
   5040   struct TALER_ExchangePublicKeyP exchange_pub;
   5041   if (1 != TALER_MERCHANTDB_lookup_refund_proof (pg,
   5042                                                  refund_serial,
   5043                                                  &exchange_sig,
   5044                                                  &exchange_pub))
   5045   {
   5046     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5047                 "Lookup refund proof failed\n");
   5048     return 1;
   5049   }
   5050   if ((0 != GNUNET_memcmp (expected_exchange_sig,
   5051                            &exchange_sig)) ||
   5052       (0 != GNUNET_memcmp (expected_exchange_pub,
   5053                            &exchange_pub)))
   5054   {
   5055     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5056                 "Lookup refund proof failed: mismatched data\n");
   5057     return 1;
   5058   }
   5059   return 0;
   5060 }
   5061 
   5062 
   5063 /**
   5064  * Closure for testing refund functionality.
   5065  */
   5066 struct TestRefunds_Closure
   5067 {
   5068   /**
   5069    * The instance.
   5070    */
   5071   struct InstanceData instance;
   5072 
   5073   /**
   5074    * The merchant account.
   5075    */
   5076   struct TALER_MERCHANTDB_AccountDetails account;
   5077 
   5078   /**
   5079    * The exchange signing key.
   5080    */
   5081   struct ExchangeSignkeyData signkey;
   5082 
   5083   /**
   5084    * The order data.
   5085    */
   5086   struct OrderData orders[2];
   5087 
   5088   /**
   5089    * The deposit data.
   5090    */
   5091   struct DepositData deposits[3];
   5092 
   5093   /**
   5094    * The refund data.
   5095    */
   5096   struct RefundData refunds[3];
   5097 
   5098   /**
   5099    * The refund proof data.
   5100    */
   5101   struct RefundProofData refund_proof;
   5102 };
   5103 
   5104 
   5105 /**
   5106  * Prepares for testing refunds.
   5107  * @param cls the closure to initialize.
   5108  */
   5109 static void
   5110 pre_test_refunds (struct TestRefunds_Closure *cls)
   5111 {
   5112   /* Instance */
   5113   make_instance ("test_inst_refunds",
   5114                  &cls->instance);
   5115 
   5116   /* Account */
   5117   make_account (&cls->account);
   5118   cls->account.instance_id = cls->instance.instance.id;
   5119   /* Signing key */
   5120   make_exchange_signkey (&cls->signkey);
   5121 
   5122   /* Order */
   5123   make_order ("test_refunds_od_0",
   5124               &cls->orders[0]);
   5125   make_order ("test_refunds_od_1",
   5126               &cls->orders[1]);
   5127 
   5128   /* Deposit */
   5129   make_deposit (&cls->instance,
   5130                 &cls->account,
   5131                 &cls->orders[0],
   5132                 &cls->signkey,
   5133                 &cls->deposits[0]);
   5134   make_deposit (&cls->instance,
   5135                 &cls->account,
   5136                 &cls->orders[0],
   5137                 &cls->signkey,
   5138                 &cls->deposits[1]);
   5139   make_deposit (&cls->instance,
   5140                 &cls->account,
   5141                 &cls->orders[1],
   5142                 &cls->signkey,
   5143                 &cls->deposits[2]);
   5144 
   5145   /* Refund */
   5146   make_refund (&cls->deposits[0],
   5147                &cls->refunds[0]);
   5148   make_refund (&cls->deposits[2],
   5149                &cls->refunds[1]);
   5150   make_refund (&cls->deposits[2],
   5151                &cls->refunds[2]);
   5152   GNUNET_assert (GNUNET_OK ==
   5153                  TALER_string_to_amount ("EUR:10.00",
   5154                                          &cls->refunds[1].refund_amount));
   5155   cls->refunds[1].reason = "refund 1";
   5156   GNUNET_assert (GNUNET_OK ==
   5157                  TALER_string_to_amount ("EUR:10.00",
   5158                                          &cls->refunds[2].refund_amount));
   5159   cls->refunds[2].reason = "refund 2";
   5160 
   5161   /* Refund proof */
   5162   GNUNET_assert (GNUNET_OK ==
   5163                  TALER_string_to_amount ("EUR:0.02",
   5164                                          &cls->refund_proof.refund_fee));
   5165   memset (&cls->refund_proof.exchange_sig,
   5166           42,
   5167           sizeof (cls->refund_proof.exchange_sig));
   5168 }
   5169 
   5170 
   5171 /**
   5172  * Cleans up after testing refunds.
   5173  * @param cls the closure.
   5174  */
   5175 static void
   5176 post_test_refunds (struct TestRefunds_Closure *cls)
   5177 {
   5178   free_instance_data (&cls->instance);
   5179   free_order_data (&cls->orders[0]);
   5180   free_order_data (&cls->orders[1]);
   5181 }
   5182 
   5183 
   5184 /**
   5185  * Runs the refund tests.
   5186  * @param cls the closure.
   5187  *
   5188  * @return 0 on success, 1 otherwise.
   5189  */
   5190 static int
   5191 run_test_refunds (struct TestRefunds_Closure *cls)
   5192 {
   5193   struct TALER_Amount inc;
   5194   uint64_t refund_serial;
   5195 
   5196   /* Insert an instance */
   5197   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   5198                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5199   /* Insert an account */
   5200   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   5201                                          &cls->account,
   5202                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5203   /* Insert an order */
   5204   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   5205                                        &cls->orders[0],
   5206                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5207   /* Insert contract terms */
   5208   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   5209                                                 &cls->orders[0],
   5210                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5211   /* Insert a signing key */
   5212   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   5213                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5214   /* Insert a deposit */
   5215   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5216                                          &cls->signkey,
   5217                                          &cls->deposits[0],
   5218                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5219   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5220                                          &cls->signkey,
   5221                                          &cls->deposits[1],
   5222                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5223   /* Mark as paid */
   5224   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   5225                                              &cls->orders[0],
   5226                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5227   /* Test refund coin */
   5228   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   5229                          TALER_MERCHANTDB_refund_coin (pg,
   5230                                                        cls->instance.instance.id,
   5231                                                        &cls->deposits[0].h_contract_terms
   5232                                                        ,
   5233                                                        cls->refunds[0].timestamp,
   5234                                                        cls->refunds[0].coin_pub,
   5235                                                        cls->refunds[0].reason),
   5236                          "Refund coin failed\n");
   5237   refund_serial = get_refund_serial (&cls->instance,
   5238                                      &cls->deposits[0].h_contract_terms,
   5239                                      &cls->refunds[0]);
   5240   /* Test double refund fails */
   5241   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS ==
   5242                          TALER_MERCHANTDB_refund_coin (pg,
   5243                                                        cls->instance.instance.id,
   5244                                                        &cls->deposits[0].h_contract_terms
   5245                                                        ,
   5246                                                        cls->refunds[0].timestamp,
   5247                                                        cls->refunds[0].coin_pub,
   5248                                                        cls->refunds[0].reason),
   5249                          "Refund coin failed\n");
   5250   /* Test lookup refunds */
   5251   TEST_RET_ON_FAIL (test_lookup_refunds (&cls->instance,
   5252                                          &cls->deposits[0].h_contract_terms,
   5253                                          1,
   5254                                          cls->refunds[0].coin_pub,
   5255                                          &cls->refunds[0].refund_amount));
   5256   /* Test lookup refunds detailed */
   5257   TEST_RET_ON_FAIL (test_lookup_refunds_detailed (&cls->instance,
   5258                                                   &cls->deposits[0].
   5259                                                   h_contract_terms,
   5260                                                   true,
   5261                                                   1,
   5262                                                   &cls->refunds[0]));
   5263   /* Test insert refund proof */
   5264   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   5265                          TALER_MERCHANTDB_insert_refund_proof (pg,
   5266                                                                refund_serial,
   5267                                                                &cls->refund_proof.
   5268                                                                exchange_sig,
   5269                                                                &cls->signkey.exchange_pub
   5270                                                                ),
   5271                          "Insert refund proof failed\n");
   5272   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS ==
   5273                          TALER_MERCHANTDB_insert_refund_proof (pg,
   5274                                                                refund_serial,
   5275                                                                &cls->refund_proof.
   5276                                                                exchange_sig,
   5277                                                                &cls->signkey.exchange_pub
   5278                                                                ),
   5279                          "Insert refund proof failed\n");
   5280   /* Test that we can't give too much in refunds */
   5281   GNUNET_assert (GNUNET_OK ==
   5282                  TALER_string_to_amount ("EUR:1000.00",
   5283                                          &inc));
   5284   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_TOO_HIGH ==
   5285                          TALER_MERCHANTDB_increase_refund (pg,
   5286                                                            cls->instance.instance.id,
   5287                                                            cls->orders[0].id,
   5288                                                            &inc,
   5289                                                            NULL,
   5290                                                            NULL,
   5291                                                            "more"),
   5292                          "Increase refund failed\n");
   5293   /* Test increase refund */
   5294   GNUNET_assert (GNUNET_OK ==
   5295                  TALER_string_to_amount ("EUR:1.00",
   5296                                          &inc));
   5297   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_SUCCESS ==
   5298                          TALER_MERCHANTDB_increase_refund (pg,
   5299                                                            cls->instance.instance.id,
   5300                                                            cls->orders[0].id,
   5301                                                            &inc,
   5302                                                            NULL,
   5303                                                            NULL,
   5304                                                            "more"),
   5305                          "Increase refund failed\n");
   5306   /* Test lookup refund proof */
   5307   TEST_RET_ON_FAIL (test_lookup_refund_proof (1,
   5308                                               &cls->refund_proof.exchange_sig,
   5309                                               &cls->signkey.exchange_pub));
   5310   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   5311                                        &cls->orders[1],
   5312                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5313   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   5314                                                 &cls->orders[1],
   5315                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5316   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5317                                          &cls->signkey,
   5318                                          &cls->deposits[2],
   5319                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5320   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   5321                                              &cls->orders[1],
   5322                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5323   /* Test refunding a small amount of the coin, then increasing it */
   5324   GNUNET_assert (GNUNET_OK ==
   5325                  TALER_string_to_amount ("EUR:10.00",
   5326                                          &inc));
   5327   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_SUCCESS ==
   5328                          TALER_MERCHANTDB_increase_refund (pg,
   5329                                                            cls->instance.instance.id,
   5330                                                            cls->orders[1].id,
   5331                                                            &inc,
   5332                                                            NULL,
   5333                                                            NULL,
   5334                                                            cls->refunds[1].reason),
   5335                          "Increase refund failed\n");
   5336   GNUNET_assert (GNUNET_OK ==
   5337                  TALER_string_to_amount ("EUR:20.00",
   5338                                          &inc));
   5339   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_SUCCESS ==
   5340                          TALER_MERCHANTDB_increase_refund (pg,
   5341                                                            cls->instance.instance.id,
   5342                                                            cls->orders[1].id,
   5343                                                            &inc,
   5344                                                            NULL,
   5345                                                            NULL,
   5346                                                            cls->refunds[2].reason),
   5347                          "Increase refund failed\n");
   5348   TEST_RET_ON_FAIL (test_lookup_refunds_detailed (&cls->instance,
   5349                                                   &cls->deposits[2].
   5350                                                   h_contract_terms,
   5351                                                   false,
   5352                                                   2,
   5353                                                   &cls->refunds[1]));
   5354   return 0;
   5355 }
   5356 
   5357 
   5358 /**
   5359  * All logic for testing refunds.
   5360  *
   5361  * @return 0 on success, 1 otherwise.
   5362  */
   5363 static int
   5364 test_refunds (void)
   5365 {
   5366   struct TestRefunds_Closure test_cls;
   5367   int test_result;
   5368 
   5369   pre_test_refunds (&test_cls);
   5370   test_result = run_test_refunds (&test_cls);
   5371   post_test_refunds (&test_cls);
   5372   return test_result;
   5373 }
   5374 
   5375 
   5376 /**
   5377  * Convenience function that reverses an array of orders.
   5378  * @param orders_length length of @e orders.
   5379  * @param orders the array to reverse.
   5380  */
   5381 static void
   5382 reverse_order_data_array (unsigned int orders_length,
   5383                           struct OrderData *orders)
   5384 {
   5385   struct OrderData tmp[orders_length];
   5386   for (unsigned int i = 0; i < orders_length; ++i)
   5387     tmp[i] = orders[orders_length - 1 - i];
   5388   for (unsigned int i = 0; i < orders_length; ++i)
   5389     orders[i] = tmp[i];
   5390 }
   5391 
   5392 
   5393 /**
   5394  * Closure for testing all the filters for looking up orders.
   5395  */
   5396 struct TestLookupOrdersAllFilters_Closure
   5397 {
   5398   /**
   5399    * The instance.
   5400    */
   5401   struct InstanceData instance;
   5402 
   5403   /**
   5404    * The merchant account.
   5405    */
   5406   struct TALER_MERCHANTDB_AccountDetails account;
   5407 
   5408   /**
   5409    * The exchange signing key.
   5410    */
   5411   struct ExchangeSignkeyData signkey;
   5412 
   5413   /**
   5414    * The array of order ids.
   5415    */
   5416   char *order_ids[64];
   5417 
   5418   /**
   5419    * The array of orders.
   5420    */
   5421   struct OrderData orders[64];
   5422 
   5423   /**
   5424    * The array of deposits.
   5425    */
   5426   struct DepositData deposits[64];
   5427 
   5428   /**
   5429    * The array of refunds.
   5430    */
   5431   struct RefundData refunds[64];
   5432 };
   5433 
   5434 
   5435 /**
   5436  * Sets up for testing lookup order filters.
   5437  * @param cls the closure.
   5438  */
   5439 static void
   5440 pre_test_lookup_orders_all_filters (
   5441   struct TestLookupOrdersAllFilters_Closure *cls)
   5442 {
   5443   make_instance ("test_inst_lookup_orders_all_filters",
   5444                  &cls->instance);
   5445   make_account (&cls->account);
   5446   cls->account.instance_id = cls->instance.instance.id;
   5447   make_exchange_signkey (&cls->signkey);
   5448   for (unsigned int i = 0; i < 64; ++i)
   5449   {
   5450     (void) GNUNET_asprintf (&cls->order_ids[i],
   5451                             "test_orders_filter_od_%u",
   5452                             i);
   5453     make_order (cls->order_ids[i],
   5454                 &cls->orders[i]);
   5455     GNUNET_assert (0 ==
   5456                    json_object_set_new (cls->orders[i].contract,
   5457                                         "order_id",
   5458                                         json_string (cls->order_ids[i])));
   5459     make_deposit (&cls->instance,
   5460                   &cls->account,
   5461                   &cls->orders[i],
   5462                   &cls->signkey,
   5463                   &cls->deposits[i]);
   5464     make_refund (&cls->deposits[i],
   5465                  &cls->refunds[i]);
   5466   }
   5467 }
   5468 
   5469 
   5470 /**
   5471  * Cleans up after testing lookup order filters.
   5472  * @param cls the closure.
   5473  */
   5474 static void
   5475 post_test_lookup_orders_all_filters (
   5476   struct TestLookupOrdersAllFilters_Closure *cls)
   5477 {
   5478   free_instance_data (&cls->instance);
   5479   for (unsigned int i = 0; i < 64; ++i)
   5480   {
   5481     free_order_data (&cls->orders[i]);
   5482     GNUNET_free (cls->order_ids[i]);
   5483   }
   5484 }
   5485 
   5486 
   5487 /**
   5488  * Runs the tests for lookup order filters.
   5489  * @param cls the closure.
   5490  *
   5491  * @return 0 on success, 1 otherwise.
   5492  */
   5493 static int
   5494 run_test_lookup_orders_all_filters (
   5495   struct TestLookupOrdersAllFilters_Closure *cls)
   5496 {
   5497   /* Order filter extravaganza */
   5498   struct
   5499   {
   5500     bool claimed;
   5501     bool paid;
   5502     bool refunded;
   5503     bool wired;
   5504   } order_status[64];
   5505   unsigned int *permutation;
   5506 
   5507   /* Pseudorandomly generate variations for the filter to differentiate */
   5508   GNUNET_CRYPTO_seed_weak_random (1);
   5509   permutation = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
   5510                                               64);
   5511   for (unsigned int i = 0; i < 64; ++i)
   5512   {
   5513     unsigned int dest = permutation[i];
   5514     order_status[dest].claimed = (i & 1) ? true : false;
   5515     order_status[dest].paid = (3 == (i & 3)) ? true : false;
   5516     order_status[dest].refunded = (5 == (i & 5)) ? true : false;
   5517     order_status[dest].wired = (9 == (i & 9)) ? true : false;
   5518   }
   5519   GNUNET_free (permutation);
   5520 
   5521 
   5522   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   5523                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5524   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   5525                                          &cls->account,
   5526                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5527   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   5528                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5529   for (unsigned int i = 0; i < 64; ++i)
   5530   {
   5531     uint64_t order_serial;
   5532 
   5533     TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   5534                                          &cls->orders[i],
   5535                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5536     order_serial = get_order_serial (&cls->instance,
   5537                                      &cls->orders[i]);
   5538 
   5539     if (order_status[i].claimed)
   5540     {
   5541       TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   5542                                                     &cls->orders[i],
   5543                                                     GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5544     }
   5545     else
   5546     {
   5547       continue;
   5548     }
   5549 
   5550     if (order_status[i].paid)
   5551       TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   5552                                                  &cls->orders[i],
   5553                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5554     if (order_status[i].refunded)
   5555     {
   5556       TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5557                                              &cls->signkey,
   5558                                              &cls->deposits[i],
   5559                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5560       TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   5561                              TALER_MERCHANTDB_refund_coin (pg,
   5562                                                            cls->instance.instance.id,
   5563                                                            &cls->deposits[i].
   5564                                                            h_contract_terms,
   5565                                                            cls->refunds[i].timestamp,
   5566                                                            cls->refunds[i].coin_pub,
   5567                                                            cls->refunds[i].reason),
   5568                              "Refund coin failed\n");
   5569     }
   5570 
   5571     if (order_status[i].wired)
   5572       TEST_RET_ON_FAIL (test_mark_order_wired (order_serial,
   5573                                                GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5574   }
   5575 
   5576   /* There are 3^3 = 27 possibilities here, not counting inc/dec and start row */
   5577   for (unsigned int i = 0; i < 27; ++i)
   5578   {
   5579     struct TALER_MERCHANTDB_OrderFilter filter = {
   5580       .paid = (i % 3) + 1,
   5581       .refunded = ((i / 3) % 3) + 1,
   5582       .wired = ((i / 9) % 3) + 1,
   5583       .date = GNUNET_TIME_UNIT_ZERO_TS,
   5584       .start_row = 0,
   5585       .delta = 64
   5586     };
   5587     unsigned int orders_length = 0;
   5588     struct OrderData orders[64];
   5589 
   5590     /* Now figure out which orders should make it through the filter */
   5591     for (unsigned int j = 0; j < 64; ++j)
   5592     {
   5593       if (((TALER_EXCHANGE_YNA_YES == filter.paid) &&
   5594            (true != order_status[j].paid)) ||
   5595           ((TALER_EXCHANGE_YNA_NO == filter.paid) &&
   5596            (false != order_status[j].paid)) ||
   5597           ((TALER_EXCHANGE_YNA_YES == filter.refunded) &&
   5598            (true != order_status[j].refunded)) ||
   5599           ((TALER_EXCHANGE_YNA_NO == filter.refunded) &&
   5600            (false != order_status[j].refunded)) ||
   5601           ((TALER_EXCHANGE_YNA_YES == filter.wired) &&
   5602            (true != order_status[j].wired)) ||
   5603           ((TALER_EXCHANGE_YNA_NO == filter.wired) &&
   5604            (false != order_status[j].wired)))
   5605         continue;
   5606       orders[orders_length] = cls->orders[j];
   5607       orders_length += 1;
   5608     }
   5609 
   5610     /* Test the lookup */
   5611     TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   5612                                           &filter,
   5613                                           orders_length,
   5614                                           orders));
   5615 
   5616     /* Now test decreasing */
   5617     filter.start_row = 256;
   5618     filter.date = GNUNET_TIME_UNIT_FOREVER_TS;
   5619     filter.delta = -64;
   5620 
   5621     reverse_order_data_array (orders_length,
   5622                               orders);
   5623 
   5624     TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   5625                                           &filter,
   5626                                           orders_length,
   5627                                           orders));
   5628   }
   5629 
   5630   return 0;
   5631 }
   5632 
   5633 
   5634 /**
   5635  * Handles all logic for testing lookup order filters.
   5636  *
   5637  * @return 0 on success, 1 otherwise.
   5638  */
   5639 static int
   5640 test_lookup_orders_all_filters (void)
   5641 {
   5642   struct TestLookupOrdersAllFilters_Closure test_cls;
   5643   int test_result;
   5644 
   5645   memset (&test_cls,
   5646           0,
   5647           sizeof (test_cls));
   5648   pre_test_lookup_orders_all_filters (&test_cls);
   5649   test_result = run_test_lookup_orders_all_filters (&test_cls);
   5650   post_test_lookup_orders_all_filters (&test_cls);
   5651   return test_result;
   5652 }
   5653 
   5654 
   5655 static void
   5656 kyc_status_ok (
   5657   void *cls,
   5658   const struct TALER_MerchantWireHashP *h_wire,
   5659   struct TALER_FullPayto payto_uri,
   5660   const char *exchange_url,
   5661   struct GNUNET_TIME_Timestamp last_check,
   5662   bool kyc_ok,
   5663   const struct TALER_AccountAccessTokenP *access_token,
   5664   unsigned int last_http_status,
   5665   enum TALER_ErrorCode last_ec,
   5666   bool in_aml_review,
   5667   const json_t *jlimits)
   5668 {
   5669   bool *fail = cls;
   5670 
   5671   if (kyc_ok)
   5672     *fail = false;
   5673 }
   5674 
   5675 
   5676 static void
   5677 kyc_status_fail (
   5678   void *cls,
   5679   const struct TALER_MerchantWireHashP *h_wire,
   5680   struct TALER_FullPayto payto_uri,
   5681   const char *exchange_url,
   5682   struct GNUNET_TIME_Timestamp last_check,
   5683   bool kyc_ok,
   5684   const struct TALER_AccountAccessTokenP *access_token,
   5685   unsigned int last_http_status,
   5686   enum TALER_ErrorCode last_ec,
   5687   bool in_aml_review,
   5688   const json_t *jlimits)
   5689 {
   5690   bool *fail = cls;
   5691 
   5692   if (! kyc_ok)
   5693     *fail = false;
   5694 }
   5695 
   5696 
   5697 /**
   5698  * Function that tests the KYC table.
   5699  *
   5700  * @return 0 on success, 1 otherwise.
   5701  */
   5702 static int
   5703 test_kyc (void)
   5704 {
   5705   struct InstanceData instance;
   5706   struct TALER_MERCHANTDB_AccountDetails account;
   5707   bool fail;
   5708   struct GNUNET_TIME_Timestamp now;
   5709 
   5710   make_instance ("test_kyc",
   5711                  &instance);
   5712   make_account (&account);
   5713   account.instance_id = instance.instance.id;
   5714   TEST_RET_ON_FAIL (test_insert_instance (&instance,
   5715                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5716   TEST_RET_ON_FAIL (test_insert_account (&instance,
   5717                                          &account,
   5718                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5719   now = GNUNET_TIME_timestamp_get ();
   5720   TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   5721                     TALER_MERCHANTDB_account_kyc_set_status (pg,
   5722                                                              instance.instance.id,
   5723                                                              &account.h_wire,
   5724                                                              "https://exchange.net/",
   5725                                                              now,
   5726                                                              GNUNET_TIME_UNIT_FOREVER_ABS,
   5727                                                              GNUNET_TIME_UNIT_HOURS,
   5728                                                              MHD_HTTP_OK,
   5729                                                              TALER_EC_NONE,
   5730                                                              42,
   5731                                                              NULL,
   5732                                                              NULL,
   5733                                                              false,
   5734                                                              false));
   5735   TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   5736                     TALER_MERCHANTDB_account_kyc_set_status (pg,
   5737                                                              instance.instance.id,
   5738                                                              &account.h_wire,
   5739                                                              "https://exchange2.com/",
   5740                                                              now,
   5741                                                              GNUNET_TIME_UNIT_FOREVER_ABS,
   5742                                                              GNUNET_TIME_UNIT_HOURS,
   5743                                                              MHD_HTTP_OK,
   5744                                                              TALER_EC_NONE,
   5745                                                              42,
   5746                                                              NULL,
   5747                                                              NULL,
   5748                                                              false,
   5749                                                              false));
   5750   TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   5751                     TALER_MERCHANTDB_account_kyc_set_status (pg,
   5752                                                              instance.instance.id,
   5753                                                              &account.h_wire,
   5754                                                              "https://exchange.net/",
   5755                                                              now,
   5756                                                              GNUNET_TIME_UNIT_FOREVER_ABS,
   5757                                                              GNUNET_TIME_UNIT_HOURS,
   5758                                                              MHD_HTTP_OK,
   5759                                                              TALER_EC_NONE,
   5760                                                              42,
   5761                                                              NULL,
   5762                                                              NULL,
   5763                                                              false,
   5764                                                              true));
   5765   fail = true;
   5766   TEST_RET_ON_FAIL (1 !=
   5767                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5768                                                              instance.instance.id,
   5769                                                              &account.h_wire,
   5770                                                              "https://exchange.net/",
   5771                                                              &kyc_status_ok,
   5772                                                              &fail));
   5773   TEST_RET_ON_FAIL (fail);
   5774   fail = true;
   5775   TEST_RET_ON_FAIL (1 !=
   5776                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5777                                                              instance.instance.id,
   5778                                                              NULL,
   5779                                                              "https://exchange2.com/",
   5780                                                              &kyc_status_fail,
   5781                                                              &fail));
   5782   TEST_RET_ON_FAIL (fail);
   5783   fail = true;
   5784   TEST_RET_ON_FAIL (2 !=
   5785                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5786                                                              instance.instance.id,
   5787                                                              NULL,
   5788                                                              NULL,
   5789                                                              &kyc_status_fail,
   5790                                                              &fail));
   5791   TEST_RET_ON_FAIL (fail);
   5792   fail = true;
   5793   TEST_RET_ON_FAIL (2 !=
   5794                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5795                                                              instance.instance.id,
   5796                                                              NULL,
   5797                                                              NULL,
   5798                                                              &kyc_status_ok,
   5799                                                              &fail));
   5800   TEST_RET_ON_FAIL (fail);
   5801   json_decref (instance.instance.address);
   5802   json_decref (instance.instance.jurisdiction);
   5803   return 0;
   5804 }
   5805 
   5806 
   5807 /* *********** Templates ********** */
   5808 
   5809 /**
   5810  * A container for data relevant to a template.
   5811  */
   5812 struct TemplateData
   5813 {
   5814   /**
   5815    * The identifier of the template.
   5816    */
   5817   const char *id;
   5818 
   5819   /**
   5820    * The details of the template.
   5821    */
   5822   struct TALER_MERCHANTDB_TemplateDetails template;
   5823 };
   5824 
   5825 
   5826 /**
   5827  * Creates a template for testing with.
   5828  *
   5829  * @param id the id of the template.
   5830  * @param template the template data to fill.
   5831  */
   5832 static void
   5833 make_template (const char *id,
   5834                struct TemplateData *template)
   5835 {
   5836   template->id = id;
   5837   template->template.template_description = "This is a test template";
   5838   template->template.otp_id = NULL;
   5839   template->template.template_contract = json_array ();
   5840   GNUNET_assert (NULL != template->template.template_contract);
   5841 }
   5842 
   5843 
   5844 /**
   5845  * Frees memory associated with @e TemplateData.
   5846  *
   5847  * @param template the container to free.
   5848  */
   5849 static void
   5850 free_template_data (struct TemplateData *template)
   5851 {
   5852   GNUNET_free (template->template.otp_id);
   5853   json_decref (template->template.template_contract);
   5854 }
   5855 
   5856 
   5857 /**
   5858  * Compare two templates for equality.
   5859  *
   5860  * @param a the first template.
   5861  * @param b the second template.
   5862  * @return 0 on equality, 1 otherwise.
   5863  */
   5864 static int
   5865 check_templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *a,
   5866                        const struct TALER_MERCHANTDB_TemplateDetails *b)
   5867 {
   5868   if ((0 != strcmp (a->template_description,
   5869                     b->template_description)) ||
   5870       ( (NULL == a->otp_id) && (NULL != b->otp_id)) ||
   5871       ( (NULL != a->otp_id) && (NULL == b->otp_id)) ||
   5872       ( (NULL != a->otp_id) && (0 != strcmp (a->otp_id,
   5873                                              b->otp_id))) ||
   5874       (1 != json_equal (a->template_contract,
   5875                         b->template_contract)))
   5876     return 1;
   5877   return 0;
   5878 }
   5879 
   5880 
   5881 /**
   5882  * Tests inserting template data into the database.
   5883  *
   5884  * @param instance the instance to insert the template for.
   5885  * @param template the template data to insert.
   5886  * @param expected_result the result we expect the db to return.
   5887  * @return 0 when successful, 1 otherwise.
   5888  */
   5889 static int
   5890 test_insert_template (const struct InstanceData *instance,
   5891                       const struct TemplateData *template,
   5892                       enum GNUNET_DB_QueryStatus expected_result)
   5893 {
   5894   TEST_COND_RET_ON_FAIL (expected_result ==
   5895                          TALER_MERCHANTDB_insert_template (pg,
   5896                                                            instance->instance.id,
   5897                                                            template->id,
   5898                                                            0,
   5899                                                            &template->template),
   5900                          "Insert template failed\n");
   5901   return 0;
   5902 }
   5903 
   5904 
   5905 /**
   5906  * Tests updating template data in the database.
   5907  *
   5908  * @param instance the instance to update the template for.
   5909  * @param template the template data to update.
   5910  * @param expected_result the result we expect the db to return.
   5911  * @return 0 when successful, 1 otherwise.
   5912  */
   5913 static int
   5914 test_update_template (const struct InstanceData *instance,
   5915                       const struct TemplateData *template,
   5916                       enum GNUNET_DB_QueryStatus expected_result)
   5917 {
   5918   TEST_COND_RET_ON_FAIL (expected_result ==
   5919                          TALER_MERCHANTDB_update_template (pg,
   5920                                                            instance->instance.id,
   5921                                                            template->id,
   5922                                                            &template->template),
   5923                          "Update template failed\n");
   5924   return 0;
   5925 }
   5926 
   5927 
   5928 /**
   5929  * Tests looking up a template from the db.
   5930  *
   5931  * @param instance the instance to query from.
   5932  * @param template the template to query and compare to.
   5933  * @return 0 when successful, 1 otherwise.
   5934  */
   5935 static int
   5936 test_lookup_template (const struct InstanceData *instance,
   5937                       const struct TemplateData *template)
   5938 {
   5939   const struct TALER_MERCHANTDB_TemplateDetails *to_cmp
   5940     = &template->template;
   5941   struct TALER_MERCHANTDB_TemplateDetails lookup_result;
   5942 
   5943   if (0 > TALER_MERCHANTDB_lookup_template (pg,
   5944                                             instance->instance.id,
   5945                                             template->id,
   5946                                             &lookup_result))
   5947   {
   5948     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5949                 "Lookup template failed\n");
   5950     TALER_MERCHANTDB_template_details_free (&lookup_result);
   5951     return 1;
   5952   }
   5953   if (0 != check_templates_equal (&lookup_result,
   5954                                   to_cmp))
   5955   {
   5956     GNUNET_break (0);
   5957     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5958                 "Lookup template failed: incorrect template returned\n");
   5959     TALER_MERCHANTDB_template_details_free (&lookup_result);
   5960     return 1;
   5961   }
   5962   TALER_MERCHANTDB_template_details_free (&lookup_result);
   5963   return 0;
   5964 }
   5965 
   5966 
   5967 /**
   5968  * Closure for testing template lookup
   5969  */
   5970 struct TestLookupTemplates_Closure
   5971 {
   5972   /**
   5973    * Number of template ids to compare to
   5974    */
   5975   unsigned int templates_to_cmp_length;
   5976 
   5977   /**
   5978    * Pointer to array of template ids
   5979    */
   5980   const struct TemplateData *templates_to_cmp;
   5981 
   5982   /**
   5983    * Pointer to array of number of matches for each template
   5984    */
   5985   unsigned int *results_matching;
   5986 
   5987   /**
   5988    * Total number of results returned
   5989    */
   5990   unsigned int results_length;
   5991 };
   5992 
   5993 
   5994 /**
   5995  * Function called after calling @e test_lookup_templates
   5996  *
   5997  * @param cls a pointer to the lookup closure.
   5998  * @param template_id the identifier of the template found.
   5999  */
   6000 static void
   6001 lookup_templates_cb (void *cls,
   6002                      const char *template_id,
   6003                      const char *template_description)
   6004 {
   6005   struct TestLookupTemplates_Closure *cmp = cls;
   6006 
   6007   if (NULL == cmp)
   6008     return;
   6009   cmp->results_length += 1;
   6010   for (unsigned int i = 0; cmp->templates_to_cmp_length > i; ++i)
   6011   {
   6012     if ( (0 == strcmp (cmp->templates_to_cmp[i].id,
   6013                        template_id)) &&
   6014          (0 == strcmp (cmp->templates_to_cmp[i].template.template_description,
   6015                        template_description)) )
   6016       cmp->results_matching[i] += 1;
   6017   }
   6018 }
   6019 
   6020 
   6021 /**
   6022  * Tests looking up all templates for an instance.
   6023  *
   6024  * @param instance the instance to query from.
   6025  * @param templates_length the number of templates we are expecting.
   6026  * @param templates the list of templates that we expect to be found.
   6027  * @return 0 when successful, 1 otherwise.
   6028  */
   6029 static int
   6030 test_lookup_templates (const struct InstanceData *instance,
   6031                        unsigned int templates_length,
   6032                        const struct TemplateData *templates)
   6033 {
   6034   unsigned int results_matching[templates_length];
   6035   struct TestLookupTemplates_Closure cls = {
   6036     .templates_to_cmp_length = templates_length,
   6037     .templates_to_cmp = templates,
   6038     .results_matching = results_matching,
   6039     .results_length = 0
   6040   };
   6041 
   6042   memset (results_matching,
   6043           0,
   6044           sizeof (unsigned int) * templates_length);
   6045   if (0 > TALER_MERCHANTDB_lookup_templates (pg,
   6046                                              instance->instance.id,
   6047                                              &lookup_templates_cb,
   6048                                              &cls))
   6049   {
   6050     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6051                 "Lookup templates failed\n");
   6052     return 1;
   6053   }
   6054   if (templates_length != cls.results_length)
   6055   {
   6056     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6057                 "Lookup templates failed: incorrect number of results\n");
   6058     return 1;
   6059   }
   6060   for (unsigned int i = 0; templates_length > i; ++i)
   6061   {
   6062     if (1 != cls.results_matching[i])
   6063     {
   6064       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6065                   "Lookup templates failed: mismatched data\n");
   6066       return 1;
   6067     }
   6068   }
   6069   return 0;
   6070 }
   6071 
   6072 
   6073 /**
   6074  * Tests deleting a template.
   6075  *
   6076  * @param instance the instance to delete the template from.
   6077  * @param template the template that should be deleted.
   6078  * @param expected_result the result that we expect the DB to return.
   6079  * @return 0 when successful, 1 otherwise.
   6080  */
   6081 static int
   6082 test_delete_template (const struct InstanceData *instance,
   6083                       const struct TemplateData *template,
   6084                       enum GNUNET_DB_QueryStatus expected_result)
   6085 {
   6086   TEST_COND_RET_ON_FAIL (expected_result ==
   6087                          TALER_MERCHANTDB_delete_template (pg,
   6088                                                            instance->instance.id,
   6089                                                            template->id),
   6090                          "Delete template failed\n");
   6091   return 0;
   6092 }
   6093 
   6094 
   6095 /**
   6096  * Closure for template tests.
   6097  */
   6098 struct TestTemplates_Closure
   6099 {
   6100   /**
   6101    * The instance to use for this test.
   6102    */
   6103   struct InstanceData instance;
   6104 
   6105   /**
   6106    * The array of templates.
   6107    */
   6108   struct TemplateData templates[2];
   6109 };
   6110 
   6111 
   6112 /**
   6113  * Sets up the data structures used in the template tests.
   6114  *
   6115  * @param cls the closure to fill with test data.
   6116  */
   6117 static void
   6118 pre_test_templates (struct TestTemplates_Closure *cls)
   6119 {
   6120   /* Instance */
   6121   make_instance ("test_inst_templates",
   6122                  &cls->instance);
   6123 
   6124   /* Templates */
   6125   make_template ("test_templates_pd_0",
   6126                  &cls->templates[0]);
   6127 
   6128   make_template ("test_templates_pd_1",
   6129                  &cls->templates[1]);
   6130   cls->templates[1].template.template_description =
   6131     "This is a another test template";
   6132 }
   6133 
   6134 
   6135 /**
   6136  * Handles all teardown after testing.
   6137  *
   6138  * @param cls the closure containing memory to be freed.
   6139  */
   6140 static void
   6141 post_test_templates (struct TestTemplates_Closure *cls)
   6142 {
   6143   free_instance_data (&cls->instance);
   6144   free_template_data (&cls->templates[0]);
   6145   free_template_data (&cls->templates[1]);
   6146 }
   6147 
   6148 
   6149 /**
   6150  * Runs the tests for templates.
   6151  *
   6152  * @param cls the container of the test data.
   6153  * @return 0 on success, 1 otherwise.
   6154  */
   6155 static int
   6156 run_test_templates (struct TestTemplates_Closure *cls)
   6157 {
   6158 
   6159   /* Test that insert without an instance fails */
   6160   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6161                                           &cls->templates[0],
   6162                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6163   /* Insert the instance */
   6164   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   6165                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6166   /* Test inserting a template */
   6167   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6168                                           &cls->templates[0],
   6169                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6170   /* Test that double insert fails */
   6171   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6172                                           &cls->templates[0],
   6173                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6174   /* Test lookup of individual templates */
   6175   TEST_RET_ON_FAIL (test_lookup_template (&cls->instance,
   6176                                           &cls->templates[0]));
   6177   /* Make sure it fails correctly for templates that don't exist */
   6178   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   6179       TALER_MERCHANTDB_lookup_template (pg,
   6180                                         cls->instance.instance.id,
   6181                                         "nonexistent_template",
   6182                                         NULL))
   6183   {
   6184     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6185                 "Lookup template failed\n");
   6186     return 1;
   6187   }
   6188   /* Test template update */
   6189   cls->templates[0].template.template_description =
   6190     "This is a test template that has been updated!";
   6191   GNUNET_free (cls->templates[0].template.otp_id);
   6192   cls->templates[0].template.otp_id = GNUNET_strdup ("otp_id");
   6193   {
   6194     /* ensure OTP device exists */
   6195     struct TALER_MERCHANTDB_OtpDeviceDetails td = {
   6196       .otp_description = "my otp",
   6197       .otp_key = "my key",
   6198       .otp_algorithm = 1,
   6199       .otp_ctr = 42
   6200     };
   6201     GNUNET_assert (0 <=
   6202                    TALER_MERCHANTDB_insert_otp (pg,
   6203                                                 cls->instance.instance.id,
   6204                                                 "otp_id",
   6205                                                 &td));
   6206   }
   6207   GNUNET_assert (0 ==
   6208                  json_array_append_new (
   6209                    cls->templates[0].template.template_contract,
   6210                    json_string ("This is a test. 3CH.")));
   6211   TEST_RET_ON_FAIL (test_update_template (&cls->instance,
   6212                                           &cls->templates[0],
   6213                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6214   TEST_RET_ON_FAIL (test_lookup_template (&cls->instance,
   6215                                           &cls->templates[0]));
   6216   TEST_RET_ON_FAIL (test_update_template (&cls->instance,
   6217                                           &cls->templates[1],
   6218                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6219   /* Test collective template lookup */
   6220   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6221                                           &cls->templates[1],
   6222                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6223   TEST_RET_ON_FAIL (test_lookup_templates (&cls->instance,
   6224                                            2,
   6225                                            cls->templates));
   6226 
   6227   /* Test template deletion */
   6228   TEST_RET_ON_FAIL (test_delete_template (&cls->instance,
   6229                                           &cls->templates[1],
   6230                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6231   /* Test double deletion fails */
   6232   TEST_RET_ON_FAIL (test_delete_template (&cls->instance,
   6233                                           &cls->templates[1],
   6234                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6235   TEST_RET_ON_FAIL (test_lookup_templates (&cls->instance,
   6236                                            1,
   6237                                            cls->templates));
   6238   return 0;
   6239 }
   6240 
   6241 
   6242 /**
   6243  * Takes care of template testing.
   6244  *
   6245  * @return 0 on success, 1 otherwise.
   6246  */
   6247 static int
   6248 test_templates (void)
   6249 {
   6250   struct TestTemplates_Closure test_cls;
   6251   int test_result;
   6252 
   6253   memset (&test_cls,
   6254           0,
   6255           sizeof (test_cls));
   6256   pre_test_templates (&test_cls);
   6257   test_result = run_test_templates (&test_cls);
   6258   post_test_templates (&test_cls);
   6259   return test_result;
   6260 }
   6261 
   6262 
   6263 /* *********** Webhooks ********** */
   6264 
   6265 /**
   6266  * A container for data relevant to a webhook.
   6267  */
   6268 struct WebhookData
   6269 {
   6270 
   6271   /**
   6272    * The identifier of the webhook.
   6273    */
   6274   const char *id;
   6275 
   6276   /**
   6277    * The details of the webhook.
   6278    */
   6279   struct TALER_MERCHANTDB_WebhookDetails webhook;
   6280 };
   6281 
   6282 
   6283 /**
   6284  * Creates a webhook for testing with.
   6285  *
   6286  * @param id the id of the webhook.
   6287  * @param webhook the webhook data to fill.
   6288  */
   6289 static void
   6290 make_webhook (const char *id,
   6291               struct WebhookData *webhook)
   6292 {
   6293   webhook->id = id;
   6294   webhook->webhook.event_type = "Paid";
   6295   webhook->webhook.url = "https://exampletest.com";
   6296   webhook->webhook.http_method = "POST";
   6297   webhook->webhook.header_template = "Authorization:XYJAORKJEO";
   6298   webhook->webhook.body_template = "$Amount";
   6299 }
   6300 
   6301 
   6302 /**
   6303  * Compare two webhooks for equality.
   6304  *
   6305  * @param a the first webhook.
   6306  * @param b the second webhook.
   6307  * @return 0 on equality, 1 otherwise.
   6308  */
   6309 static int
   6310 check_webhooks_equal (const struct TALER_MERCHANTDB_WebhookDetails *a,
   6311                       const struct TALER_MERCHANTDB_WebhookDetails *b)
   6312 {
   6313   if ((0 != strcmp (a->event_type,
   6314                     b->event_type)) ||
   6315       (0 != strcmp (a->url,
   6316                     b->url)) ||
   6317       (0 != strcmp (a->http_method,
   6318                     b->http_method)) ||
   6319       (0 != strcmp (a->header_template,
   6320                     b->header_template)) ||
   6321       (0 != strcmp (a->body_template,
   6322                     b->body_template)))
   6323     return 1;
   6324   return 0;
   6325 }
   6326 
   6327 
   6328 /**
   6329  * Tests inserting webhook data into the database.
   6330  *
   6331  * @param instance the instance to insert the webhook for.
   6332  * @param webhook the webhook data to insert.
   6333  * @param expected_result the result we expect the db to return.
   6334  * @return 0 when successful, 1 otherwise.
   6335  */
   6336 static int
   6337 test_insert_webhook (const struct InstanceData *instance,
   6338                      const struct WebhookData *webhook,
   6339                      enum GNUNET_DB_QueryStatus expected_result)
   6340 {
   6341   TEST_COND_RET_ON_FAIL (expected_result ==
   6342                          TALER_MERCHANTDB_insert_webhook (pg,
   6343                                                           instance->instance.id,
   6344                                                           webhook->id,
   6345                                                           &webhook->webhook),
   6346                          "Insert webhook failed\n");
   6347   return 0;
   6348 }
   6349 
   6350 
   6351 /**
   6352  * Tests updating webhook data in the database.
   6353  *
   6354  * @param instance the instance to update the webhook for.
   6355  * @param webhook the webhook data to update.
   6356  * @param expected_result the result we expect the db to return.
   6357  * @return 0 when successful, 1 otherwise.
   6358  */
   6359 static int
   6360 test_update_webhook (const struct InstanceData *instance,
   6361                      const struct WebhookData *webhook,
   6362                      enum GNUNET_DB_QueryStatus expected_result)
   6363 {
   6364   TEST_COND_RET_ON_FAIL (expected_result ==
   6365                          TALER_MERCHANTDB_update_webhook (pg,
   6366                                                           instance->instance.id,
   6367                                                           webhook->id,
   6368                                                           &webhook->webhook),
   6369                          "Update webhook failed\n");
   6370   return 0;
   6371 }
   6372 
   6373 
   6374 /**
   6375  * Tests looking up a webhook from the db.
   6376  *
   6377  * @param instance the instance to query from.
   6378  * @param webhook the webhook to query and compare to.
   6379  * @return 0 when successful, 1 otherwise.
   6380  */
   6381 static int
   6382 test_lookup_webhook (const struct InstanceData *instance,
   6383                      const struct WebhookData *webhook)
   6384 {
   6385   const struct TALER_MERCHANTDB_WebhookDetails *to_cmp = &webhook->webhook;
   6386   struct TALER_MERCHANTDB_WebhookDetails lookup_result;
   6387 
   6388   if (0 > TALER_MERCHANTDB_lookup_webhook (pg,
   6389                                            instance->instance.id,
   6390                                            webhook->id,
   6391                                            &lookup_result))
   6392   {
   6393     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6394                 "Lookup webhook failed\n");
   6395     TALER_MERCHANTDB_webhook_details_free (&lookup_result);
   6396     return 1;
   6397   }
   6398   if (0 != check_webhooks_equal (&lookup_result,
   6399                                  to_cmp))
   6400   {
   6401     GNUNET_break (0);
   6402     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6403                 "Lookup webhook failed: incorrect webhook returned\n");
   6404     TALER_MERCHANTDB_webhook_details_free (&lookup_result);
   6405     return 1;
   6406   }
   6407   TALER_MERCHANTDB_webhook_details_free (&lookup_result);
   6408   return 0;
   6409 }
   6410 
   6411 
   6412 /**
   6413  * Closure for testing webhook lookup
   6414  */
   6415 struct TestLookupWebhooks_Closure
   6416 {
   6417   /**
   6418    * Number of webhook ids to compare to
   6419    */
   6420   unsigned int webhooks_to_cmp_length;
   6421 
   6422   /**
   6423    * Pointer to array of webhook ids
   6424    */
   6425   const struct WebhookData *webhooks_to_cmp;
   6426 
   6427   /**
   6428    * Pointer to array of number of matches for each webhook
   6429    */
   6430   unsigned int *results_matching;
   6431 
   6432   /**
   6433    * Total number of results returned
   6434    */
   6435   unsigned int results_length;
   6436 };
   6437 
   6438 
   6439 /**
   6440  * Function called after calling @e test_lookup_webhooks
   6441  *
   6442  * @param cls a pointer to the lookup closure.
   6443  * @param webhook_id the identifier of the webhook found.
   6444  */
   6445 static void
   6446 lookup_webhooks_cb (void *cls,
   6447                     const char *webhook_id,
   6448                     const char *event_type)
   6449 {
   6450   struct TestLookupWebhooks_Closure *cmp = cls;
   6451   if (NULL == cmp)
   6452     return;
   6453   cmp->results_length += 1;
   6454   for (unsigned int i = 0; cmp->webhooks_to_cmp_length > i; ++i)
   6455   {
   6456     if ((0 == strcmp (cmp->webhooks_to_cmp[i].id,
   6457                       webhook_id)) &&
   6458         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.event_type,
   6459                       event_type)) )
   6460       cmp->results_matching[i] += 1;
   6461   }
   6462 }
   6463 
   6464 
   6465 /**
   6466  * Tests looking up all webhooks for an instance.
   6467  *
   6468  * @param instance the instance to query from.
   6469  * @param webhooks_length the number of webhooks we are expecting.
   6470  * @param webhooks the list of webhooks that we expect to be found.
   6471  * @return 0 when successful, 1 otherwise.
   6472  */
   6473 static int
   6474 test_lookup_webhooks (const struct InstanceData *instance,
   6475                       unsigned int webhooks_length,
   6476                       const struct WebhookData *webhooks)
   6477 {
   6478   unsigned int results_matching[webhooks_length];
   6479   struct TestLookupWebhooks_Closure cls = {
   6480     .webhooks_to_cmp_length = webhooks_length,
   6481     .webhooks_to_cmp = webhooks,
   6482     .results_matching = results_matching,
   6483     .results_length = 0
   6484   };
   6485   memset (results_matching, 0, sizeof (unsigned int) * webhooks_length);
   6486   if (0 > TALER_MERCHANTDB_lookup_webhooks (pg,
   6487                                             instance->instance.id,
   6488                                             &lookup_webhooks_cb,
   6489                                             &cls))
   6490   {
   6491     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6492                 "Lookup webhooks failed\n");
   6493     return 1;
   6494   }
   6495   if (webhooks_length != cls.results_length)
   6496   {
   6497     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6498                 "Lookup webhooks failed: incorrect number of results\n");
   6499     return 1;
   6500   }
   6501   for (unsigned int i = 0; webhooks_length > i; ++i)
   6502   {
   6503     if (1 != cls.results_matching[i])
   6504     {
   6505       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6506                   "Lookup webhooks failed: mismatched data\n");
   6507       return 1;
   6508     }
   6509   }
   6510   return 0;
   6511 }
   6512 
   6513 
   6514 /**
   6515  * Function called after calling @e test_lookup_webhooks
   6516  *
   6517  * @param cls a pointer to the lookup closure.
   6518  * @param webhook_id the identifier of the webhook found.
   6519  */
   6520 static void
   6521 lookup_webhook_by_event_cb (void *cls,
   6522                             uint64_t webhook_serial,
   6523                             const char *event_type,
   6524                             const char *url,
   6525                             const char *http_method,
   6526                             const char *header_template,
   6527                             const char *body_template)
   6528 {
   6529   struct TestLookupWebhooks_Closure *cmp = cls;
   6530   if (NULL == cmp)
   6531     return;
   6532   cmp->results_length += 1;
   6533   for (unsigned int i = 0; cmp->webhooks_to_cmp_length > i; ++i)
   6534   {
   6535     if ((0 == strcmp (cmp->webhooks_to_cmp[i].webhook.event_type,
   6536                       event_type)) &&
   6537         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.url,
   6538                       url)) &&
   6539         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.http_method,
   6540                       http_method)) &&
   6541         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.header_template,
   6542                       header_template)) &&
   6543         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.body_template,
   6544                       body_template)) )
   6545       cmp->results_matching[i] += 1;
   6546   }
   6547 }
   6548 
   6549 
   6550 /**
   6551  * Tests looking up webhooks by event for an instance.
   6552  *
   6553  * @param instance the instance to query from.
   6554  * @param webhooks_length the number of webhooks we are expecting.
   6555  * @param webhooks the list of webhooks that we expect to be found.
   6556  * @return 0 when successful, 1 otherwise.
   6557  */
   6558 static int
   6559 test_lookup_webhook_by_event (const struct InstanceData *instance,
   6560                               unsigned int webhooks_length,
   6561                               const struct WebhookData *webhooks)
   6562 {
   6563   unsigned int results_matching[webhooks_length];
   6564   struct TestLookupWebhooks_Closure cls = {
   6565     .webhooks_to_cmp_length = webhooks_length,
   6566     .webhooks_to_cmp = webhooks,
   6567     .results_matching = results_matching,
   6568     .results_length = 0
   6569   };
   6570   memset (results_matching, 0, sizeof (unsigned int) * webhooks_length);
   6571   if (0 > TALER_MERCHANTDB_lookup_webhook_by_event (pg,
   6572                                                     instance->instance.id,
   6573                                                     webhooks->webhook.event_type,
   6574                                                     &lookup_webhook_by_event_cb,
   6575                                                     &cls))
   6576   {
   6577     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6578                 "Lookup webhooks by event failed\n");
   6579     return 1;
   6580   }
   6581 
   6582   if (webhooks_length != cls.results_length)
   6583   {
   6584     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6585                 "Lookup webhooks by event failed: incorrect number of results\n");
   6586     return 1;
   6587   }
   6588   for (unsigned int i = 0; webhooks_length > i; ++i)
   6589   {
   6590     if (1 != cls.results_matching[i])
   6591     {
   6592       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6593                   "Lookup webhooks by event failed: mismatched data\n");
   6594       return 1;
   6595     }
   6596   }
   6597   return 0;
   6598 }
   6599 
   6600 
   6601 /**
   6602  * Tests deleting a webhook.
   6603  *
   6604  * @param instance the instance to delete the webhook from.
   6605  * @param webhook the webhook that should be deleted.
   6606  * @param expected_result the result that we expect the DB to return.
   6607  * @return 0 when successful, 1 otherwise.
   6608  */
   6609 static int
   6610 test_delete_webhook (const struct InstanceData *instance,
   6611                      const struct WebhookData *webhook,
   6612                      enum GNUNET_DB_QueryStatus expected_result)
   6613 {
   6614   TEST_COND_RET_ON_FAIL (expected_result ==
   6615                          TALER_MERCHANTDB_delete_webhook (pg,
   6616                                                           instance->instance.id,
   6617                                                           webhook->id),
   6618                          "Delete webhook failed\n");
   6619   return 0;
   6620 }
   6621 
   6622 
   6623 /**
   6624  * Closure for webhook tests.
   6625  */
   6626 struct TestWebhooks_Closure
   6627 {
   6628   /**
   6629    * The instance to use for this test.
   6630    */
   6631   struct InstanceData instance;
   6632 
   6633   /**
   6634    * The array of webhooks.
   6635    */
   6636   struct WebhookData webhooks[3];
   6637 };
   6638 
   6639 
   6640 /**
   6641  * Sets up the data structures used in the webhook tests.
   6642  *
   6643  * @param cls the closure to fill with test data.
   6644  */
   6645 static void
   6646 pre_test_webhooks (struct TestWebhooks_Closure *cls)
   6647 {
   6648   /* Instance */
   6649   make_instance ("test_inst_webhooks",
   6650                  &cls->instance);
   6651 
   6652   /* Webhooks */
   6653   make_webhook ("test_webhooks_wb_0",
   6654                 &cls->webhooks[0]);
   6655 
   6656   make_webhook ("test_webhooks_wb_1",
   6657                 &cls->webhooks[1]);
   6658   cls->webhooks[1].webhook.event_type = "Test paid";
   6659   cls->webhooks[1].webhook.url = "https://example.com";
   6660   cls->webhooks[1].webhook.http_method = "POST";
   6661   cls->webhooks[1].webhook.header_template = "Authorization:1XYJAOR493O";
   6662   cls->webhooks[1].webhook.body_template = "$Amount";
   6663 
   6664   make_webhook ("test_webhooks_wb_2",
   6665                 &cls->webhooks[2]);
   6666   cls->webhooks[2].webhook.event_type = "Test paid";
   6667   cls->webhooks[2].webhook.url = "https://examplerefund.com";
   6668   cls->webhooks[2].webhook.http_method = "POST";
   6669   cls->webhooks[2].webhook.header_template = "Authorization:XY6ORK52JEO";
   6670   cls->webhooks[2].webhook.body_template = "$Amount";
   6671 }
   6672 
   6673 
   6674 /**
   6675  * Handles all teardown after testing.
   6676  *
   6677  * @param cls the closure containing memory to be freed.
   6678  */
   6679 static void
   6680 post_test_webhooks (struct TestWebhooks_Closure *cls)
   6681 {
   6682   free_instance_data (&cls->instance);
   6683 }
   6684 
   6685 
   6686 /**
   6687  * Runs the tests for webhooks.
   6688  *
   6689  * @param cls the container of the test data.
   6690  * @return 0 on success, 1 otherwise.
   6691  */
   6692 static int
   6693 run_test_webhooks (struct TestWebhooks_Closure *cls)
   6694 {
   6695 
   6696   /* Test that insert without an instance fails */
   6697   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6698                                          &cls->webhooks[0],
   6699                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6700   /* Insert the instance */
   6701   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   6702                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6703   /* Test inserting a webhook */
   6704   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6705                                          &cls->webhooks[0],
   6706                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6707   /* Test that double insert fails */
   6708   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6709                                          &cls->webhooks[0],
   6710                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6711   /* Test lookup of individual webhooks */
   6712   TEST_RET_ON_FAIL (test_lookup_webhook (&cls->instance,
   6713                                          &cls->webhooks[0]));
   6714   /* Make sure it fails correctly for webhooks that don't exist */
   6715   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   6716       TALER_MERCHANTDB_lookup_webhook (pg,
   6717                                        cls->instance.instance.id,
   6718                                        "nonexistent_webhook",
   6719                                        NULL))
   6720   {
   6721     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6722                 "Lookup webhook failed\n");
   6723     return 1;
   6724   }
   6725   /* Test webhook update */
   6726   cls->webhooks[0].webhook.event_type =
   6727     "Test paid";
   6728   cls->webhooks[0].webhook.url =
   6729     "example.com";
   6730   cls->webhooks[0].webhook.http_method =
   6731     "POST";
   6732   cls->webhooks[0].webhook.header_template =
   6733     "Authorization:WEKFOEKEXZ";
   6734   cls->webhooks[0].webhook.body_template =
   6735     "$Amount";
   6736   TEST_RET_ON_FAIL (test_update_webhook (&cls->instance,
   6737                                          &cls->webhooks[0],
   6738                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6739 
   6740   TEST_RET_ON_FAIL (test_lookup_webhook (&cls->instance,
   6741                                          &cls->webhooks[0]));
   6742   TEST_RET_ON_FAIL (test_update_webhook (&cls->instance,
   6743                                          &cls->webhooks[1],
   6744                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6745   /* Test collective webhook lookup */
   6746   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6747                                          &cls->webhooks[1],
   6748                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6749   TEST_RET_ON_FAIL (test_lookup_webhooks (&cls->instance,
   6750                                           2,
   6751                                           cls->webhooks));
   6752   TEST_RET_ON_FAIL (test_lookup_webhook_by_event (&cls->instance,
   6753                                                   2,
   6754                                                   cls->webhooks));
   6755   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6756                                          &cls->webhooks[2],
   6757                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6758 
   6759   /* Test webhook deletion */
   6760   TEST_RET_ON_FAIL (test_delete_webhook (&cls->instance,
   6761                                          &cls->webhooks[1],
   6762                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6763   /* Test double deletion fails */
   6764   TEST_RET_ON_FAIL (test_delete_webhook (&cls->instance,
   6765                                          &cls->webhooks[1],
   6766                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6767   cls->webhooks[1] = cls->webhooks[2];
   6768   TEST_RET_ON_FAIL (test_lookup_webhooks (&cls->instance,
   6769                                           2,
   6770                                           cls->webhooks));
   6771   TEST_RET_ON_FAIL (test_lookup_webhook_by_event (&cls->instance,
   6772                                                   2,
   6773                                                   cls->webhooks));
   6774   return 0;
   6775 }
   6776 
   6777 
   6778 /**
   6779  * Takes care of webhook testing.
   6780  *
   6781  * @return 0 on success, 1 otherwise.
   6782  */
   6783 static int
   6784 test_webhooks (void)
   6785 {
   6786   struct TestWebhooks_Closure test_cls;
   6787   int test_result;
   6788 
   6789   pre_test_webhooks (&test_cls);
   6790   test_result = run_test_webhooks (&test_cls);
   6791   post_test_webhooks (&test_cls);
   6792   return test_result;
   6793 }
   6794 
   6795 
   6796 /* *********** Pending Webhooks ********** */
   6797 
   6798 /**
   6799  * A container for data relevant to a pending webhook.
   6800  */
   6801 struct PendingWebhookData
   6802 {
   6803   /**
   6804    * Reference to the configured webhook template.
   6805    */
   6806   uint64_t webhook_serial;
   6807 
   6808   /**
   6809    * The details of the pending webhook.
   6810    */
   6811   struct TALER_MERCHANTDB_PendingWebhookDetails pwebhook;
   6812 };
   6813 
   6814 
   6815 /**
   6816  * Creates a pending webhook for testing with.
   6817  *
   6818  * @param serial reference to the configured webhook template.
   6819  * @param pwebhook the pending webhook data to fill.
   6820  */
   6821 static void
   6822 make_pending_webhook (uint64_t webhook_serial,
   6823                       struct PendingWebhookData *pwebhook)
   6824 {
   6825   pwebhook->webhook_serial = webhook_serial;
   6826   pwebhook->pwebhook.next_attempt = GNUNET_TIME_UNIT_ZERO_ABS;
   6827   pwebhook->pwebhook.retries = 0;
   6828   pwebhook->pwebhook.url = "https://exampletest.com";
   6829   pwebhook->pwebhook.http_method = "POST";
   6830   pwebhook->pwebhook.header = "Authorization:XYJAORKJEO";
   6831   pwebhook->pwebhook.body = "$Amount";
   6832 }
   6833 
   6834 
   6835 /**
   6836  * Tests inserting pending webhook data into the database.
   6837  *
   6838  * @param instance the instance to insert the pending webhook for.
   6839  * @param pending webhook the pending webhook data to insert.
   6840  * @param expected_result the result we expect the db to return.
   6841  * @return 0 when successful, 1 otherwise.
   6842  */
   6843 static int
   6844 test_insert_pending_webhook (const struct InstanceData *instance,
   6845                              struct PendingWebhookData *pwebhook,
   6846                              enum GNUNET_DB_QueryStatus expected_result)
   6847 {
   6848 
   6849   TEST_COND_RET_ON_FAIL (expected_result ==
   6850                          TALER_MERCHANTDB_insert_pending_webhook (pg,
   6851                                                                   instance->instance.id,
   6852                                                                   pwebhook->
   6853                                                                   webhook_serial,
   6854                                                                   pwebhook->pwebhook.url,
   6855                                                                   pwebhook->pwebhook.
   6856                                                                   http_method,
   6857                                                                   pwebhook->pwebhook.
   6858                                                                   header,
   6859                                                                   pwebhook->pwebhook.body
   6860                                                                   ),
   6861                          "Insert pending webhook failed\n");
   6862   return 0;
   6863 }
   6864 
   6865 
   6866 /**
   6867  * Tests updating pending webhook data in the database.
   6868  *
   6869  * @param instance the instance to update the pending webhook for.
   6870  * @param pending webhook the pending webhook data to update.
   6871  * @param expected_result the result we expect the db to return.
   6872  * @return 0 when successful, 1 otherwise.
   6873  */
   6874 static int
   6875 test_update_pending_webhook (const struct InstanceData *instance,
   6876                              struct PendingWebhookData *pwebhook,
   6877                              enum GNUNET_DB_QueryStatus expected_result)
   6878 {
   6879   pwebhook->pwebhook.next_attempt = GNUNET_TIME_relative_to_absolute (
   6880     GNUNET_TIME_UNIT_HOURS);
   6881   pwebhook->pwebhook.retries++;
   6882   TEST_COND_RET_ON_FAIL (expected_result ==
   6883                          TALER_MERCHANTDB_update_pending_webhook (pg,
   6884                                                                   pwebhook->
   6885                                                                   webhook_serial,
   6886                                                                   pwebhook->pwebhook.
   6887                                                                   next_attempt),
   6888                          "Update pending webhook failed\n");
   6889   return 0;
   6890 }
   6891 
   6892 
   6893 /**
   6894  * Container for information for looking up the row number of a deposit.
   6895  */
   6896 struct LookupPendingWebhookSerial_Closure
   6897 {
   6898   /**
   6899    * The pending webhook we're looking for.
   6900    */
   6901   const struct PendingWebhookData *pwebhook;
   6902 
   6903   /**
   6904    * The serial found.
   6905    */
   6906   uint64_t webhook_pending_serial;
   6907 };
   6908 
   6909 
   6910 /**
   6911  * Function called after calling @e test_lookup_all_webhook,
   6912  * test_lookup_future_webhook and test_lookup_pending_webhook
   6913  *
   6914  * @param cls a pointer to the lookup closure.
   6915  * @param webhook_serial reference to the configured webhook template.
   6916  */
   6917 static void
   6918 get_pending_serial_cb (void *cls,
   6919                        uint64_t webhook_pending_serial,
   6920                        struct GNUNET_TIME_Absolute next_attempt,
   6921                        uint32_t retries,
   6922                        const char *url,
   6923                        const char *http_method,
   6924                        const char *header,
   6925                        const char *body)
   6926 {
   6927   struct LookupPendingWebhookSerial_Closure *lpw = cls;
   6928 
   6929   if ((0 == strcmp (lpw->pwebhook->pwebhook.url,
   6930                     url)) &&
   6931       (0 == strcmp (lpw->pwebhook->pwebhook.http_method,
   6932                     http_method)) &&
   6933       (0 == strcmp (lpw->pwebhook->pwebhook.header,
   6934                     header)) &&
   6935       (0 == strcmp (lpw->pwebhook->pwebhook.body,
   6936                     body)) )
   6937   {
   6938     lpw->webhook_pending_serial = webhook_pending_serial;
   6939   }
   6940   /* else
   6941     {
   6942       fprintf(stdout, "next_attempt: %lu vs %lu\n", lpw->pwebhook->pwebhook.next_attempt.abs_value_us, next_attempt.abs_value_us);
   6943       fprintf(stdout, "retries: %d vs %d\n", lpw->pwebhook->pwebhook.retries, retries);
   6944       fprintf(stdout, "url: %s vs %s\n", lpw->pwebhook->pwebhook.url, url);
   6945       fprintf(stdout, "http_method: %s vs %s\n", lpw->pwebhook->pwebhook.http_method, http_method);
   6946       fprintf(stdout, "header: %s vs %s\n", lpw->pwebhook->pwebhook.header, header);
   6947       fprintf(stdout, "body: %s vs %s\n", lpw->pwebhook->pwebhook.body, body);
   6948       }*/
   6949 }
   6950 
   6951 
   6952 /**
   6953  * Convenience function to retrieve the row number of a webhook pending in the database.
   6954  *
   6955  * @param instance the instance to get webhook pending(wp) from.
   6956  * @param webhook pending the wp to lookup the serial for.
   6957  * @return the row number of the deposit.
   6958  */
   6959 static uint64_t
   6960 get_pending_serial (const struct InstanceData *instance,
   6961                     const struct PendingWebhookData *pwebhook)
   6962 {
   6963   struct LookupPendingWebhookSerial_Closure lpw = {
   6964     .pwebhook = pwebhook,
   6965     .webhook_pending_serial = 0
   6966   };
   6967 
   6968   GNUNET_assert (0 <
   6969                  TALER_MERCHANTDB_lookup_all_webhooks (pg,
   6970                                                        instance->instance.id,
   6971                                                        0,
   6972                                                        INT_MAX,
   6973                                                        &get_pending_serial_cb,
   6974                                                        &lpw));
   6975   GNUNET_assert (0 != lpw.webhook_pending_serial);
   6976 
   6977   return lpw.webhook_pending_serial;
   6978 }
   6979 
   6980 
   6981 /**
   6982  * Closure for testing pending webhook lookup
   6983  */
   6984 struct TestLookupPendingWebhooks_Closure
   6985 {
   6986   /**
   6987    * Number of webhook serial to compare to
   6988    */
   6989   unsigned int webhooks_to_cmp_length;
   6990 
   6991   /**
   6992    * Pointer to array of webhook serials
   6993    */
   6994   const struct PendingWebhookData *webhooks_to_cmp;
   6995 
   6996   /**
   6997    * Pointer to array of number of matches for each pending webhook
   6998    */
   6999   unsigned int *results_matching;
   7000 
   7001   /**
   7002    * Total number of results returned
   7003    */
   7004   unsigned int results_length;
   7005 };
   7006 
   7007 
   7008 /**
   7009  * Function called after calling @e test_lookup_all_webhook,
   7010  * test_lookup_future_webhook and test_lookup_pending_webhook
   7011  *
   7012  * @param cls a pointer to the lookup closure.
   7013  * @param webhook_serial reference to the configured webhook template.
   7014  */
   7015 static void
   7016 lookup_pending_webhooks_cb (void *cls,
   7017                             uint64_t webhook_pending_serial,
   7018                             struct GNUNET_TIME_Absolute next_attempt,
   7019                             uint32_t retries,
   7020                             const char *url,
   7021                             const char *http_method,
   7022                             const char *header,
   7023                             const char *body)
   7024 {
   7025   struct TestLookupPendingWebhooks_Closure *cmp = cls;
   7026 
   7027   cmp->results_length++;
   7028   for (unsigned int i = 0; cmp->webhooks_to_cmp_length > i; ++i)
   7029   {
   7030     if ((0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.url,
   7031                       url)) &&
   7032         (0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.http_method,
   7033                       http_method)) &&
   7034         (0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.header,
   7035                       header)) &&
   7036         (0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.body,
   7037                       body)) )
   7038     {
   7039       cmp->results_matching[i]++;
   7040     }
   7041   }
   7042 }
   7043 
   7044 
   7045 /**
   7046  * Tests looking up the pending webhook for an instance.
   7047  *
   7048  * @param instance the instance to query from.
   7049  * @param pwebhooks_length the number of pending webhook we are expecting.
   7050  * @param pwebhooks the list of pending webhooks that we expect to be found.
   7051  * @return 0 when successful, 1 otherwise.
   7052  */
   7053 static int
   7054 test_lookup_pending_webhooks (const struct InstanceData *instance,
   7055                               unsigned int pwebhooks_length,
   7056                               const struct PendingWebhookData *pwebhooks)
   7057 {
   7058   unsigned int results_matching[pwebhooks_length];
   7059   struct TestLookupPendingWebhooks_Closure cls = {
   7060     .webhooks_to_cmp_length = pwebhooks_length,
   7061     .webhooks_to_cmp = pwebhooks,
   7062     .results_matching = results_matching,
   7063     .results_length = 0
   7064   };
   7065 
   7066   memset (results_matching, 0, sizeof (results_matching));
   7067   if (0 > TALER_MERCHANTDB_lookup_pending_webhooks (pg,
   7068                                                     &lookup_pending_webhooks_cb,
   7069                                                     &cls))
   7070   {
   7071     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7072                 "Lookup pending webhook failed\n");
   7073     return 1;
   7074   }
   7075   if (pwebhooks_length != cls.results_length)
   7076   {
   7077     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7078                 "Lookup pending webhook failed: incorrect number of results\n");
   7079     return 1;
   7080   }
   7081   for (unsigned int i = 0; i < pwebhooks_length; i++)
   7082   {
   7083     if (1 != cls.results_matching[i])
   7084     {
   7085       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7086                   "Lookup pending webhook failed: mismatched data\n");
   7087       return 1;
   7088     }
   7089   }
   7090   return 0;
   7091 }
   7092 
   7093 
   7094 /**
   7095  * Tests looking up the future webhook to send for an instance.
   7096  *
   7097  * @param instance the instance to query from.
   7098  * @param pwebhooks_length the number of pending webhook we are expecting.
   7099  * @param pwebhooks the list of pending webhooks that we expect to be found.
   7100  * @return 0 when successful, 1 otherwise.
   7101  */
   7102 static int
   7103 test_lookup_future_webhook (const struct InstanceData *instance,
   7104                             unsigned int pwebhooks_length,
   7105                             const struct PendingWebhookData *pwebhooks)
   7106 {
   7107   unsigned int results_matching[pwebhooks_length];
   7108   struct TestLookupPendingWebhooks_Closure cls = {
   7109     .webhooks_to_cmp_length = pwebhooks_length,
   7110     .webhooks_to_cmp = pwebhooks,
   7111     .results_matching = results_matching,
   7112     .results_length = 0
   7113   };
   7114 
   7115   memset (results_matching, 0, sizeof (results_matching));
   7116   if (0 > TALER_MERCHANTDB_lookup_future_webhook (pg,
   7117                                                   &lookup_pending_webhooks_cb,
   7118                                                   &cls))
   7119   {
   7120     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7121                 "Lookup future webhook failed\n");
   7122     return 1;
   7123   }
   7124   if (pwebhooks_length != cls.results_length)
   7125   {
   7126     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7127                 "Lookup future webhook failed: incorrect number of results\n");
   7128     return 1;
   7129   }
   7130   for (unsigned int i = 0; pwebhooks_length > i; ++i)
   7131   {
   7132     if (1 != cls.results_matching[i])
   7133     {
   7134       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7135                   "Lookup future webhook failed: mismatched data\n");
   7136       return 1;
   7137     }
   7138   }
   7139   return 0;
   7140 }
   7141 
   7142 
   7143 /**
   7144  * Tests looking up all the pending webhook for an instance.
   7145  *
   7146  * @param instance the instance to query from.
   7147  * @param pwebhooks_length the number of pending webhook we are expecting.
   7148  * @param pwebhooks the list of pending webhooks that we expect to be found.
   7149  * @return 0 when successful, 1 otherwise.
   7150  */
   7151 static int
   7152 test_lookup_all_webhooks (const struct InstanceData *instance,
   7153                           unsigned int pwebhooks_length,
   7154                           const struct PendingWebhookData *pwebhooks)
   7155 {
   7156   uint64_t max_results = 2;
   7157   uint64_t min_row = 0;
   7158   unsigned int results_matching[GNUNET_NZL (pwebhooks_length)];
   7159   struct TestLookupPendingWebhooks_Closure cls = {
   7160     .webhooks_to_cmp_length = pwebhooks_length,
   7161     .webhooks_to_cmp = pwebhooks,
   7162     .results_matching = results_matching,
   7163     .results_length = 0
   7164   };
   7165 
   7166   memset (results_matching,
   7167           0,
   7168           sizeof (results_matching));
   7169   if (0 > TALER_MERCHANTDB_lookup_all_webhooks (pg,
   7170                                                 instance->instance.id,
   7171                                                 min_row,
   7172                                                 max_results,
   7173                                                 &lookup_pending_webhooks_cb,
   7174                                                 &cls))
   7175   {
   7176     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7177                 "Lookup all webhooks failed\n");
   7178     return 1;
   7179   }
   7180   if (pwebhooks_length != cls.results_length)
   7181   {
   7182     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7183                 "Lookup all webhooks failed: incorrect number of results\n");
   7184     return 1;
   7185   }
   7186   for (unsigned int i = 0; pwebhooks_length > i; ++i)
   7187   {
   7188     if (1 != cls.results_matching[i])
   7189     {
   7190       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7191                   "Lookup all webhooks failed: mismatched data\n");
   7192       return 1;
   7193     }
   7194   }
   7195   return 0;
   7196 }
   7197 
   7198 
   7199 /**
   7200  * Tests deleting a pending webhook.
   7201  *
   7202  * @param instance the instance to delete the pending webhook from.
   7203  * @param pwebhook the pending webhook that should be deleted.
   7204  * @param expected_result the result that we expect the DB to return.
   7205  * @return 0 when successful, 1 otherwise.
   7206  */
   7207 static int
   7208 test_delete_pending_webhook (uint64_t webhooks_pending_serial,
   7209                              enum GNUNET_DB_QueryStatus expected_result)
   7210 {
   7211 
   7212   TEST_COND_RET_ON_FAIL (expected_result ==
   7213                          TALER_MERCHANTDB_delete_pending_webhook (pg,
   7214                                                                   webhooks_pending_serial),
   7215                          "Delete webhook failed\n");
   7216   return 0;
   7217 }
   7218 
   7219 
   7220 /**
   7221  * Closure for pending webhook tests.
   7222  */
   7223 struct TestPendingWebhooks_Closure
   7224 {
   7225   /**
   7226    * The instance to use for this test.
   7227    */
   7228   struct InstanceData instance;
   7229 
   7230   /**
   7231    * The array of pending webhooks.
   7232    */
   7233   struct PendingWebhookData pwebhooks[2];
   7234 };
   7235 
   7236 
   7237 /**
   7238  * Sets up the data structures used in the pending webhook tests.
   7239  *
   7240  * @param cls the closure to fill with test data.
   7241  */
   7242 static void
   7243 pre_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls)
   7244 {
   7245   /* Instance */
   7246   make_instance ("test_inst_pending_webhooks",
   7247                  &cls->instance);
   7248 
   7249   /* Webhooks */
   7250   make_pending_webhook (1,
   7251                         &cls->pwebhooks[0]);
   7252 
   7253   make_pending_webhook (4,
   7254                         &cls->pwebhooks[1]);
   7255   cls->pwebhooks[1].pwebhook.url = "https://test.com";
   7256   cls->pwebhooks[1].pwebhook.http_method = "POST";
   7257   cls->pwebhooks[1].pwebhook.header = "Authorization:XYJAO5R06EO";
   7258   cls->pwebhooks[1].pwebhook.body = "$Amount";
   7259 }
   7260 
   7261 
   7262 /**
   7263  * Handles all teardown after testing.
   7264  *
   7265  * @param cls the closure containing memory to be freed.
   7266  */
   7267 static void
   7268 post_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls)
   7269 {
   7270   free_instance_data (&cls->instance);
   7271 }
   7272 
   7273 
   7274 /**
   7275  * Runs the tests for pending webhooks.
   7276  *
   7277  * @param cls the container of the test data.
   7278  * @return 0 on success, 1 otherwise.
   7279  */
   7280 static int
   7281 run_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls)
   7282 {
   7283   uint64_t webhook_pending_serial0;
   7284   uint64_t webhook_pending_serial1;
   7285 
   7286   /* Test that insert without an instance fails */
   7287   TEST_RET_ON_FAIL (test_insert_pending_webhook (&cls->instance,
   7288                                                  &cls->pwebhooks[0],
   7289                                                  GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   7290 
   7291   /* Insert the instance */
   7292   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   7293                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7294 
   7295   /* Test inserting a pending webhook */
   7296   TEST_RET_ON_FAIL (test_insert_pending_webhook (&cls->instance,
   7297                                                  &cls->pwebhooks[0],
   7298                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7299   TEST_RET_ON_FAIL (test_insert_pending_webhook (&cls->instance,
   7300                                                  &cls->pwebhooks[1],
   7301                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7302   /* Test collective pending webhook lookup */
   7303   TEST_RET_ON_FAIL (test_lookup_pending_webhooks (&cls->instance,
   7304                                                   2,
   7305                                                   cls->pwebhooks));
   7306   /* Test pending webhook update */
   7307   TEST_RET_ON_FAIL (test_update_pending_webhook (&cls->instance,
   7308                                                  &cls->pwebhooks[0],
   7309                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7310   TEST_RET_ON_FAIL (test_lookup_future_webhook (&cls->instance,
   7311                                                 1,
   7312                                                 &cls->pwebhooks[1]));
   7313   TEST_RET_ON_FAIL (test_update_pending_webhook (&cls->instance,
   7314                                                  &cls->pwebhooks[1],
   7315                                                  GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   7316   // ???
   7317   TEST_RET_ON_FAIL (test_lookup_all_webhooks (&cls->instance,
   7318                                               2,
   7319                                               cls->pwebhooks));
   7320 
   7321   webhook_pending_serial0 = get_pending_serial (&cls->instance,
   7322                                                 &cls->pwebhooks[0]);
   7323   webhook_pending_serial1 = get_pending_serial (&cls->instance,
   7324                                                 &cls->pwebhooks[1]);
   7325 
   7326   /* Test webhook deletion */
   7327   TEST_RET_ON_FAIL (test_delete_pending_webhook (webhook_pending_serial1,
   7328                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7329   /* Test double deletion fails */
   7330   TEST_RET_ON_FAIL (test_delete_pending_webhook (webhook_pending_serial1,
   7331                                                  GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   7332   TEST_RET_ON_FAIL (test_delete_pending_webhook (webhook_pending_serial0,
   7333                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7334   TEST_RET_ON_FAIL (test_lookup_all_webhooks (&cls->instance,
   7335                                               0,
   7336                                               NULL));
   7337   return 0;
   7338 }
   7339 
   7340 
   7341 /**
   7342  * Takes care of pending webhook testing.
   7343  *
   7344  * @return 0 on success, 1 otherwise.
   7345  */
   7346 static int
   7347 test_pending_webhooks (void)
   7348 {
   7349   struct TestPendingWebhooks_Closure test_cls;
   7350   int test_result;
   7351 
   7352   pre_test_pending_webhooks (&test_cls);
   7353   test_result = run_test_pending_webhooks (&test_cls);
   7354   post_test_pending_webhooks (&test_cls);
   7355   return test_result;
   7356 }
   7357 
   7358 
   7359 /**
   7360  * Function that runs all tests.
   7361  *
   7362  * @return 0 on success, 1 otherwise.
   7363  */
   7364 static int
   7365 run_tests (void)
   7366 {
   7367   TEST_RET_ON_FAIL (test_instances ());
   7368   TEST_RET_ON_FAIL (test_products ());
   7369   TEST_RET_ON_FAIL (test_orders ());
   7370   TEST_RET_ON_FAIL (test_deposits ());
   7371   TEST_RET_ON_FAIL (test_transfers ());
   7372   TEST_RET_ON_FAIL (test_refunds ());
   7373   TEST_RET_ON_FAIL (test_lookup_orders_all_filters ());
   7374   TEST_RET_ON_FAIL (test_kyc ());
   7375   TEST_RET_ON_FAIL (test_templates ());
   7376   TEST_RET_ON_FAIL (test_webhooks ());
   7377   TEST_RET_ON_FAIL (test_pending_webhooks ());
   7378   return 0;
   7379 }
   7380 
   7381 
   7382 /**
   7383  * Main function that will be run by the scheduler.
   7384  *
   7385  * @param cls closure with config
   7386  */
   7387 static void
   7388 run (void *cls)
   7389 {
   7390   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
   7391 
   7392   /* Drop the tables to cleanup anything that might cause issues */
   7393   (void) TALER_MERCHANTDB_drop_tables (cfg);
   7394   if (GNUNET_OK !=
   7395       TALER_MERCHANTDB_create_tables (cfg))
   7396   {
   7397     result = 77;
   7398     return;
   7399   }
   7400   if (NULL == (pg = TALER_MERCHANTDB_connect (cfg)))
   7401   {
   7402     result = 77;
   7403     return;
   7404   }
   7405   /* Run the preflight */
   7406   TALER_MERCHANTDB_preflight (pg);
   7407 
   7408   result = run_tests ();
   7409   /* if (0 == result) result = run_test_templates (); */
   7410 
   7411   TALER_MERCHANTDB_disconnect (pg);
   7412   pg = NULL;
   7413   if (0 != result)
   7414     return;
   7415   if (GNUNET_OK !=
   7416       TALER_MERCHANTDB_drop_tables (cfg))
   7417   {
   7418     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7419                 "Dropping tables failed\n");
   7420     result = 1;
   7421     return;
   7422   }
   7423 }
   7424 
   7425 
   7426 /**
   7427  * Entry point for the tests.
   7428  */
   7429 int
   7430 main (int argc,
   7431       char *const argv[])
   7432 {
   7433   struct GNUNET_CONFIGURATION_Handle *cfg;
   7434 
   7435   GNUNET_log_setup (argv[0],
   7436                     "DEBUG",
   7437                     NULL);
   7438   cfg = GNUNET_CONFIGURATION_create (TALER_MERCHANT_project_data ());
   7439   if (GNUNET_OK !=
   7440       GNUNET_CONFIGURATION_parse (cfg,
   7441                                   "test-merchantdb-postgres.conf"))
   7442   {
   7443     GNUNET_break (0);
   7444     return 2;
   7445   }
   7446   GNUNET_SCHEDULER_run (&run,
   7447                         cfg);
   7448   GNUNET_CONFIGURATION_destroy (cfg);
   7449   return result;
   7450 }
   7451 
   7452 
   7453 /* end of test_merchantdb.c */