merchant

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

test_merchantdb.c (252419B)


      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 for %s/%s failed: wired status is wrong (expected %d got %d)\n",
   2166                 instance_id,
   2167                 order_id,
   2168                 expected_wired,
   2169                 wired);
   2170     return 1;
   2171   }
   2172   if (expected_paid != paid)
   2173   {
   2174     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2175                 "Lookup payment status failed: paid status is wrong\n");
   2176     return 1;
   2177   }
   2178   return 0;
   2179 }
   2180 
   2181 
   2182 /**
   2183  * Test marking an order as being wired.
   2184  *
   2185  * @param order_id the row of the order in the database.
   2186  * @param expected_result the result we expect the DB to return.
   2187  * @return 0 on success, 1 otherwise.
   2188  */
   2189 static int
   2190 test_mark_order_wired (uint64_t order_id,
   2191                        enum GNUNET_DB_QueryStatus expected_result)
   2192 {
   2193   TEST_COND_RET_ON_FAIL (expected_result ==
   2194                          TALER_MERCHANTDB_mark_order_wired (pg,
   2195                                                             order_id),
   2196                          "Mark order wired failed\n");
   2197   return 0;
   2198 }
   2199 
   2200 
   2201 /**
   2202  * Closure for order tests.
   2203  */
   2204 struct TestOrders_Closure
   2205 {
   2206   /**
   2207    * The instance to use for the order tests.
   2208    */
   2209   struct InstanceData instance;
   2210 
   2211   /**
   2212    * A product to use for the order tests.
   2213    */
   2214   struct ProductData product;
   2215 
   2216   /**
   2217    * The array of orders
   2218    */
   2219   struct OrderData orders[3];
   2220 };
   2221 
   2222 
   2223 /**
   2224  * Initializes order test data.
   2225  *
   2226  * @param cls the order test closure.
   2227  */
   2228 static void
   2229 pre_test_orders (struct TestOrders_Closure *cls)
   2230 {
   2231   /* Instance */
   2232   make_instance ("test_inst_orders",
   2233                  &cls->instance);
   2234 
   2235   /* Product */
   2236   make_product ("test_orders_pd_0",
   2237                 &cls->product);
   2238 
   2239   /* Orders */
   2240   make_order ("test_orders_od_0",
   2241               &cls->orders[0]);
   2242   make_order ("test_orders_od_1",
   2243               &cls->orders[1]);
   2244   make_order ("test_orders_od_2",
   2245               &cls->orders[2]);
   2246 
   2247   GNUNET_assert (0 ==
   2248                  json_object_set_new (cls->orders[1].contract,
   2249                                       "other_field",
   2250                                       json_string ("Second contract")));
   2251 
   2252   cls->orders[2].pay_deadline = GNUNET_TIME_UNIT_ZERO_TS;
   2253   GNUNET_assert (0 ==
   2254                  json_object_set_new (
   2255                    cls->orders[2].contract,
   2256                    "pay_deadline",
   2257                    GNUNET_JSON_from_timestamp (cls->orders[2].pay_deadline)));
   2258 }
   2259 
   2260 
   2261 /**
   2262  * Frees memory after order tests.
   2263  *
   2264  * @param cls the order test closure.
   2265  */
   2266 static void
   2267 post_test_orders (struct TestOrders_Closure *cls)
   2268 {
   2269   free_instance_data (&cls->instance);
   2270   free_product_data (&cls->product);
   2271   free_order_data (&cls->orders[0]);
   2272   free_order_data (&cls->orders[1]);
   2273   free_order_data (&cls->orders[2]);
   2274 }
   2275 
   2276 
   2277 /**
   2278  * Run the tests for orders.
   2279  *
   2280  * @param cls the order test closure.
   2281  * @return 0 on success, 1 on failure.
   2282  */
   2283 static int
   2284 run_test_orders (struct TestOrders_Closure *cls)
   2285 {
   2286   struct TALER_MERCHANTDB_OrderFilter filter = {
   2287     .paid = TALER_EXCHANGE_YNA_ALL,
   2288     .refunded = TALER_EXCHANGE_YNA_ALL,
   2289     .wired = TALER_EXCHANGE_YNA_ALL,
   2290     .date = GNUNET_TIME_UNIT_ZERO_TS,
   2291     .start_row = 0,
   2292     .delta = 8
   2293   };
   2294   uint64_t serial;
   2295 
   2296   /* Insert the instance */
   2297   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   2298                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2299   /* Test inserting an order */
   2300   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2301                                        &cls->orders[0],
   2302                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2303   /* Test double insert fails */
   2304   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2305                                        &cls->orders[0],
   2306                                        GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2307   /* Test lookup order */
   2308   TEST_RET_ON_FAIL (test_lookup_order (&cls->instance,
   2309                                        &cls->orders[0]));
   2310   /* Make sure it fails correctly for nonexistent orders */
   2311   {
   2312     struct TALER_MerchantPostDataHashP unused;
   2313 
   2314     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2315         TALER_MERCHANTDB_lookup_order (pg,
   2316                                        cls->instance.instance.id,
   2317                                        cls->orders[1].id,
   2318                                        NULL,
   2319                                        &unused,
   2320                                        NULL))
   2321     {
   2322       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2323                   "Lookup order failed\n");
   2324       return 1;
   2325     }
   2326   }
   2327   /* Test lookups on multiple orders */
   2328   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2329                                        &cls->orders[1],
   2330                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2331   serial = get_order_serial (&cls->instance,
   2332                              &cls->orders[0]);
   2333   TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   2334                                         &filter,
   2335                                         2,
   2336                                         cls->orders));
   2337   /* Test inserting contract terms */
   2338   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   2339                                                 &cls->orders[0],
   2340                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2341   /* Test double insert fails */
   2342   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   2343                                                 &cls->orders[0],
   2344                                                 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2345   /* Test order lock */
   2346   TEST_RET_ON_FAIL (test_insert_product (&cls->instance,
   2347                                          &cls->product,
   2348                                          0,
   2349                                          NULL,
   2350                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   2351                                          false,
   2352                                          false,
   2353                                          -1));
   2354   if (1 != TALER_MERCHANTDB_insert_order_lock (pg,
   2355                                                cls->instance.instance.id,
   2356                                                cls->orders[0].id,
   2357                                                cls->product.id,
   2358                                                5,
   2359                                                0))
   2360   {
   2361     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2362                 "Insert order lock failed\n");
   2363     return 1;
   2364   }
   2365   /* Test lookup contract terms */
   2366   TEST_RET_ON_FAIL (test_lookup_contract_terms (&cls->instance,
   2367                                                 &cls->orders[0]));
   2368   /* Test lookup fails for nonexistent contract terms */
   2369   {
   2370     json_t *lookup_contract = NULL;
   2371     uint64_t lookup_order_serial;
   2372 
   2373     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2374         TALER_MERCHANTDB_lookup_contract_terms (pg,
   2375                                                 cls->instance.instance.id,
   2376                                                 cls->orders[1].id,
   2377                                                 &lookup_contract,
   2378                                                 &lookup_order_serial,
   2379                                                 NULL))
   2380     {
   2381       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2382                   "Lookup contract terms failed\n");
   2383       GNUNET_assert (NULL == lookup_contract);
   2384       return 1;
   2385     }
   2386   }
   2387   /* Test update contract terms */
   2388   GNUNET_assert (0 ==
   2389                  json_object_set_new (cls->orders[0].contract,
   2390                                       "some_new_field",
   2391                                       json_string ("another value")));
   2392   TEST_RET_ON_FAIL (test_update_contract_terms (&cls->instance,
   2393                                                 &cls->orders[0],
   2394                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2395   TEST_RET_ON_FAIL (test_lookup_contract_terms (&cls->instance,
   2396                                                 &cls->orders[0]));
   2397   /* Test lookup order status */
   2398   TEST_RET_ON_FAIL (test_lookup_order_status (&cls->instance,
   2399                                               &cls->orders[0],
   2400                                               false));
   2401   {
   2402     struct TALER_PrivateContractHashP h_contract_terms;
   2403     bool order_paid = false;
   2404 
   2405     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2406         TALER_MERCHANTDB_lookup_order_status (pg,
   2407                                               cls->instance.instance.id,
   2408                                               cls->orders[1].id,
   2409                                               &h_contract_terms,
   2410                                               &order_paid))
   2411     {
   2412       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2413                   "Lookup order status failed\n");
   2414       return 1;
   2415     }
   2416   }
   2417   /* Test lookup payment status */
   2418   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2419                                                 cls->orders[0].id,
   2420                                                 NULL,
   2421                                                 false,
   2422                                                 false));
   2423   /* Test lookup order status fails for nonexistent order */
   2424   {
   2425     struct TALER_PrivateContractHashP h_contract_terms;
   2426     bool order_paid;
   2427 
   2428     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2429         TALER_MERCHANTDB_lookup_order_status (pg,
   2430                                               cls->instance.instance.id,
   2431                                               cls->orders[1].id,
   2432                                               &h_contract_terms,
   2433                                               &order_paid))
   2434     {
   2435       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2436                   "Lookup order status failed\n");
   2437       return 1;
   2438     }
   2439   }
   2440   /* Test marking contracts as paid */
   2441   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   2442                                              &cls->orders[0],
   2443                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2444   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2445                                                 cls->orders[0].id,
   2446                                                 NULL,
   2447                                                 true,
   2448                                                 false));
   2449   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2450                                                 cls->orders[0].id,
   2451                                                 "test_orders_session",
   2452                                                 true,
   2453                                                 false));
   2454   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2455                                                 cls->orders[0].id,
   2456                                                 "bad_session",
   2457                                                 false,
   2458                                                 false));
   2459   /* Test lookup order by fulfillment */
   2460   TEST_RET_ON_FAIL (test_lookup_order_by_fulfillment (&cls->instance,
   2461                                                       &cls->orders[0],
   2462                                                       "test_orders_session"));
   2463   {
   2464     char *order_id;
   2465     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   2466         TALER_MERCHANTDB_lookup_order_by_fulfillment (pg,
   2467                                                       cls->instance.instance.id,
   2468                                                       "fulfillment_url",
   2469                                                       "test_orders_session",
   2470                                                       false,
   2471                                                       &order_id))
   2472     {
   2473       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2474                   "Lookup order by fulfillment failed\n");
   2475       GNUNET_free (order_id);
   2476       return 1;
   2477     }
   2478   }
   2479   /* Test mark as paid fails for nonexistent order */
   2480   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   2481                                              &cls->orders[1],
   2482                                              GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2483   TEST_RET_ON_FAIL (test_lookup_order_status (&cls->instance,
   2484                                               &cls->orders[0],
   2485                                               true));
   2486   filter.paid = TALER_EXCHANGE_YNA_YES;
   2487   TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   2488                                         &filter,
   2489                                         1,
   2490                                         cls->orders));
   2491   /* Test marking orders as wired */
   2492   TEST_RET_ON_FAIL (test_mark_order_wired (serial,
   2493                                            GNUNET_DB_STATUS_SUCCESS_ONE_RESULT))
   2494   ;
   2495   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   2496                                                 cls->orders[0].id,
   2497                                                 NULL,
   2498                                                 true,
   2499                                                 true));
   2500   TEST_RET_ON_FAIL (test_mark_order_wired (1007,
   2501                                            GNUNET_DB_STATUS_SUCCESS_NO_RESULTS))
   2502   ;
   2503   /* If an order has been claimed and we aren't past
   2504      the pay deadline, we can't delete it. */
   2505   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2506                                        &cls->orders[0],
   2507                                        GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2508   /* Test we can't delete before the legal expiration */
   2509   TEST_RET_ON_FAIL (test_delete_contract_terms (&cls->instance,
   2510                                                 &cls->orders[0],
   2511                                                 GNUNET_TIME_UNIT_MONTHS,
   2512                                                 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2513   /* Test deleting contract terms */
   2514   TEST_RET_ON_FAIL (test_delete_contract_terms (&cls->instance,
   2515                                                 &cls->orders[0],
   2516                                                 GNUNET_TIME_UNIT_ZERO,
   2517                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2518   /* Test we can't delete something that doesn't exist */
   2519   TEST_RET_ON_FAIL (test_delete_contract_terms (&cls->instance,
   2520                                                 &cls->orders[0],
   2521                                                 GNUNET_TIME_UNIT_ZERO,
   2522                                                 GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2523   /* Test delete order where we aren't past
   2524      the deadline, but the order is unclaimed. */
   2525   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2526                                        &cls->orders[1],
   2527                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2528   TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   2529                                         &filter,
   2530                                         0,
   2531                                         NULL));
   2532   /* Test we can't delete something that doesn't exist */
   2533   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2534                                        &cls->orders[1],
   2535                                        GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   2536 
   2537   /* Test we can also delete a claimed order that's past the pay deadline. */
   2538   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   2539                                        &cls->orders[2],
   2540                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2541   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   2542                                                 &cls->orders[2],
   2543                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2544   TEST_RET_ON_FAIL (test_delete_order (&cls->instance,
   2545                                        &cls->orders[2],
   2546                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   2547   return 0;
   2548 }
   2549 
   2550 
   2551 /**
   2552  * Does all tasks for testing orders.
   2553  *
   2554  * @return 0 when successful, 1 otherwise.
   2555  */
   2556 static int
   2557 test_orders (void)
   2558 {
   2559   struct TestOrders_Closure test_cls;
   2560   int test_result;
   2561 
   2562   pre_test_orders (&test_cls);
   2563   test_result = run_test_orders (&test_cls);
   2564   post_test_orders (&test_cls);
   2565   return test_result;
   2566 }
   2567 
   2568 
   2569 /* ********** Deposits ********** */
   2570 
   2571 
   2572 /**
   2573  * A container for exchange signing key data.
   2574  */
   2575 struct ExchangeSignkeyData
   2576 {
   2577   /**
   2578    * The master private key of the exchange.
   2579    */
   2580   struct TALER_MasterPrivateKeyP master_priv;
   2581 
   2582   /**
   2583    * The master public key of the exchange.
   2584    */
   2585   struct TALER_MasterPublicKeyP master_pub;
   2586 
   2587   /**
   2588    * A signature made with the master keys.
   2589    */
   2590   struct TALER_MasterSignatureP master_sig;
   2591 
   2592   /**
   2593    * The private key of the exchange.
   2594    */
   2595   struct TALER_ExchangePrivateKeyP exchange_priv;
   2596 
   2597   /**
   2598    * The public key of the exchange.
   2599    */
   2600   struct TALER_ExchangePublicKeyP exchange_pub;
   2601 
   2602   /**
   2603    * When the signing key becomes valid.
   2604    */
   2605   struct GNUNET_TIME_Timestamp start_date;
   2606 
   2607   /**
   2608    * When the signing key stops being used.
   2609    */
   2610   struct GNUNET_TIME_Timestamp expire_date;
   2611 
   2612   /**
   2613    * When the signing key becomes invalid for proof.
   2614    */
   2615   struct GNUNET_TIME_Timestamp end_date;
   2616 };
   2617 
   2618 
   2619 /**
   2620  * Creates an exchange signing key.
   2621  *
   2622  * @param signkey the signing key data to fill.
   2623  */
   2624 static void
   2625 make_exchange_signkey (struct ExchangeSignkeyData *signkey)
   2626 {
   2627   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   2628 
   2629   GNUNET_CRYPTO_eddsa_key_create (&signkey->exchange_priv.eddsa_priv);
   2630   GNUNET_CRYPTO_eddsa_key_get_public (&signkey->exchange_priv.eddsa_priv,
   2631                                       &signkey->exchange_pub.eddsa_pub);
   2632   GNUNET_CRYPTO_eddsa_key_create (&signkey->master_priv.eddsa_priv);
   2633   GNUNET_CRYPTO_eddsa_key_get_public (&signkey->master_priv.eddsa_priv,
   2634                                       &signkey->master_pub.eddsa_pub);
   2635   signkey->start_date = now;
   2636   signkey->expire_date = now;
   2637   signkey->end_date = now;
   2638   TALER_exchange_offline_signkey_validity_sign (
   2639     &signkey->exchange_pub,
   2640     signkey->start_date,
   2641     signkey->expire_date,
   2642     signkey->end_date,
   2643     &signkey->master_priv,
   2644     &signkey->master_sig);
   2645 }
   2646 
   2647 
   2648 /**
   2649  * A container for deposit data.
   2650  */
   2651 struct DepositData
   2652 {
   2653   /**
   2654    * When the deposit was made.
   2655    */
   2656   struct GNUNET_TIME_Timestamp timestamp;
   2657 
   2658   /**
   2659    * Hash of the associated order's contract terms.
   2660    */
   2661   struct TALER_PrivateContractHashP h_contract_terms;
   2662 
   2663   /**
   2664    * Public key of the coin that has been deposited.
   2665    */
   2666   struct TALER_CoinSpendPublicKeyP coin_pub;
   2667 
   2668   /**
   2669    * Signature of the coin that has been deposited.
   2670    */
   2671   struct TALER_CoinSpendSignatureP coin_sig;
   2672 
   2673   /**
   2674    * URL of the exchange.
   2675    */
   2676   const char *exchange_url;
   2677 
   2678   /**
   2679    * Value of the coin with fees applied.
   2680    */
   2681   struct TALER_Amount amount_with_fee;
   2682 
   2683   /**
   2684    * Fee charged for deposit.
   2685    */
   2686   struct TALER_Amount deposit_fee;
   2687 
   2688   /**
   2689    * Fee to be charged in case of a refund.
   2690    */
   2691   struct TALER_Amount refund_fee;
   2692 
   2693   /**
   2694    * Fee charged after the money is wired.
   2695    */
   2696   struct TALER_Amount wire_fee;
   2697 
   2698   /**
   2699    * Hash of the wire details.
   2700    */
   2701   struct TALER_MerchantWireHashP h_wire;
   2702 
   2703   /**
   2704    * Signature the exchange made on this deposit.
   2705    */
   2706   struct TALER_ExchangeSignatureP exchange_sig;
   2707 
   2708 };
   2709 
   2710 
   2711 /**
   2712  * Generates deposit data for an order.
   2713  *
   2714  * @param instance the instance to make the deposit to.
   2715  * @param account the merchant account to use.
   2716  * @param order the order this deposit is for.
   2717  * @param signkey the signing key to use.
   2718  * @param deposit the deposit data to fill.
   2719  */
   2720 static void
   2721 make_deposit (const struct InstanceData *instance,
   2722               const struct TALER_MERCHANTDB_AccountDetails *account,
   2723               const struct OrderData *order,
   2724               const struct ExchangeSignkeyData *signkey,
   2725               struct DepositData *deposit)
   2726 {
   2727   struct TALER_CoinSpendPrivateKeyP coin_priv;
   2728   struct GNUNET_TIME_Timestamp now;
   2729   struct TALER_Amount amount_without_fee;
   2730 
   2731   now = GNUNET_TIME_timestamp_get ();
   2732   deposit->timestamp = now;
   2733   GNUNET_assert (GNUNET_OK ==
   2734                  TALER_JSON_contract_hash (order->contract,
   2735                                            &deposit->h_contract_terms));
   2736   GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv);
   2737   GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
   2738                                       &deposit->coin_pub.eddsa_pub);
   2739   deposit->exchange_url = "https://test-exchange/";
   2740   GNUNET_assert (GNUNET_OK ==
   2741                  TALER_string_to_amount ("EUR:50.00",
   2742                                          &deposit->amount_with_fee));
   2743   GNUNET_assert (GNUNET_OK ==
   2744                  TALER_string_to_amount ("EUR:1.00",
   2745                                          &deposit->deposit_fee));
   2746   GNUNET_assert (GNUNET_OK ==
   2747                  TALER_string_to_amount ("EUR:1.50",
   2748                                          &deposit->refund_fee));
   2749   GNUNET_assert (GNUNET_OK ==
   2750                  TALER_string_to_amount ("EUR:2.00",
   2751                                          &deposit->wire_fee));
   2752   GNUNET_assert (0 <=
   2753                  TALER_amount_subtract (&amount_without_fee,
   2754                                         &deposit->amount_with_fee,
   2755                                         &deposit->deposit_fee));
   2756   deposit->h_wire = account->h_wire;
   2757   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   2758                               &deposit->exchange_sig,
   2759                               sizeof (deposit->exchange_sig));
   2760   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   2761                               &deposit->coin_sig,
   2762                               sizeof (deposit->coin_sig));
   2763 }
   2764 
   2765 
   2766 /**
   2767  * Tests inserting an exchange signing key into the database.
   2768  *
   2769  * @param signkey the signing key to insert.
   2770  * @param expected_result the result we expect the database to return.
   2771  * @return 0 on success, 1 otherwise.
   2772  */
   2773 static int
   2774 test_insert_exchange_signkey (const struct ExchangeSignkeyData *signkey,
   2775                               enum GNUNET_DB_QueryStatus expected_result)
   2776 {
   2777   TEST_COND_RET_ON_FAIL (expected_result ==
   2778                          TALER_MERCHANTDB_insert_exchange_signkey (pg,
   2779                                                                    &signkey->master_pub,
   2780                                                                    &signkey->exchange_pub
   2781                                                                    ,
   2782                                                                    signkey->start_date,
   2783                                                                    signkey->expire_date,
   2784                                                                    signkey->end_date,
   2785                                                                    &signkey->master_sig),
   2786                          "Insert exchange signkey failed\n");
   2787   return 0;
   2788 }
   2789 
   2790 
   2791 /**
   2792  * Tests inserting a deposit into the database.
   2793  *
   2794  * @param instance the instance the deposit was made to.
   2795  * @param signkey the signing key used.
   2796  * @param deposit the deposit information to insert.
   2797  * @param expected_result the result we expect the database to return.
   2798  * @return 0 on success, 1 otherwise.
   2799  */
   2800 static int
   2801 test_insert_deposit (const struct InstanceData *instance,
   2802                      const struct ExchangeSignkeyData *signkey,
   2803                      const struct DepositData *deposit,
   2804                      enum GNUNET_DB_QueryStatus expected_result)
   2805 {
   2806   uint64_t row;
   2807   struct TALER_Amount awf;
   2808 
   2809   GNUNET_assert (0 <=
   2810                  TALER_amount_subtract (&awf,
   2811                                         &deposit->amount_with_fee,
   2812                                         &deposit->deposit_fee));
   2813   TEST_COND_RET_ON_FAIL (
   2814     GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   2815     TALER_MERCHANTDB_insert_deposit_confirmation (pg,
   2816                                                   instance->instance.id,
   2817                                                   deposit->timestamp,
   2818                                                   &deposit->h_contract_terms,
   2819                                                   deposit->exchange_url,
   2820                                                   deposit->timestamp,
   2821                                                   &awf,
   2822                                                   &deposit->wire_fee,
   2823                                                   &deposit->h_wire,
   2824                                                   &deposit->exchange_sig,
   2825                                                   &signkey->exchange_pub,
   2826                                                   &row),
   2827     "Insert deposit confirmation failed\n");
   2828   TEST_COND_RET_ON_FAIL (
   2829     expected_result ==
   2830     TALER_MERCHANTDB_insert_deposit (pg,
   2831                                      0,
   2832                                      row,
   2833                                      &deposit->coin_pub,
   2834                                      &deposit->coin_sig,
   2835                                      &deposit->amount_with_fee,
   2836                                      &deposit->deposit_fee,
   2837                                      &deposit->refund_fee,
   2838                                      GNUNET_TIME_absolute_get ()),
   2839     "Insert deposit failed\n");
   2840   return 0;
   2841 }
   2842 
   2843 
   2844 /**
   2845  * Closure for testing deposit lookup
   2846  */
   2847 struct TestLookupDeposits_Closure
   2848 {
   2849   /**
   2850    * Number of deposits to compare to
   2851    */
   2852   unsigned int deposits_to_cmp_length;
   2853 
   2854   /**
   2855    * Pointer to array of deposit data
   2856    */
   2857   const struct DepositData *deposits_to_cmp;
   2858 
   2859   /**
   2860    * Pointer to array of number of matches per deposit
   2861    */
   2862   unsigned int *results_matching;
   2863 
   2864   /**
   2865    * Total number of results returned
   2866    */
   2867   unsigned int results_length;
   2868 };
   2869 
   2870 
   2871 /**
   2872  * Called after 'test_lookup_deposits'.
   2873  *
   2874  * @param cls pointer to the test lookup closure.
   2875  * @param coin_pub public key of the coin deposited.
   2876  * @param amount_with_fee amount of the deposit with fees.
   2877  * @param deposit_fee fee charged for the deposit.
   2878  * @param refund_fee fee charged in case of a refund.
   2879  */
   2880 static void
   2881 lookup_deposits_cb (void *cls,
   2882                     const char *exchange_url,
   2883                     const struct TALER_CoinSpendPublicKeyP *coin_pub,
   2884                     const struct TALER_Amount *amount_with_fee,
   2885                     const struct TALER_Amount *deposit_fee,
   2886                     const struct TALER_Amount *refund_fee)
   2887 {
   2888   struct TestLookupDeposits_Closure *cmp = cls;
   2889   if (NULL == cmp)
   2890     return;
   2891   cmp->results_length += 1;
   2892   for (unsigned int i = 0; cmp->deposits_to_cmp_length > i; ++i)
   2893   {
   2894     if ((GNUNET_OK ==
   2895          TALER_amount_cmp_currency (
   2896            &cmp->deposits_to_cmp[i].amount_with_fee,
   2897            amount_with_fee)) &&
   2898         (0 ==
   2899          TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
   2900                            amount_with_fee)) &&
   2901         (GNUNET_OK ==
   2902          TALER_amount_cmp_currency (
   2903            &cmp->deposits_to_cmp[i].deposit_fee,
   2904            deposit_fee)) &&
   2905         (0 ==
   2906          TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
   2907                            deposit_fee)) &&
   2908         (GNUNET_OK ==
   2909          TALER_amount_cmp_currency (
   2910            &cmp->deposits_to_cmp[i].refund_fee,
   2911            refund_fee)) &&
   2912         (0 ==
   2913          TALER_amount_cmp (&cmp->deposits_to_cmp[i].refund_fee,
   2914                            refund_fee)))
   2915     {
   2916       cmp->results_matching[i] += 1;
   2917     }
   2918 
   2919   }
   2920 }
   2921 
   2922 
   2923 /**
   2924  * Tests looking up deposits from the database.
   2925  *
   2926  * @param instance the instance to lookup deposits from.
   2927  * @param h_contract_terms the contract terms that the deposits should have.
   2928  * @param deposits_length length of @e deposits.
   2929  * @param deposits the deposits we expect to be found.
   2930  * @return 0 on success, 1 otherwise.
   2931  */
   2932 static int
   2933 test_lookup_deposits (const struct InstanceData *instance,
   2934                       const struct TALER_PrivateContractHashP *h_contract_terms,
   2935                       unsigned int deposits_length,
   2936                       const struct DepositData *deposits)
   2937 {
   2938   unsigned int results_matching[GNUNET_NZL (deposits_length)];
   2939   struct TestLookupDeposits_Closure cmp = {
   2940     .deposits_to_cmp_length = deposits_length,
   2941     .deposits_to_cmp = deposits,
   2942     .results_matching = results_matching,
   2943     .results_length = 0
   2944   };
   2945   memset (results_matching,
   2946           0,
   2947           sizeof (unsigned int) * deposits_length);
   2948   TEST_COND_RET_ON_FAIL (0 <=
   2949                          TALER_MERCHANTDB_lookup_deposits (pg,
   2950                                                            instance->instance.id,
   2951                                                            h_contract_terms,
   2952                                                            &lookup_deposits_cb,
   2953                                                            &cmp),
   2954                          "Lookup deposits failed\n");
   2955   if (deposits_length != cmp.results_length)
   2956   {
   2957     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2958                 "Lookup deposits failed: incorrect number of results returned (%d)\n",
   2959                 cmp.results_length);
   2960     return 1;
   2961   }
   2962   for (unsigned int i = 0; deposits_length > i; ++i)
   2963   {
   2964     if (cmp.results_matching[i] != 1)
   2965     {
   2966       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   2967                   "Lookup deposits failed: mismatched data\n");
   2968       return 1;
   2969     }
   2970   }
   2971   return 0;
   2972 }
   2973 
   2974 
   2975 /**
   2976  * Called after 'test_lookup_deposits_contract_and_coin'.
   2977  *
   2978  * @param cls pointer to the test lookup closure.
   2979  * @param exchange_url URL to the exchange
   2980  * @param amount_with_fee amount of the deposit with fees.
   2981  * @param deposit_fee fee charged for the deposit.
   2982  * @param refund_fee fee charged in case of a refund.
   2983  * @param wire_fee fee charged when the money is wired.
   2984  * @param h_wire hash of the wire transfer details.
   2985  * @param deposit_timestamp when the deposit was made.
   2986  * @param refund_deadline deadline for refunding the deposit.
   2987  * @param exchange_sig signature the exchange made on the deposit.
   2988  * @param exchange_pub public key of the exchange.
   2989  */
   2990 static void
   2991 lookup_deposits_contract_coin_cb (
   2992   void *cls,
   2993   const char *exchange_url,
   2994   const struct TALER_Amount *amount_with_fee,
   2995   const struct TALER_Amount *deposit_fee,
   2996   const struct TALER_Amount *refund_fee,
   2997   const struct TALER_Amount *wire_fee,
   2998   const struct TALER_MerchantWireHashP *h_wire,
   2999   struct GNUNET_TIME_Timestamp deposit_timestamp,
   3000   struct GNUNET_TIME_Timestamp refund_deadline,
   3001   const struct TALER_ExchangeSignatureP *exchange_sig,
   3002   const struct TALER_ExchangePublicKeyP *exchange_pub)
   3003 {
   3004   struct TestLookupDeposits_Closure *cmp = cls;
   3005 
   3006   if (NULL == cmp)
   3007     return;
   3008   cmp->results_length++;
   3009   for (unsigned int i = 0; cmp->deposits_to_cmp_length > i; ++i)
   3010   {
   3011     if ((GNUNET_TIME_timestamp_cmp (cmp->deposits_to_cmp[i].timestamp,
   3012                                     ==,
   3013                                     deposit_timestamp)) &&
   3014         (0 == strcmp (cmp->deposits_to_cmp[i].exchange_url,
   3015                       exchange_url)) &&
   3016         (GNUNET_OK == TALER_amount_cmp_currency (
   3017            &cmp->deposits_to_cmp[i].amount_with_fee,
   3018            amount_with_fee)) &&
   3019         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
   3020                                 amount_with_fee)) &&
   3021         (GNUNET_OK == TALER_amount_cmp_currency (
   3022            &cmp->deposits_to_cmp[i].deposit_fee,
   3023            deposit_fee)) &&
   3024         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
   3025                                 deposit_fee)) &&
   3026         (GNUNET_OK == TALER_amount_cmp_currency (
   3027            &cmp->deposits_to_cmp[i].refund_fee,
   3028            refund_fee)) &&
   3029         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].refund_fee,
   3030                                 refund_fee)) &&
   3031         (GNUNET_OK == TALER_amount_cmp_currency (
   3032            &cmp->deposits_to_cmp[i].wire_fee,
   3033            wire_fee)) &&
   3034         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].wire_fee,
   3035                                 wire_fee)) &&
   3036         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].h_wire,
   3037                              h_wire)) &&
   3038         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].exchange_sig,
   3039                              exchange_sig)))
   3040     {
   3041       cmp->results_matching[i]++;
   3042     }
   3043   }
   3044 }
   3045 
   3046 
   3047 /**
   3048  * Tests lookup of deposits by contract and coin.
   3049  *
   3050  * @param instance the instance to lookup from.
   3051  * @param h_contract the contract terms the deposits should have.
   3052  * @param coin_pub the public key of the coin the deposits should have.
   3053  * @param deposits_length length of @e deposits.
   3054  * @param deposits the deposits the db is expected to find.
   3055  * @return 0 on success, 1 otherwise.
   3056  */
   3057 static int
   3058 test_lookup_deposits_contract_and_coin (
   3059   const struct InstanceData *instance,
   3060   const struct TALER_PrivateContractHashP *h_contract,
   3061   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   3062   unsigned int deposits_length,
   3063   const struct DepositData *deposits)
   3064 {
   3065   unsigned int results_matching[deposits_length];
   3066   struct TestLookupDeposits_Closure cmp = {
   3067     .deposits_to_cmp_length = deposits_length,
   3068     .deposits_to_cmp = deposits,
   3069     .results_matching = results_matching,
   3070     .results_length = 0
   3071   };
   3072   memset (results_matching,
   3073           0,
   3074           sizeof (unsigned int) * deposits_length);
   3075   TEST_COND_RET_ON_FAIL (
   3076     GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   3077     TALER_MERCHANTDB_lookup_deposits_by_contract_and_coin (
   3078       pg,
   3079       instance->instance.id,
   3080       h_contract,
   3081       coin_pub,
   3082       &lookup_deposits_contract_coin_cb,
   3083       &cmp),
   3084     "Lookup deposits by contract and coin failed\n");
   3085   if (deposits_length != cmp.results_length)
   3086   {
   3087     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3088                 "Lookup deposits failed: incorrect number of results returned\n");
   3089     return 1;
   3090   }
   3091   for (unsigned int i = 0; deposits_length > i; ++i)
   3092   {
   3093     if (cmp.results_matching[i] != 1)
   3094     {
   3095       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3096                   "Lookup deposits failed: mismatched data\n");
   3097       return 1;
   3098     }
   3099   }
   3100   return 0;
   3101 }
   3102 
   3103 
   3104 /**
   3105  * Called after 'test_lookup_deposits_by_order'.
   3106  *
   3107  * @param cls pointer to the test lookup closure.
   3108  * @param deposit_serial row number of the deposit in the database.
   3109  * @param exchange_url URL to the exchange
   3110  * @param h_wire hash of the wire transfer details.
   3111  * @param deposit_timestamp when was the deposit made
   3112  * @param amount_with_fee amount of the deposit with fees.
   3113  * @param deposit_fee fee charged for the deposit.
   3114  * @param coin_pub public key of the coin deposited.
   3115  */
   3116 static void
   3117 lookup_deposits_order_cb (void *cls,
   3118                           uint64_t deposit_serial,
   3119                           const char *exchange_url,
   3120                           const struct TALER_MerchantWireHashP *h_wire,
   3121                           struct GNUNET_TIME_Timestamp deposit_timestamp,
   3122                           const struct TALER_Amount *amount_with_fee,
   3123                           const struct TALER_Amount *deposit_fee,
   3124                           const struct TALER_CoinSpendPublicKeyP *coin_pub)
   3125 {
   3126   struct TestLookupDeposits_Closure *cmp = cls;
   3127 
   3128   if (NULL == cmp)
   3129     return;
   3130   cmp->results_length += 1;
   3131   for (unsigned int i = 0; i < cmp->deposits_to_cmp_length; ++i)
   3132   {
   3133     if ((0 == strcmp (cmp->deposits_to_cmp[i].exchange_url,
   3134                       exchange_url)) &&
   3135         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].h_wire,
   3136                              h_wire)) &&
   3137         (GNUNET_OK == TALER_amount_cmp_currency (
   3138            &cmp->deposits_to_cmp[i].amount_with_fee,
   3139            amount_with_fee)) &&
   3140         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
   3141                                 amount_with_fee)) &&
   3142         (GNUNET_OK == TALER_amount_cmp_currency (
   3143            &cmp->deposits_to_cmp[i].deposit_fee,
   3144            deposit_fee)) &&
   3145         (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
   3146                                 deposit_fee)) &&
   3147         (0 == GNUNET_memcmp (&cmp->deposits_to_cmp[i].coin_pub,
   3148                              coin_pub)))
   3149       cmp->results_matching[i] += 1;
   3150   }
   3151 }
   3152 
   3153 
   3154 /**
   3155  * Tests looking up deposits by associated order.
   3156  *
   3157  * @param order_serial row number of the order to lookup for.
   3158  * @param deposits_length length of @e deposits_length.
   3159  * @param deposits the deposits we expect to be found.
   3160  * @return 0 on success, 1 otherwise.
   3161  */
   3162 static int
   3163 test_lookup_deposits_by_order (uint64_t order_serial,
   3164                                unsigned int deposits_length,
   3165                                const struct DepositData *deposits)
   3166 {
   3167   unsigned int results_matching[deposits_length];
   3168   struct TestLookupDeposits_Closure cmp = {
   3169     .deposits_to_cmp_length = deposits_length,
   3170     .deposits_to_cmp = deposits,
   3171     .results_matching = results_matching,
   3172     .results_length = 0
   3173   };
   3174   memset (results_matching,
   3175           0,
   3176           sizeof (unsigned int) * deposits_length);
   3177   if (deposits_length !=
   3178       TALER_MERCHANTDB_lookup_deposits_by_order (pg,
   3179                                                  order_serial,
   3180                                                  &lookup_deposits_order_cb,
   3181                                                  &cmp))
   3182   {
   3183     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3184                 "Lookup deposits by order failed\n");
   3185     return 1;
   3186   }
   3187   if (deposits_length != cmp.results_length)
   3188   {
   3189     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3190                 "Lookup deposits by order failed: incorrect number of results\n");
   3191     return 1;
   3192   }
   3193   for (unsigned int i = 0; i < deposits_length; ++i)
   3194   {
   3195     if (1 != cmp.results_matching[i])
   3196     {
   3197       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3198                   "Lookup deposits by order failed: mismatched data\n");
   3199       return 1;
   3200     }
   3201   }
   3202   return 0;
   3203 }
   3204 
   3205 
   3206 /**
   3207  * Container for information for looking up the row number of a deposit.
   3208  */
   3209 struct LookupDepositSerial_Closure
   3210 {
   3211   /**
   3212    * The deposit we're looking for.
   3213    */
   3214   const struct DepositData *deposit;
   3215 
   3216   /**
   3217    * The serial found.
   3218    */
   3219   uint64_t serial;
   3220 };
   3221 
   3222 
   3223 /**
   3224  * Called after 'get_deposit_serial'.
   3225  *
   3226  * @param cls pointer to the test lookup closure.
   3227  * @param deposit_serial row number of the deposit in the database.
   3228  * @param exchange_url URL to the exchange
   3229  * @param h_wire hash of the wire transfer details.
   3230  * @param deposit_timestamp when was the deposit made.
   3231  * @param amount_with_fee amount of the deposit with fees.
   3232  * @param deposit_fee fee charged for the deposit.
   3233  * @param coin_pub public key of the coin deposited.
   3234  */
   3235 static void
   3236 get_deposit_serial_cb (void *cls,
   3237                        uint64_t deposit_serial,
   3238                        const char *exchange_url,
   3239                        const struct TALER_MerchantWireHashP *h_wire,
   3240                        struct GNUNET_TIME_Timestamp deposit_timestamp,
   3241                        const struct TALER_Amount *amount_with_fee,
   3242                        const struct TALER_Amount *deposit_fee,
   3243                        const struct TALER_CoinSpendPublicKeyP *coin_pub)
   3244 {
   3245   struct LookupDepositSerial_Closure *lookup_cls = cls;
   3246 
   3247   (void) deposit_timestamp;
   3248   if (NULL == lookup_cls)
   3249     return;
   3250   if ((0 == strcmp (lookup_cls->deposit->exchange_url,
   3251                     exchange_url)) &&
   3252       (0 == GNUNET_memcmp (&lookup_cls->deposit->h_wire,
   3253                            h_wire)) &&
   3254       (GNUNET_OK == TALER_amount_cmp_currency (
   3255          &lookup_cls->deposit->amount_with_fee,
   3256          amount_with_fee)) &&
   3257       (0 == TALER_amount_cmp (&lookup_cls->deposit->amount_with_fee,
   3258                               amount_with_fee)) &&
   3259       (GNUNET_OK == TALER_amount_cmp_currency (
   3260          &lookup_cls->deposit->deposit_fee,
   3261          deposit_fee)) &&
   3262       (0 == TALER_amount_cmp (&lookup_cls->deposit->deposit_fee,
   3263                               deposit_fee)) &&
   3264       (0 == GNUNET_memcmp (&lookup_cls->deposit->coin_pub,
   3265                            coin_pub)))
   3266     lookup_cls->serial = deposit_serial;
   3267 }
   3268 
   3269 
   3270 /**
   3271  * Convenience function to retrieve the row number of a deposit in the database.
   3272  *
   3273  * @param instance the instance to get deposits from.
   3274  * @param order the order associated with the deposit.
   3275  * @param deposit the deposit to lookup the serial for.
   3276  * @return the row number of the deposit.
   3277  */
   3278 static uint64_t
   3279 get_deposit_serial (const struct InstanceData *instance,
   3280                     const struct OrderData *order,
   3281                     const struct DepositData *deposit)
   3282 {
   3283   uint64_t order_serial = get_order_serial (instance,
   3284                                             order);
   3285   struct LookupDepositSerial_Closure lookup_cls = {
   3286     .deposit = deposit,
   3287     .serial = 0
   3288   };
   3289 
   3290   GNUNET_assert (0 <
   3291                  TALER_MERCHANTDB_lookup_deposits_by_order (pg,
   3292                                                             order_serial,
   3293                                                             &get_deposit_serial_cb,
   3294                                                             &lookup_cls));
   3295   GNUNET_assert (0 != lookup_cls.serial);
   3296 
   3297   return lookup_cls.serial;
   3298 }
   3299 
   3300 
   3301 /**
   3302  * Closure for deposit tests.
   3303  */
   3304 struct TestDeposits_Closure
   3305 {
   3306   /**
   3307    * The instance settings
   3308    */
   3309   struct InstanceData instance;
   3310 
   3311   /**
   3312    * The merchant account
   3313    */
   3314   struct TALER_MERCHANTDB_AccountDetails account;
   3315 
   3316   /**
   3317    * The exchange signing key
   3318    */
   3319   struct ExchangeSignkeyData signkey;
   3320 
   3321   /**
   3322    * The order data
   3323    */
   3324   struct OrderData orders[2];
   3325 
   3326   /**
   3327    * The array of deposits
   3328    */
   3329   struct DepositData deposits[3];
   3330 };
   3331 
   3332 
   3333 /**
   3334  * Initializes data for testing deposits.
   3335  *
   3336  * @param cls the test closure to initialize.
   3337  */
   3338 static void
   3339 pre_test_deposits (struct TestDeposits_Closure *cls)
   3340 {
   3341   /* Instance */
   3342   make_instance ("test_inst_deposits",
   3343                  &cls->instance);
   3344 
   3345   /* Account */
   3346   make_account (&cls->account);
   3347   cls->account.instance_id = cls->instance.instance.id;
   3348   /* Signing key */
   3349   make_exchange_signkey (&cls->signkey);
   3350 
   3351   /* Order */
   3352   make_order ("test_deposits_od_1",
   3353               &cls->orders[0]);
   3354   make_order ("test_deposits_od_2",
   3355               &cls->orders[1]);
   3356 
   3357   /* Deposit */
   3358   make_deposit (&cls->instance,
   3359                 &cls->account,
   3360                 &cls->orders[0],
   3361                 &cls->signkey,
   3362                 &cls->deposits[0]);
   3363   make_deposit (&cls->instance,
   3364                 &cls->account,
   3365                 &cls->orders[0],
   3366                 &cls->signkey,
   3367                 &cls->deposits[1]);
   3368   GNUNET_assert (GNUNET_OK ==
   3369                  TALER_string_to_amount ("EUR:29.00",
   3370                                          &cls->deposits[1].amount_with_fee));
   3371   make_deposit (&cls->instance,
   3372                 &cls->account,
   3373                 &cls->orders[1],
   3374                 &cls->signkey,
   3375                 &cls->deposits[2]);
   3376 }
   3377 
   3378 
   3379 /**
   3380  * Cleans up memory after testing deposits.
   3381  *
   3382  * @param cls the closure containing memory to free.
   3383  */
   3384 static void
   3385 post_test_deposits (struct TestDeposits_Closure *cls)
   3386 {
   3387   free_instance_data (&cls->instance);
   3388   json_decref (cls->orders[0].contract);
   3389   json_decref (cls->orders[1].contract);
   3390 }
   3391 
   3392 
   3393 /**
   3394  * Runs tests for deposits.
   3395  *
   3396  * @param cls the closure containing test data.
   3397  * @return 0 on success, 1 otherwise.
   3398  */
   3399 static int
   3400 run_test_deposits (struct TestDeposits_Closure *cls)
   3401 {
   3402   /* Insert the instance */
   3403   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   3404                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3405   /* Insert an account */
   3406   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   3407                                          &cls->account,
   3408                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3409   /* Insert a signing key */
   3410   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   3411                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3412   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   3413                                                   GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   3414   /* Insert an order */
   3415   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   3416                                        &cls->orders[0],
   3417                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3418   /* Insert contract terms */
   3419   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   3420                                                 &cls->orders[0],
   3421                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3422   /* Test inserting a deposit */
   3423   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3424                                          &cls->signkey,
   3425                                          &cls->deposits[0],
   3426                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3427   /* Test double inserts are idempotent */
   3428   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3429                                          &cls->signkey,
   3430                                          &cls->deposits[0],
   3431                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   3432   /* Test lookup deposits */
   3433   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3434                                           &cls->deposits[0].h_contract_terms,
   3435                                           1,
   3436                                           cls->deposits));
   3437   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3438                                           &cls->deposits[2].h_contract_terms,
   3439                                           0,
   3440                                           NULL));
   3441   /* Test lookup deposits by contract and coins */
   3442   TEST_RET_ON_FAIL (test_lookup_deposits_contract_and_coin (
   3443                       &cls->instance,
   3444                       &cls->deposits[0].h_contract_terms,
   3445                       &cls->deposits[0].coin_pub,
   3446                       1,
   3447                       cls->deposits));
   3448   /* Test multiple deposits */
   3449   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3450                                          &cls->signkey,
   3451                                          &cls->deposits[1],
   3452                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3453   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   3454                                        &cls->orders[1],
   3455                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3456   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   3457                                                 &cls->orders[1],
   3458                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3459   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   3460                                          &cls->signkey,
   3461                                          &cls->deposits[2],
   3462                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   3463   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3464                                           &cls->deposits[0].h_contract_terms,
   3465                                           2,
   3466                                           cls->deposits));
   3467   TEST_RET_ON_FAIL (test_lookup_deposits (&cls->instance,
   3468                                           &cls->deposits[2].h_contract_terms,
   3469                                           1,
   3470                                           &cls->deposits[2]));
   3471   /* Test lookup deposits by order */
   3472   {
   3473     uint64_t order_serial = get_order_serial (&cls->instance,
   3474                                               &cls->orders[0]);
   3475     TEST_RET_ON_FAIL (test_lookup_deposits_by_order (order_serial,
   3476                                                      2,
   3477                                                      cls->deposits));
   3478     order_serial = get_order_serial (&cls->instance,
   3479                                      &cls->orders[1]);
   3480     TEST_RET_ON_FAIL (test_lookup_deposits_by_order (order_serial,
   3481                                                      1,
   3482                                                      &cls->deposits[2]));
   3483   }
   3484   return 0;
   3485 }
   3486 
   3487 
   3488 /**
   3489  * Handles functionality for testing deposits.
   3490  *
   3491  * @return 0 on success, 1 otherwise.
   3492  */
   3493 static int
   3494 test_deposits (void)
   3495 {
   3496   struct TestDeposits_Closure test_cls;
   3497   int test_result;
   3498 
   3499   pre_test_deposits (&test_cls);
   3500   test_result = run_test_deposits (&test_cls);
   3501   post_test_deposits (&test_cls);
   3502   return test_result;
   3503 }
   3504 
   3505 
   3506 /* *********** Transfers ********** */
   3507 
   3508 
   3509 /**
   3510  * Container for wire fee data for an exchange.
   3511  */
   3512 struct WireFeeData
   3513 {
   3514   /**
   3515    * The method used.
   3516    */
   3517   const char *wire_method;
   3518 
   3519   /**
   3520    * Hash of the wire method.
   3521    */
   3522   struct GNUNET_HashCode h_wire_method;
   3523 
   3524   /**
   3525    * Wire fees charged.
   3526    */
   3527   struct TALER_WireFeeSet fees;
   3528 
   3529   /**
   3530    * Start date of the wire fee.
   3531    */
   3532   struct GNUNET_TIME_Timestamp wire_fee_start;
   3533 
   3534   /**
   3535    * End date of the wire fee.
   3536    */
   3537   struct GNUNET_TIME_Timestamp wire_fee_end;
   3538 
   3539   /**
   3540    * Signature on the wire fee.
   3541    */
   3542   struct TALER_MasterSignatureP fee_sig;
   3543 };
   3544 
   3545 
   3546 /**
   3547  * Creates data for an exchange wire fee.
   3548  *
   3549  * @param signkey the exchange signing key data.
   3550  * @param wire_fee where to store the wire fee data.
   3551  */
   3552 static void
   3553 make_wire_fee (const struct ExchangeSignkeyData *signkey,
   3554                struct WireFeeData *wire_fee)
   3555 {
   3556   wire_fee->wire_method = "wire-method";
   3557   GNUNET_CRYPTO_hash (wire_fee->wire_method,
   3558                       strlen (wire_fee->wire_method) + 1,
   3559                       &wire_fee->h_wire_method);
   3560   GNUNET_assert (GNUNET_OK ==
   3561                  TALER_string_to_amount ("EUR:0.49",
   3562                                          &wire_fee->fees.wire));
   3563   GNUNET_assert (GNUNET_OK ==
   3564                  TALER_string_to_amount ("EUR:0.49",
   3565                                          &wire_fee->fees.closing));
   3566   wire_fee->wire_fee_start = GNUNET_TIME_timestamp_get ();
   3567   wire_fee->wire_fee_end = GNUNET_TIME_relative_to_timestamp (
   3568     GNUNET_TIME_UNIT_MONTHS);
   3569   TALER_exchange_offline_wire_fee_sign (
   3570     wire_fee->wire_method,
   3571     wire_fee->wire_fee_start,
   3572     wire_fee->wire_fee_end,
   3573     &wire_fee->fees,
   3574     &signkey->master_priv,
   3575     &wire_fee->fee_sig);
   3576 }
   3577 
   3578 
   3579 /**
   3580  * Container for wire transfer data.
   3581  */
   3582 struct TransferData
   3583 {
   3584   /**
   3585    * Id of the transfer.
   3586    */
   3587   struct TALER_WireTransferIdentifierRawP wtid;
   3588 
   3589   /**
   3590    * The main data for the transfer.
   3591    */
   3592   struct TALER_EXCHANGE_TransferData data;
   3593 
   3594   /**
   3595    * URL to the exchange the transfer was made through.
   3596    */
   3597   const char *exchange_url;
   3598 
   3599   /**
   3600    * How much the fee for the deposit was.
   3601    */
   3602   struct TALER_Amount deposit_fee;
   3603 
   3604   /**
   3605    * Whether the transfer has been confirmed.
   3606    */
   3607   bool confirmed;
   3608 
   3609   /**
   3610    * Whether the transfer has been verified.
   3611    */
   3612   bool verified;
   3613 };
   3614 
   3615 
   3616 /**
   3617  * Creates a transfer for use with testing.
   3618  *
   3619  * @param deposits_length length of @e deposits.
   3620  * @param deposits list of deposits to combine into one transfer.
   3621  * @param transfer where to write the transfer data.
   3622  */
   3623 static void
   3624 make_transfer (const struct ExchangeSignkeyData *signkey,
   3625                unsigned int deposits_length,
   3626                const struct DepositData deposits[static deposits_length],
   3627                struct TransferData *transfer)
   3628 {
   3629   struct TALER_TrackTransferDetails *details = NULL;
   3630 
   3631   GNUNET_CRYPTO_seed_weak_random (585);
   3632   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
   3633                               &transfer->wtid,
   3634                               sizeof (struct TALER_WireTransferIdentifierRawP));
   3635   transfer->exchange_url = deposits[0].exchange_url;
   3636   transfer->verified = false;
   3637   transfer->confirmed = false;
   3638   transfer->data.details_length = 0;
   3639   GNUNET_assert (GNUNET_OK ==
   3640                  TALER_amount_set_zero (deposits[0].amount_with_fee.currency,
   3641                                         &transfer->data.total_amount));
   3642   GNUNET_assert (GNUNET_OK ==
   3643                  TALER_amount_set_zero (deposits[0].amount_with_fee.currency,
   3644                                         &transfer->deposit_fee));
   3645   for (unsigned int i = 0; i < deposits_length; ++i)
   3646   {
   3647     GNUNET_array_grow (details,
   3648                        transfer->data.details_length,
   3649                        i + 1);
   3650     details[i].h_contract_terms = deposits[i].h_contract_terms;
   3651     details[i].coin_pub = deposits[i].coin_pub;
   3652     details[i].coin_value = deposits[i].amount_with_fee;
   3653     details[i].coin_fee = deposits[i].deposit_fee;
   3654     GNUNET_assert (0 <=
   3655                    TALER_amount_add (&transfer->data.total_amount,
   3656                                      &transfer->data.total_amount,
   3657                                      &deposits[i].amount_with_fee));
   3658     GNUNET_assert (0 <=
   3659                    TALER_amount_add (&transfer->deposit_fee,
   3660                                      &transfer->deposit_fee,
   3661                                      &deposits[i].deposit_fee));
   3662   }
   3663   transfer->data.exchange_pub = signkey->exchange_pub;
   3664   transfer->data.execution_time = GNUNET_TIME_timestamp_get ();
   3665   transfer->data.details = details;
   3666   GNUNET_assert (GNUNET_OK ==
   3667                  TALER_string_to_amount ("EUR:0.50",
   3668                                          &transfer->data.wire_fee));
   3669 }
   3670 
   3671 
   3672 /**
   3673  * Closure for testing 'lookup_transfer_summary'
   3674  */
   3675 struct TestLookupTransferSummary_Closure
   3676 {
   3677   /**
   3678    * Id of the order the transfer was made for.
   3679    */
   3680   const char *order_id;
   3681 
   3682   /**
   3683    * The value of the deposit made.
   3684    */
   3685   const struct TALER_Amount *deposit_value;
   3686 
   3687   /**
   3688    * The fee on the deposit made.
   3689    */
   3690   const struct TALER_Amount *deposit_fee;
   3691 
   3692   /**
   3693    * 0 if the comparison is true, 1 if false.
   3694    */
   3695   int result;
   3696 };
   3697 
   3698 
   3699 /**
   3700  * Called after 'test_lookup_transfer_summary'.
   3701  *
   3702  * @param cls pointer to 'TestLookupTransferSummary_Closure'.
   3703  * @param order_id id of the order the transfer was made for.
   3704  * @param deposit_value the value of the deposit made.
   3705  * @param deposit_fee the fee on the deposit made.
   3706  */
   3707 static void
   3708 lookup_transfer_summary_cb (void *cls,
   3709                             const char *order_id,
   3710                             const struct TALER_Amount *deposit_value,
   3711                             const struct TALER_Amount *deposit_fee)
   3712 {
   3713   struct TestLookupTransferSummary_Closure *cmp = cls;
   3714   if (NULL == cmp)
   3715     return;
   3716   if ((0 == strcmp (cmp->order_id,
   3717                     order_id)) &&
   3718       (GNUNET_OK == TALER_amount_cmp_currency (cmp->deposit_value,
   3719                                                deposit_value)) &&
   3720       (0 == TALER_amount_cmp (cmp->deposit_value,
   3721                               deposit_value)) &&
   3722       (GNUNET_OK == TALER_amount_cmp_currency (cmp->deposit_fee,
   3723                                                deposit_fee)) &&
   3724       (0 == TALER_amount_cmp (cmp->deposit_fee,
   3725                               deposit_fee)))
   3726     cmp->result = 0;
   3727   else
   3728     cmp->result = 1;
   3729 }
   3730 
   3731 
   3732 /**
   3733  * Tests looking up a transfer's summary.
   3734  *
   3735  * @param exchange_url url to the exchange for the transfer.
   3736  * @param wtid identifier of the transfer.
   3737  * @param expected_order_id the id of the order associated with the transfer.
   3738  * @param expected_deposit_value the amount of the deposit made for the transfer.
   3739  * @param expected_deposit_fee the fee on the deposit made for the transfer.
   3740  * @return 1 on success, 0 otherwise.
   3741  */
   3742 static int
   3743 test_lookup_transfer_summary (
   3744   const char *exchange_url,
   3745   const struct TALER_WireTransferIdentifierRawP *wtid,
   3746   const char *expected_order_id,
   3747   const struct TALER_Amount *expected_deposit_value,
   3748   const struct TALER_Amount *expected_deposit_fee)
   3749 {
   3750   struct TestLookupTransferSummary_Closure cmp = {
   3751     .order_id = expected_order_id,
   3752     .deposit_value = expected_deposit_value,
   3753     .deposit_fee = expected_deposit_fee,
   3754     .result = 0
   3755   };
   3756   if (1 != TALER_MERCHANTDB_lookup_transfer_summary (pg,
   3757                                                      exchange_url,
   3758                                                      wtid,
   3759                                                      &lookup_transfer_summary_cb,
   3760                                                      &cmp))
   3761   {
   3762     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3763                 "Lookup transfer summary failed\n");
   3764     return 1;
   3765   }
   3766   if (0 != cmp.result)
   3767   {
   3768     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3769                 "Lookup transfer summary failed: mismatched data\n");
   3770     return 1;
   3771   }
   3772   return 0;
   3773 }
   3774 
   3775 
   3776 /**
   3777  * Closure for testing 'lookup_transfer_details'.
   3778  */
   3779 struct TestLookupTransferDetails_Closure
   3780 {
   3781   /**
   3782    * Length of @e details_to_cmp.
   3783    */
   3784   unsigned int details_to_cmp_length;
   3785 
   3786   /**
   3787    * The details we expect to find.
   3788    */
   3789   const struct TALER_TrackTransferDetails *details_to_cmp;
   3790 
   3791   /**
   3792    * Number of results matching each detail in @e details_to_cmp.
   3793    */
   3794   unsigned int *results_matching;
   3795 
   3796   /**
   3797    * Total number of results found.
   3798    */
   3799   unsigned int results_length;
   3800 };
   3801 
   3802 
   3803 /**
   3804  * Called after 'test_lookup_transfer_details'.
   3805  *
   3806  * @param cls pointer to 'TestLookupTransferDetails_Closure'.
   3807  * @param current_offset offset within transfer details.
   3808  * @param details the details that were found.
   3809  */
   3810 static void
   3811 lookup_transfer_details_cb (void *cls,
   3812                             unsigned int current_offset,
   3813                             const struct TALER_TrackTransferDetails *details)
   3814 {
   3815   struct TestLookupTransferDetails_Closure *cmp = cls;
   3816   if (NULL == cmp)
   3817     return;
   3818   for (unsigned int i = 0; cmp->details_to_cmp_length > i; ++i)
   3819   {
   3820     if ((0 == GNUNET_memcmp (&cmp->details_to_cmp[i].h_contract_terms,
   3821                              &details->h_contract_terms)) &&
   3822         (0 == GNUNET_memcmp (&cmp->details_to_cmp[i].coin_pub,
   3823                              &details->coin_pub)) &&
   3824         (GNUNET_OK == TALER_amount_cmp_currency (
   3825            &cmp->details_to_cmp[i].coin_value,
   3826            &details->coin_value)) &&
   3827         (0 == TALER_amount_cmp (&cmp->details_to_cmp[i].coin_value,
   3828                                 &details->coin_value)) &&
   3829         (GNUNET_OK == TALER_amount_cmp_currency (
   3830            &cmp->details_to_cmp[i].coin_fee,
   3831            &details->coin_fee)) &&
   3832         (0 == TALER_amount_cmp (&cmp->details_to_cmp[i].coin_fee,
   3833                                 &details->coin_fee)))
   3834     {
   3835       cmp->results_matching[i] += 1;
   3836     }
   3837   }
   3838   cmp->results_length += 1;
   3839 }
   3840 
   3841 
   3842 /**
   3843  * Tests looking up details for a wire transfer.
   3844  *
   3845  * @param exchange_url url to the exchange.
   3846  * @param wtid id of the transfer.
   3847  * @param details_length the length of @e details.
   3848  * @param details the details we expect to be returned.
   3849  * @return 1 on success, 0 otherwise.
   3850  */
   3851 static int
   3852 test_lookup_transfer_details (
   3853   const char *exchange_url,
   3854   const struct TALER_WireTransferIdentifierRawP *wtid,
   3855   unsigned int details_length,
   3856   const struct TALER_TrackTransferDetails *details)
   3857 {
   3858   unsigned int results_matching[details_length];
   3859   struct TestLookupTransferDetails_Closure cmp = {
   3860     .details_to_cmp_length = details_length,
   3861     .details_to_cmp = details,
   3862     .results_matching = results_matching,
   3863     .results_length = 0
   3864   };
   3865   memset (results_matching,
   3866           0,
   3867           sizeof (unsigned int) * details_length);
   3868   if (1 != TALER_MERCHANTDB_lookup_transfer_details (pg,
   3869                                                      exchange_url,
   3870                                                      wtid,
   3871                                                      &lookup_transfer_details_cb,
   3872                                                      &cmp))
   3873   {
   3874     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3875                 "Lookup transfer details failed\n");
   3876     return 1;
   3877   }
   3878   if (details_length != cmp.results_length)
   3879   {
   3880     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3881                 "Lookup transfer details failed: incorrect number of results (%d)\n",
   3882                 cmp.results_length);
   3883     return 1;
   3884   }
   3885   for (unsigned int i = 0; details_length > i; ++i)
   3886   {
   3887     if (1 != cmp.results_matching[i])
   3888     {
   3889       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   3890                   "Lookup transfer details failed: mismatched data\n");
   3891       return 1;
   3892     }
   3893   }
   3894   return 0;
   3895 }
   3896 
   3897 
   3898 /**
   3899  * Closure for 'lookup_transfer_details_by_order'.
   3900  */
   3901 struct TestLookupTransferDetailsByOrder_Closure
   3902 {
   3903   /**
   3904    * Length of @e transfers_to_cmp.
   3905    */
   3906   unsigned int transfers_to_cmp_length;
   3907 
   3908   /**
   3909    * List of transfers that we expect to find.
   3910    */
   3911   const struct TransferData *transfers_to_cmp;
   3912 
   3913   /**
   3914    * How many results match the corresponding element of @e transfers_to_cmp.
   3915    */
   3916   unsigned int *results_matching;
   3917 
   3918   /**
   3919    * Total number of results found.
   3920    */
   3921   unsigned int results_length;
   3922 };
   3923 
   3924 
   3925 /**
   3926  * Called after 'test_lookup_transfer_details_by_order'.
   3927  *
   3928  * @param cls pointer to 'TestLookupTransferDetailsByOrder_Closure'.
   3929  * @param wtid identifier of the transfer found.
   3930  * @param exchange_url exchange url of the transfer found.
   3931  * @param execution_time when the transfer found occurred.
   3932  * @param deposit_value amount of the deposit for the transfer found.
   3933  * @param deposit_fee amount of the fee for the deposit of the transfer.
   3934  * @param transfer_confirmed did the merchant confirm that a wire transfer with
   3935  *        @a wtid over the total amount happened?
   3936  */
   3937 static void
   3938 lookup_transfer_details_order_cb (
   3939   void *cls,
   3940   const struct TALER_WireTransferIdentifierRawP *wtid,
   3941   const char *exchange_url,
   3942   struct GNUNET_TIME_Timestamp execution_time,
   3943   const struct TALER_Amount *deposit_value,
   3944   const struct TALER_Amount *deposit_fee,
   3945   bool transfer_confirmed,
   3946   uint64_t expected_transfer_serial_id)
   3947 {
   3948   struct TestLookupTransferDetailsByOrder_Closure *cmp = cls;
   3949 
   3950   if (NULL == cmp)
   3951     return;
   3952   cmp->results_length += 1;
   3953   for (unsigned int i = 0; i < cmp->transfers_to_cmp_length; ++i)
   3954   {
   3955     /* Right now lookup_transfer_details_by_order leaves execution_time
   3956        uninitialized */
   3957     if ((0 == GNUNET_memcmp (&cmp->transfers_to_cmp[i].wtid,
   3958                              wtid)) &&
   3959         (0 == strcmp (cmp->transfers_to_cmp[i].exchange_url,
   3960                       exchange_url)) &&
   3961         (GNUNET_OK ==
   3962          TALER_amount_cmp_currency (
   3963            &cmp->transfers_to_cmp[i].data.total_amount,
   3964            deposit_value)) &&
   3965         (0 ==
   3966          TALER_amount_cmp (&cmp->transfers_to_cmp[i].data.total_amount,
   3967                            deposit_value)) &&
   3968         (GNUNET_OK ==
   3969          TALER_amount_cmp_currency (
   3970            &cmp->transfers_to_cmp[i].deposit_fee,
   3971            deposit_fee)) &&
   3972         (0 ==
   3973          TALER_amount_cmp (&cmp->transfers_to_cmp[i].deposit_fee,
   3974                            deposit_fee)) )
   3975       cmp->results_matching[i] += 1;
   3976   }
   3977 }
   3978 
   3979 
   3980 /**
   3981  * Tests looking up wire transfers associated with an order.
   3982  *
   3983  * @param order_serial the order to be queried.
   3984  * @param transfers_length length of @e transfers.
   3985  * @param transfers the transfers we expect to be found.
   3986  * @return 0 on success, 1 otherwise.
   3987  */
   3988 static int
   3989 test_lookup_transfer_details_by_order (
   3990   uint64_t order_serial,
   3991   unsigned int transfers_length,
   3992   const struct TransferData *transfers)
   3993 {
   3994   unsigned int results_matching[transfers_length];
   3995   struct TestLookupTransferDetailsByOrder_Closure cmp = {
   3996     .transfers_to_cmp_length = transfers_length,
   3997     .transfers_to_cmp = transfers,
   3998     .results_matching = results_matching,
   3999     .results_length = 0
   4000   };
   4001   memset (results_matching,
   4002           0,
   4003           sizeof (unsigned int) * transfers_length);
   4004   if (transfers_length !=
   4005       TALER_MERCHANTDB_lookup_transfer_details_by_order (
   4006         pg,
   4007         order_serial,
   4008         &lookup_transfer_details_order_cb,
   4009         &cmp))
   4010   {
   4011     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4012                 "Lookup transfer details by order failed\n");
   4013     return 1;
   4014   }
   4015   if (transfers_length != cmp.results_length)
   4016   {
   4017     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4018                 "Lookup transfer details by order failed: incorrect number of results\n");
   4019     return 1;
   4020   }
   4021   for (unsigned int i = 0; i < transfers_length; ++i)
   4022   {
   4023     if (1 != cmp.results_matching[i])
   4024     {
   4025       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4026                   "Lookup transfer details by order failed: mismatched data\n");
   4027       return 1;
   4028     }
   4029   }
   4030   return 0;
   4031 }
   4032 
   4033 
   4034 /**
   4035  * Tests inserting wire fee data for an exchange.
   4036  *
   4037  * @param signkey the signing key for the exchange.
   4038  * @param wire_fee the wire fee data.
   4039  * @param expected_result what the database should return.
   4040  * @return 0 on success, 1 otherwise.
   4041  */
   4042 static int
   4043 test_insert_wire_fee (const struct ExchangeSignkeyData *signkey,
   4044                       const struct WireFeeData *wire_fee,
   4045                       enum GNUNET_DB_QueryStatus expected_result)
   4046 {
   4047   TEST_COND_RET_ON_FAIL (expected_result ==
   4048                          TALER_MERCHANTDB_store_wire_fee_by_exchange (
   4049                            pg,
   4050                            &signkey->master_pub,
   4051                            &wire_fee->h_wire_method,
   4052                            &wire_fee->fees,
   4053                            wire_fee->wire_fee_start,
   4054                            wire_fee->wire_fee_end,
   4055                            &wire_fee->fee_sig),
   4056                          "Store wire fee by exchange failed\n");
   4057   return 0;
   4058 }
   4059 
   4060 
   4061 /**
   4062  * Tests looking up wire fee data for an exchange.
   4063  *
   4064  * @param signkey the signing key to use for lookup.
   4065  * @param wire_fee_data the wire fee data we expect to find.
   4066  * @return 0 on success, 1 otherwise.
   4067  */
   4068 static int
   4069 test_lookup_wire_fee (const struct ExchangeSignkeyData *signkey,
   4070                       const struct WireFeeData *wire_fee_data)
   4071 {
   4072   struct TALER_WireFeeSet fees;
   4073   struct GNUNET_TIME_Timestamp start_date;
   4074   struct GNUNET_TIME_Timestamp end_date;
   4075   struct TALER_MasterSignatureP master_sig;
   4076   if (1 != TALER_MERCHANTDB_lookup_wire_fee (pg,
   4077                                              &signkey->master_pub,
   4078                                              wire_fee_data->wire_method,
   4079                                              GNUNET_TIME_timestamp_get (),
   4080                                              &fees,
   4081                                              &start_date,
   4082                                              &end_date,
   4083                                              &master_sig))
   4084   {
   4085     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4086                 "Lookup wire fee failed\n");
   4087     return 1;
   4088   }
   4089   if ((0 !=
   4090        TALER_wire_fee_set_cmp (&wire_fee_data->fees,
   4091                                &fees)) ||
   4092       (GNUNET_TIME_timestamp_cmp (wire_fee_data->wire_fee_start,
   4093                                   !=,
   4094                                   start_date)) ||
   4095       (GNUNET_TIME_timestamp_cmp (wire_fee_data->wire_fee_end,
   4096                                   !=,
   4097                                   end_date)) ||
   4098       (0 != GNUNET_memcmp (&wire_fee_data->fee_sig,
   4099                            &master_sig)))
   4100   {
   4101     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4102                 "Lookup wire fee failed: mismatched data\n");
   4103     return 1;
   4104   }
   4105   return 0;
   4106 }
   4107 
   4108 
   4109 /**
   4110  * Closure for 'lookup_transfers'.
   4111  */
   4112 struct TestLookupTransfers_Closure
   4113 {
   4114   /**
   4115    * Length of @e transfers_to_cmp.
   4116    */
   4117   unsigned int transfers_to_cmp_length;
   4118 
   4119   /**
   4120    * The transfers we expect to find.
   4121    */
   4122   const struct TransferData *transfers_to_cmp;
   4123 
   4124   /**
   4125    * Number of results matching each transfer.
   4126    */
   4127   unsigned int *results_matching;
   4128 
   4129   /**
   4130    * Total number of results found.
   4131    */
   4132   unsigned int results_length;
   4133 };
   4134 
   4135 
   4136 /**
   4137  * Function called after 'test_lookup_transfers'.
   4138  *
   4139  * @param cls pointer to 'TestLookupTransfers_Closure'.
   4140  * @param credit_amount how much was wired to the merchant (minus fees)
   4141  * @param wtid wire transfer identifier
   4142  * @param payto_uri target account that received the wire transfer
   4143  * @param exchange_url base URL of the exchange that made the wire transfer
   4144  * @param transfer_serial_id serial number identifying the transfer in the backend
   4145  * @param expected_transfer_serial_id serial number identifying the expected transfer in the backend, 0 if not @a expected
   4146  * @param execution_time when did the exchange make the transfer, #GNUNET_TIME_UNIT_FOREVER_TS
   4147  *           if it did not yet happen
   4148  * @param expected true if the merchant acknowledged the wire transfer reception
   4149  */
   4150 static void
   4151 lookup_transfers_cb (void *cls,
   4152                      const struct TALER_Amount *credit_amount,
   4153                      const struct TALER_WireTransferIdentifierRawP *wtid,
   4154                      struct TALER_FullPayto payto_uri,
   4155                      const char *exchange_url,
   4156                      uint64_t transfer_serial_id,
   4157                      uint64_t expected_transfer_serial_id,
   4158                      struct GNUNET_TIME_Absolute execution_time,
   4159                      bool expected)
   4160 {
   4161   struct TestLookupTransfers_Closure *cmp = cls;
   4162   if (NULL == cmp)
   4163     return;
   4164   for (unsigned int i = 0; cmp->transfers_to_cmp_length > i; ++i)
   4165   {
   4166     if ( (GNUNET_OK ==
   4167           TALER_amount_cmp_currency (
   4168             &cmp->transfers_to_cmp[i].data.total_amount,
   4169             credit_amount)) &&
   4170          (0 == TALER_amount_cmp (&cmp->transfers_to_cmp[i].data.total_amount,
   4171                                  credit_amount)) )
   4172     {
   4173       cmp->results_matching[i]++;
   4174     }
   4175   }
   4176   cmp->results_length++;
   4177 }
   4178 
   4179 
   4180 /**
   4181  * Tests looking up transfers from the database.
   4182  *
   4183  * @param instance the instance to lookup from.
   4184  * @param account the account the transfer was made to.
   4185  * @param before do not return transfers before this time.
   4186  * @param after do not return transfers after this time.
   4187  * @param limit maximum number of transfers to return.
   4188  * @param offset row in the database to start with.
   4189  * @param filter_verified how to filter verified transfers.
   4190  * @param transfers_length length of @e transfers.
   4191  * @param transfers the transfers we expect to find.
   4192  * @return 0 on success, 1 otherwise.
   4193  */
   4194 static int
   4195 test_lookup_transfers (const struct InstanceData *instance,
   4196                        const struct TALER_MERCHANTDB_AccountDetails *account,
   4197                        struct GNUNET_TIME_Timestamp before,
   4198                        struct GNUNET_TIME_Timestamp after,
   4199                        int64_t limit,
   4200                        uint64_t offset,
   4201                        unsigned int transfers_length,
   4202                        const struct TransferData *transfers)
   4203 {
   4204   unsigned int results_matching[transfers_length];
   4205   struct TestLookupTransfers_Closure cmp = {
   4206     .transfers_to_cmp_length = transfers_length,
   4207     .transfers_to_cmp = transfers,
   4208     .results_matching = results_matching,
   4209     .results_length = 0
   4210   };
   4211   memset (results_matching,
   4212           0,
   4213           sizeof (unsigned int) * transfers_length);
   4214   if (1 != TALER_MERCHANTDB_lookup_transfers (pg,
   4215                                               instance->instance.id,
   4216                                               account->payto_uri,
   4217                                               before,
   4218                                               after,
   4219                                               limit,
   4220                                               offset,
   4221                                               TALER_EXCHANGE_YNA_ALL,
   4222                                               &lookup_transfers_cb,
   4223                                               &cmp))
   4224   {
   4225     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4226                 "Lookup transfers failed\n");
   4227     return 1;
   4228   }
   4229   if (transfers_length != cmp.results_length)
   4230   {
   4231     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4232                 "Lookup transfers failed: incorrect number of results\n");
   4233     return 1;
   4234   }
   4235   for (unsigned int i = 0; transfers_length > i; ++i)
   4236   {
   4237     if (1 != cmp.results_matching[i])
   4238     {
   4239       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4240                   "Lookup transfers failed: mismatched data\n");
   4241       return 1;
   4242     }
   4243   }
   4244   return 0;
   4245 }
   4246 
   4247 
   4248 /**
   4249  * Tests inserting a transfer into the database.
   4250  *
   4251  * @param instance the instance to use.
   4252  * @param account the account to transfer to.
   4253  * @param transfer the transfer to insert.
   4254  * @param expected_result the result we expect the db to return.
   4255  * @return 0 on success, 1 otherwise.
   4256  */
   4257 static int
   4258 test_insert_transfer (const struct InstanceData *instance,
   4259                       const struct TALER_MERCHANTDB_AccountDetails *account,
   4260                       const struct TransferData *transfer,
   4261                       enum GNUNET_DB_QueryStatus expected_result)
   4262 {
   4263   bool no_instance;
   4264   bool no_account;
   4265   bool conflict;
   4266 
   4267   TEST_COND_RET_ON_FAIL (expected_result ==
   4268                          TALER_MERCHANTDB_insert_transfer (pg,
   4269                                                            instance->instance.id,
   4270                                                            transfer->exchange_url,
   4271                                                            &transfer->wtid,
   4272                                                            &transfer->data.total_amount,
   4273                                                            account->payto_uri,
   4274                                                            transfer->confirmed,
   4275                                                            &no_instance,
   4276                                                            &no_account,
   4277                                                            &conflict),
   4278                          "Insert transfer failed\n");
   4279   return 0;
   4280 }
   4281 
   4282 
   4283 /**
   4284  * Tests linking a deposit to a transfer.
   4285  *
   4286  * @param instance the instance that the deposit and transfer are for.
   4287  * @param signkey the signing used on the deposit.
   4288  * @param order the order the deposit and transfer were made for.
   4289  * @param transfer the transfer.
   4290  * @param expected_result the result the database should return.
   4291  * @param expected_cleared clearance status the database should return.
   4292  * @return 0 on success, 1 otherwise.
   4293  */
   4294 static int
   4295 test_insert_deposit_to_transfer (const struct InstanceData *instance,
   4296                                  const struct ExchangeSignkeyData *signkey,
   4297                                  const struct OrderData *order,
   4298                                  const struct DepositData *deposit,
   4299                                  const struct TransferData *transfer,
   4300                                  enum GNUNET_DB_QueryStatus expected_result,
   4301                                  bool expect_cleared)
   4302 {
   4303   const struct TALER_EXCHANGE_DepositData deposit_data = {
   4304     .exchange_pub = signkey->exchange_pub,
   4305     .exchange_sig = deposit->exchange_sig,
   4306     .wtid = transfer->wtid,
   4307     .execution_time = transfer->data.execution_time,
   4308     .coin_contribution = deposit->amount_with_fee
   4309   };
   4310   uint64_t deposit_serial = get_deposit_serial (instance,
   4311                                                 order,
   4312                                                 deposit);
   4313 
   4314   TEST_COND_RET_ON_FAIL (expected_result ==
   4315                          TALER_MERCHANTDB_insert_deposit_to_transfer (
   4316                            pg,
   4317                            deposit_serial,
   4318                            &deposit->h_wire,
   4319                            deposit->exchange_url,
   4320                            &deposit_data),
   4321                          "insert deposit to transfer failed\n");
   4322   return 0;
   4323 }
   4324 
   4325 
   4326 /**
   4327  * Inserts details for a transfer into the database.
   4328  *
   4329  * @param instance the instance the transfer is in.
   4330  * @param account the destination account for the transfer.
   4331  * @param transfer the transfer we are adding details to.
   4332  * @param expected_result the result expected from the db.
   4333  * @return 0 on success, 1 otherwise.
   4334  */
   4335 static int
   4336 test_insert_transfer_details (
   4337   const struct InstanceData *instance,
   4338   const struct TALER_MERCHANTDB_AccountDetails *account,
   4339   const struct TransferData *transfer,
   4340   enum GNUNET_DB_QueryStatus expected_result)
   4341 {
   4342   TEST_COND_RET_ON_FAIL (expected_result ==
   4343                          TALER_MERCHANTDB_insert_transfer_details (
   4344                            pg,
   4345                            instance->instance.id,
   4346                            transfer->exchange_url,
   4347                            account->payto_uri,
   4348                            &transfer->wtid,
   4349                            &transfer->data),
   4350                          "Insert transfer details failed\n");
   4351   return 0;
   4352 }
   4353 
   4354 
   4355 /**
   4356  * Container for data used when testing transfers.
   4357  */
   4358 struct TestTransfers_Closure
   4359 {
   4360   /**
   4361    * The instance.
   4362    */
   4363   struct InstanceData instance;
   4364 
   4365   /**
   4366    * The account.
   4367    */
   4368   struct TALER_MERCHANTDB_AccountDetails account;
   4369 
   4370   /**
   4371    * The exchange signing key.
   4372    */
   4373   struct ExchangeSignkeyData signkey;
   4374 
   4375   /**
   4376    * The order data.
   4377    */
   4378   struct OrderData order;
   4379 
   4380   /**
   4381    * The deposit data.
   4382    */
   4383   struct DepositData deposit;
   4384 
   4385   /**
   4386    * Wire fee data.
   4387    */
   4388   struct WireFeeData wire_fee[2];
   4389 
   4390   /**
   4391    * The transfers.
   4392    */
   4393   struct TransferData transfers[1];
   4394 };
   4395 
   4396 
   4397 /**
   4398  * Prepares for testing transfers.
   4399  *
   4400  * @param cls the test data.
   4401  */
   4402 static void
   4403 pre_test_transfers (struct TestTransfers_Closure *cls)
   4404 {
   4405   /* Instance */
   4406   make_instance ("test_inst_transfers",
   4407                  &cls->instance);
   4408 
   4409   /* Account */
   4410   make_account (&cls->account);
   4411   cls->account.instance_id = cls->instance.instance.id;
   4412   /* Order */
   4413   make_order ("test_transfers_od_1",
   4414               &cls->order);
   4415 
   4416   /* Signing key */
   4417   make_exchange_signkey (&cls->signkey);
   4418 
   4419   /* Deposit */
   4420   make_deposit (&cls->instance,
   4421                 &cls->account,
   4422                 &cls->order,
   4423                 &cls->signkey,
   4424                 &cls->deposit);
   4425 
   4426   /* Wire fee */
   4427   make_wire_fee (&cls->signkey,
   4428                  &cls->wire_fee[0]);
   4429   make_wire_fee (&cls->signkey,
   4430                  &cls->wire_fee[1]);
   4431   cls->wire_fee[1].wire_method = "wire-method-2";
   4432   GNUNET_CRYPTO_hash (cls->wire_fee[1].wire_method,
   4433                       strlen (cls->wire_fee[1].wire_method) + 1,
   4434                       &cls->wire_fee[1].h_wire_method);
   4435 
   4436   /* Transfers */
   4437   make_transfer (&cls->signkey,
   4438                  1,
   4439                  &cls->deposit,
   4440                  &cls->transfers[0]);
   4441   cls->transfers[0].confirmed = true;
   4442 }
   4443 
   4444 
   4445 /**
   4446  * Cleans up after testing transfers.
   4447  *
   4448  * @param cls the test data.
   4449  */
   4450 static void
   4451 post_test_transfers (struct TestTransfers_Closure *cls)
   4452 {
   4453   GNUNET_array_grow (cls->transfers->data.details,
   4454                      cls->transfers->data.details_length,
   4455                      0);
   4456   free_instance_data (&cls->instance);
   4457   free_order_data (&cls->order);
   4458 }
   4459 
   4460 
   4461 /**
   4462  * Runs the tests for transfers.
   4463  *
   4464  * @param cls the test data.
   4465  * @return 0 on success, 1 otherwise.
   4466  */
   4467 static int
   4468 run_test_transfers (struct TestTransfers_Closure *cls)
   4469 {
   4470   uint64_t order_serial;
   4471   struct TALER_WireFeeSet fees;
   4472 
   4473   /* Test lookup wire fee fails when it isn't in the db */
   4474   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS ==
   4475                          TALER_MERCHANTDB_lookup_wire_fee (pg,
   4476                                                            &cls->signkey.master_pub,
   4477                                                            cls->wire_fee[0].wire_method,
   4478                                                            GNUNET_TIME_timestamp_get (),
   4479                                                            &fees,
   4480                                                            NULL,
   4481                                                            NULL,
   4482                                                            NULL),
   4483                          "Lookup wire fee failed\n");
   4484   /* Test store wire fee by exchange */
   4485   TEST_RET_ON_FAIL (test_insert_wire_fee (&cls->signkey,
   4486                                           &cls->wire_fee[0],
   4487                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4488   /* Test double insertion fails */
   4489   TEST_RET_ON_FAIL (test_insert_wire_fee (&cls->signkey,
   4490                                           &cls->wire_fee[0],
   4491                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   4492   /* Test lookup wire fee by exchange */
   4493   TEST_RET_ON_FAIL (test_lookup_wire_fee (&cls->signkey,
   4494                                           &cls->wire_fee[0]));
   4495   /* Test different wire fees for different methods. */
   4496   TEST_RET_ON_FAIL (test_insert_wire_fee (&cls->signkey,
   4497                                           &cls->wire_fee[1],
   4498                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4499   TEST_RET_ON_FAIL (test_lookup_wire_fee (&cls->signkey,
   4500                                           &cls->wire_fee[1]));
   4501   /* Insert the instance */
   4502   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   4503                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4504   /* Insert the account */
   4505   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   4506                                          &cls->account,
   4507                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4508   /* Insert a signing key */
   4509   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   4510                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4511   /* Insert an order */
   4512   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   4513                                        &cls->order,
   4514                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4515   /* Insert contract terms */
   4516   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   4517                                                 &cls->order,
   4518                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4519   order_serial = get_order_serial (&cls->instance,
   4520                                    &cls->order);
   4521   /* Insert the deposit */
   4522   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   4523                                          &cls->signkey,
   4524                                          &cls->deposit,
   4525                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4526   /* Mark as paid, otherwise wiring doesn't make sense. */
   4527   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   4528                                              &cls->order,
   4529                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4530   /* Insert the transfer */
   4531   TEST_RET_ON_FAIL (test_insert_transfer (&cls->instance,
   4532                                           &cls->account,
   4533                                           &cls->transfers[0],
   4534                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4535   TEST_RET_ON_FAIL (test_insert_transfer (&cls->instance,
   4536                                           &cls->account,
   4537                                           &cls->transfers[0],
   4538                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   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_deposit_to_transfer (&cls->instance,
   4547                                                      &cls->signkey,
   4548                                                      &cls->order,
   4549                                                      &cls->deposit,
   4550                                                      &cls->transfers[0],
   4551                                                      GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   4552                                                      false));
   4553   TEST_RET_ON_FAIL (test_insert_transfer_details (&cls->instance,
   4554                                                   &cls->account,
   4555                                                   &cls->transfers[0],
   4556                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   4557   /* Inserting deposits/transfers will automatically mark as wired. */
   4558   TEST_RET_ON_FAIL (test_lookup_payment_status (cls->instance.instance.id,
   4559                                                 cls->order.id,
   4560                                                 NULL,
   4561                                                 true,
   4562                                                 true));
   4563   TEST_RET_ON_FAIL (test_insert_deposit_to_transfer (&cls->instance,
   4564                                                      &cls->signkey,
   4565                                                      &cls->order,
   4566                                                      &cls->deposit,
   4567                                                      &cls->transfers[0],
   4568                                                      GNUNET_DB_STATUS_SUCCESS_ONE_RESULT,
   4569                                                      true));
   4570 
   4571   TEST_RET_ON_FAIL (test_lookup_transfer_summary (cls->deposit.exchange_url,
   4572                                                   &cls->transfers[0].wtid,
   4573                                                   cls->order.id,
   4574                                                   &cls->deposit.amount_with_fee,
   4575                                                   &cls->deposit.deposit_fee));
   4576   TEST_RET_ON_FAIL (test_lookup_transfer_details (cls->deposit.exchange_url,
   4577                                                   &cls->transfers[0].wtid,
   4578                                                   1,
   4579                                                   &cls->transfers[0].data.
   4580                                                   details[0]));
   4581   TEST_RET_ON_FAIL (test_lookup_transfer_details_by_order (order_serial,
   4582                                                            1,
   4583                                                            &cls->transfers[0]));
   4584   TEST_RET_ON_FAIL (test_lookup_transfers (&cls->instance,
   4585                                            &cls->account,
   4586                                            GNUNET_TIME_UNIT_FOREVER_TS,
   4587                                            GNUNET_TIME_UNIT_ZERO_TS,
   4588                                            8,
   4589                                            0,
   4590                                            1,
   4591                                            &cls->transfers[0]));
   4592   return 0;
   4593 }
   4594 
   4595 
   4596 /**
   4597  * Takes care of all work for testing transfers.
   4598  *
   4599  * @return 0 on success, 1 otherwise.
   4600  */
   4601 static int
   4602 test_transfers (void)
   4603 {
   4604   struct TestTransfers_Closure test_cls;
   4605   int test_result;
   4606 
   4607   pre_test_transfers (&test_cls);
   4608   test_result = run_test_transfers (&test_cls);
   4609   post_test_transfers (&test_cls);
   4610   return test_result;
   4611 }
   4612 
   4613 
   4614 /**
   4615  * Closure for testing lookup_refunds.
   4616  */
   4617 struct TestLookupRefunds_Closure
   4618 {
   4619   /**
   4620    * Length of @e coin_pub_to_cmp and @e refund_amount_to_cmp.
   4621    */
   4622   unsigned int refunds_to_cmp_length;
   4623 
   4624   /**
   4625    * Public keys of the refunded coins.
   4626    */
   4627   const struct TALER_CoinSpendPublicKeyP *coin_pub_to_cmp;
   4628 
   4629   /**
   4630    * Amount of each refund.
   4631    */
   4632   const struct TALER_Amount *refund_amount_to_cmp;
   4633 
   4634   /**
   4635    * Number of results matching each refund provided.
   4636    */
   4637   unsigned int *results_matching;
   4638 
   4639   /**
   4640    * Total number of results returned;
   4641    */
   4642   unsigned int results_length;
   4643 };
   4644 
   4645 
   4646 /**
   4647  * Called after test_lookup_refunds.
   4648  * @param cls pointer to a TestLookupRefunds_Closure.
   4649  * @param coin_pub the public key of the coin for the refund found.
   4650  * @param refund_amount the amount of the refund found.
   4651  */
   4652 static void
   4653 lookup_refunds_cb (void *cls,
   4654                    const struct TALER_CoinSpendPublicKeyP *coin_pub,
   4655                    const struct TALER_Amount *refund_amount)
   4656 {
   4657   struct TestLookupRefunds_Closure *cmp = cls;
   4658   if (NULL == cmp)
   4659     return;
   4660   cmp->results_length += 1;
   4661   for (unsigned int i = 0; cmp->refunds_to_cmp_length > i; ++i)
   4662   {
   4663     if ((0 == GNUNET_memcmp (&cmp->coin_pub_to_cmp[i],
   4664                              coin_pub)) &&
   4665         (GNUNET_OK == TALER_amount_cmp_currency (&cmp->refund_amount_to_cmp[i],
   4666                                                  refund_amount)) &&
   4667         (0 == TALER_amount_cmp (&cmp->refund_amount_to_cmp[i],
   4668                                 refund_amount)))
   4669     {
   4670       cmp->results_matching[i] += 1;
   4671     }
   4672   }
   4673 }
   4674 
   4675 
   4676 /**
   4677  * Tests looking up refunds from the database.
   4678  * @param instance the instance to look up refunds for.
   4679  * @param h_contract_terms hash of the contract terms the refunds are for.
   4680  * @param refunds_length length of @e coin_pubs and @e refund_amounts.
   4681  * @param coin_pubs the public keys of the coins that were refunded.
   4682  * @param refund_amounts the amounts of the coins that were refunded.
   4683  *
   4684  * @return 0 on success, 1 otherwise.
   4685  */
   4686 static int
   4687 test_lookup_refunds (const struct InstanceData *instance,
   4688                      const struct TALER_PrivateContractHashP *h_contract_terms,
   4689                      unsigned int refunds_length,
   4690                      const struct TALER_CoinSpendPublicKeyP *coin_pubs,
   4691                      const struct TALER_Amount *refund_amounts)
   4692 {
   4693   unsigned int results_matching[refunds_length];
   4694   struct TestLookupRefunds_Closure cmp = {
   4695     .refunds_to_cmp_length = refunds_length,
   4696     .coin_pub_to_cmp = coin_pubs,
   4697     .refund_amount_to_cmp = refund_amounts,
   4698     .results_matching = results_matching,
   4699     .results_length = 0
   4700   };
   4701   memset (results_matching, 0, sizeof (unsigned int) * refunds_length);
   4702   if (1 != TALER_MERCHANTDB_lookup_refunds (pg,
   4703                                             instance->instance.id,
   4704                                             h_contract_terms,
   4705                                             &lookup_refunds_cb,
   4706                                             &cmp))
   4707   {
   4708     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4709                 "Lookup refunds failed\n");
   4710     return 1;
   4711   }
   4712   if (refunds_length != cmp.results_length)
   4713   {
   4714     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4715                 "Lookup refunds failed: incorrect number of results returned\n")
   4716     ;
   4717     return 1;
   4718   }
   4719   for (unsigned int i = 0; refunds_length > i; ++i)
   4720   {
   4721     if (1 != cmp.results_matching[i])
   4722     {
   4723       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4724                   "Lookup refunds failed: mismatched data\n");
   4725       return 1;
   4726     }
   4727   }
   4728   return 0;
   4729 }
   4730 
   4731 
   4732 /**
   4733  * Container for refund data.
   4734  */
   4735 struct RefundData
   4736 {
   4737   /**
   4738    * When the refund occurred.
   4739    */
   4740   struct GNUNET_TIME_Timestamp timestamp;
   4741 
   4742   /**
   4743    * Reason for the refund.
   4744    */
   4745   const char *reason;
   4746 
   4747   /**
   4748    * Amount of the refund.
   4749    */
   4750   struct TALER_Amount refund_amount;
   4751 
   4752   /**
   4753    * Public key of the coin that was refunded.
   4754    */
   4755   const struct TALER_CoinSpendPublicKeyP *coin_pub;
   4756 
   4757   /**
   4758    * URL to the exchange that did the refund.
   4759    */
   4760   const char *exchange_url;
   4761 };
   4762 
   4763 
   4764 /**
   4765  * Creates a refund for testing with.
   4766  * @param deposit the deposit being refunded.
   4767  * @param refund the data to set.
   4768  */
   4769 static void
   4770 make_refund (const struct DepositData *deposit,
   4771              struct RefundData *refund)
   4772 {
   4773   refund->timestamp = GNUNET_TIME_timestamp_get ();
   4774   refund->reason = "some reason";
   4775   refund->refund_amount = deposit->amount_with_fee;
   4776   refund->coin_pub = &deposit->coin_pub;
   4777   refund->exchange_url = deposit->exchange_url;
   4778 }
   4779 
   4780 
   4781 /**
   4782  * Container for proof of a refund.
   4783  */
   4784 struct RefundProofData
   4785 {
   4786   /**
   4787    * Fee charged for the refund.
   4788    */
   4789   struct TALER_Amount refund_fee;
   4790 
   4791   /**
   4792    * The exchange's signature on the refund.
   4793    */
   4794   struct TALER_ExchangeSignatureP exchange_sig;
   4795 };
   4796 
   4797 
   4798 /**
   4799  * Closure for testing lookup_refunds_detailed.
   4800  */
   4801 struct TestLookupRefundsDetailed_Closure
   4802 {
   4803   /**
   4804    * Length of @e refunds_to_cmp.
   4805    */
   4806   unsigned int refunds_to_cmp_length;
   4807 
   4808   /**
   4809    * The refunds we expect to find.
   4810    */
   4811   const struct RefundData *refunds_to_cmp;
   4812 
   4813   /**
   4814    * Whether to compare the timestamps or not (if we don't have direct control
   4815    * of the timestamps, there will be differences on the order of microseconds
   4816    * that can be ignored).
   4817    */
   4818   bool cmp_timestamps;
   4819 
   4820   /**
   4821    * The number of results matching each refund.
   4822    */
   4823   unsigned int *results_matching;
   4824 
   4825   /**
   4826    * The total number of results from the db.
   4827    */
   4828   unsigned int results_length;
   4829 };
   4830 
   4831 
   4832 /**
   4833  * Called after test_lookup_refunds_detailed.
   4834  * @param cls pointer to a TestLookupRefundsDetailed_Closure.
   4835  * @param refund_serial unique serial number of the refund
   4836  * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
   4837  * @param coin_pub public coin from which the refund comes from
   4838  * @param exchange_url URL of the exchange that issued @a coin_pub
   4839  * @param rtransaction_id identificator of the refund
   4840  * @param reason human-readable explanation of the refund
   4841  * @param refund_amount refund amount which is being taken from @a coin_pub
   4842  * @param pending true if this refund has not been processed by the wallet/exchange
   4843  */
   4844 static void
   4845 lookup_refunds_detailed_cb (void *cls,
   4846                             uint64_t refund_serial,
   4847                             struct GNUNET_TIME_Timestamp timestamp,
   4848                             const struct TALER_CoinSpendPublicKeyP *coin_pub,
   4849                             const char *exchange_url,
   4850                             uint64_t rtransaction_id,
   4851                             const char *reason,
   4852                             const struct TALER_Amount *refund_amount,
   4853                             bool pending)
   4854 {
   4855   struct TestLookupRefundsDetailed_Closure *cmp = cls;
   4856   if (NULL == cmp)
   4857     return;
   4858   cmp->results_length += 1;
   4859   for (unsigned int i = 0; cmp->refunds_to_cmp_length > i; ++i)
   4860   {
   4861     if (((GNUNET_TIME_timestamp_cmp (cmp->refunds_to_cmp[i].timestamp,
   4862                                      ==,
   4863                                      timestamp)) ||
   4864          ! cmp->cmp_timestamps) &&
   4865         (0 == GNUNET_memcmp (cmp->refunds_to_cmp[i].coin_pub,
   4866                              coin_pub)) &&
   4867         (0 == strcmp (cmp->refunds_to_cmp[i].exchange_url,
   4868                       exchange_url)) &&
   4869         (0 == strcmp (cmp->refunds_to_cmp[i].reason,
   4870                       reason)) &&
   4871         (GNUNET_OK ==
   4872          TALER_amount_cmp_currency (
   4873            &cmp->refunds_to_cmp[i].refund_amount,
   4874            refund_amount)) &&
   4875         (0 == TALER_amount_cmp (&cmp->refunds_to_cmp[i].refund_amount,
   4876                                 refund_amount)))
   4877     {
   4878       cmp->results_matching[i] += 1;
   4879     }
   4880   }
   4881 }
   4882 
   4883 
   4884 /**
   4885  * Tests looking up refunds with details from the database.
   4886  * @param instance the instance to lookup from.
   4887  * @param h_contract_terms the contract terms the refunds were made for.
   4888  * @param cmp_timestamps whether to compare timestamps or not.
   4889  * @param refunds_length length of @e refunds.
   4890  * @param refunds the refunds we expect to be returned.
   4891  *
   4892  * @return 0 on success, 1 otherwise.
   4893  */
   4894 static int
   4895 test_lookup_refunds_detailed (
   4896   const struct InstanceData *instance,
   4897   const struct TALER_PrivateContractHashP *h_contract_terms,
   4898   bool cmp_timestamps,
   4899   unsigned int refunds_length,
   4900   const struct RefundData *refunds)
   4901 {
   4902   unsigned int results_matching[refunds_length];
   4903   struct TestLookupRefundsDetailed_Closure cmp = {
   4904     .refunds_to_cmp_length = refunds_length,
   4905     .refunds_to_cmp = refunds,
   4906     .cmp_timestamps = cmp_timestamps,
   4907     .results_matching = results_matching,
   4908     .results_length = 0
   4909   };
   4910   memset (results_matching, 0, sizeof (unsigned int) * refunds_length);
   4911   if (0 > TALER_MERCHANTDB_lookup_refunds_detailed (pg,
   4912                                                     instance->instance.id,
   4913                                                     h_contract_terms,
   4914                                                     &lookup_refunds_detailed_cb,
   4915                                                     &cmp))
   4916   {
   4917     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4918                 "Lookup refunds detailed failed\n");
   4919     return 1;
   4920   }
   4921   if (refunds_length != cmp.results_length)
   4922   {
   4923     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4924                 "Lookup refunds detailed failed: incorrect number of results\n")
   4925     ;
   4926     return 1;
   4927   }
   4928   for (unsigned int i = 0; refunds_length > i; ++i)
   4929   {
   4930     if (1 != cmp.results_matching[i])
   4931     {
   4932       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   4933                   "Lookup refunds detailed failed: mismatched data\n");
   4934       return 1;
   4935     }
   4936   }
   4937   return 0;
   4938 }
   4939 
   4940 
   4941 /**
   4942  * Closure for get_refund_serial.
   4943  */
   4944 struct LookupRefundSerial_Closure
   4945 {
   4946   /**
   4947    * The refund we are looking up the id for.
   4948    */
   4949   const struct RefundData *refund;
   4950 
   4951   /**
   4952    * The row number found.
   4953    */
   4954   uint64_t serial;
   4955 };
   4956 
   4957 
   4958 /**
   4959  * Called after get_refund_serial.
   4960  * @param cls pointer to a LookupRefundSerial_Closure.
   4961  * @param refund_serial unique serial number of the refund
   4962  * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
   4963  * @param coin_pub public coin from which the refund comes from
   4964  * @param exchange_url URL of the exchange that issued @a coin_pub
   4965  * @param rtransaction_id identificator of the refund
   4966  * @param reason human-readable explanation of the refund
   4967  * @param refund_amount refund amount which is being taken from @a coin_pub
   4968  * @param pending true if this refund has not been processed by the wallet/exchange
   4969  */
   4970 static void
   4971 get_refund_serial_cb (void *cls,
   4972                       uint64_t refund_serial,
   4973                       struct GNUNET_TIME_Timestamp timestamp,
   4974                       const struct TALER_CoinSpendPublicKeyP *coin_pub,
   4975                       const char *exchange_url,
   4976                       uint64_t rtransaction_id,
   4977                       const char *reason,
   4978                       const struct TALER_Amount *refund_amount,
   4979                       bool pending)
   4980 {
   4981   struct LookupRefundSerial_Closure *lookup_cls = cls;
   4982   if (NULL == lookup_cls)
   4983     return;
   4984   if ((GNUNET_TIME_timestamp_cmp (lookup_cls->refund->timestamp,
   4985                                   ==,
   4986                                   timestamp)) &&
   4987       (0 == GNUNET_memcmp (lookup_cls->refund->coin_pub,
   4988                            coin_pub)) &&
   4989       (0 == strcmp (lookup_cls->refund->exchange_url,
   4990                     exchange_url)) &&
   4991       (0 == strcmp (lookup_cls->refund->reason,
   4992                     reason)) &&
   4993       (GNUNET_OK ==
   4994        TALER_amount_cmp_currency (
   4995          &lookup_cls->refund->refund_amount,
   4996          refund_amount)) &&
   4997       (0 == TALER_amount_cmp (&lookup_cls->refund->refund_amount,
   4998                               refund_amount)))
   4999     lookup_cls->serial = refund_serial;
   5000 }
   5001 
   5002 
   5003 /**
   5004  * Utility function for getting the database row number of a refund.
   5005  * @param instance the instance associated with the refund.
   5006  * @param h_contract_terms the contract terms the refund was made with.
   5007  * @param refund the refund we are querying the row number of.
   5008  *
   5009  * @return the row number of the refund.
   5010  */
   5011 static uint64_t
   5012 get_refund_serial (const struct InstanceData *instance,
   5013                    const struct TALER_PrivateContractHashP *h_contract_terms,
   5014                    const struct RefundData *refund)
   5015 {
   5016   struct LookupRefundSerial_Closure lookup_cls = {
   5017     .refund = refund,
   5018     .serial = 0
   5019   };
   5020 
   5021   GNUNET_assert (0 < TALER_MERCHANTDB_lookup_refunds_detailed (pg,
   5022                                                                instance->instance.id,
   5023                                                                h_contract_terms,
   5024                                                                &get_refund_serial_cb,
   5025                                                                &lookup_cls));
   5026   GNUNET_assert (0 != lookup_cls.serial);
   5027 
   5028   return lookup_cls.serial;
   5029 }
   5030 
   5031 
   5032 /**
   5033  * Tests looking up proof of a refund.
   5034  * @param refund_serial the row number of the refund.
   5035  * @param expected_exchange_sig the exchange signature we are expecting.
   5036  * @param expected_exchange_pub the exchange public key we are expecting.
   5037  *
   5038  * @return 0 on success, 1 otherwise.
   5039  */
   5040 static int
   5041 test_lookup_refund_proof (uint64_t refund_serial,
   5042                           const struct
   5043                           TALER_ExchangeSignatureP *expected_exchange_sig,
   5044                           const struct
   5045                           TALER_ExchangePublicKeyP *expected_exchange_pub)
   5046 {
   5047   struct TALER_ExchangeSignatureP exchange_sig;
   5048   struct TALER_ExchangePublicKeyP exchange_pub;
   5049   if (1 != TALER_MERCHANTDB_lookup_refund_proof (pg,
   5050                                                  refund_serial,
   5051                                                  &exchange_sig,
   5052                                                  &exchange_pub))
   5053   {
   5054     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5055                 "Lookup refund proof failed\n");
   5056     return 1;
   5057   }
   5058   if ((0 != GNUNET_memcmp (expected_exchange_sig,
   5059                            &exchange_sig)) ||
   5060       (0 != GNUNET_memcmp (expected_exchange_pub,
   5061                            &exchange_pub)))
   5062   {
   5063     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5064                 "Lookup refund proof failed: mismatched data\n");
   5065     return 1;
   5066   }
   5067   return 0;
   5068 }
   5069 
   5070 
   5071 /**
   5072  * Closure for testing refund functionality.
   5073  */
   5074 struct TestRefunds_Closure
   5075 {
   5076   /**
   5077    * The instance.
   5078    */
   5079   struct InstanceData instance;
   5080 
   5081   /**
   5082    * The merchant account.
   5083    */
   5084   struct TALER_MERCHANTDB_AccountDetails account;
   5085 
   5086   /**
   5087    * The exchange signing key.
   5088    */
   5089   struct ExchangeSignkeyData signkey;
   5090 
   5091   /**
   5092    * The order data.
   5093    */
   5094   struct OrderData orders[2];
   5095 
   5096   /**
   5097    * The deposit data.
   5098    */
   5099   struct DepositData deposits[3];
   5100 
   5101   /**
   5102    * The refund data.
   5103    */
   5104   struct RefundData refunds[3];
   5105 
   5106   /**
   5107    * The refund proof data.
   5108    */
   5109   struct RefundProofData refund_proof;
   5110 };
   5111 
   5112 
   5113 /**
   5114  * Prepares for testing refunds.
   5115  * @param cls the closure to initialize.
   5116  */
   5117 static void
   5118 pre_test_refunds (struct TestRefunds_Closure *cls)
   5119 {
   5120   /* Instance */
   5121   make_instance ("test_inst_refunds",
   5122                  &cls->instance);
   5123 
   5124   /* Account */
   5125   make_account (&cls->account);
   5126   cls->account.instance_id = cls->instance.instance.id;
   5127   /* Signing key */
   5128   make_exchange_signkey (&cls->signkey);
   5129 
   5130   /* Order */
   5131   make_order ("test_refunds_od_0",
   5132               &cls->orders[0]);
   5133   make_order ("test_refunds_od_1",
   5134               &cls->orders[1]);
   5135 
   5136   /* Deposit */
   5137   make_deposit (&cls->instance,
   5138                 &cls->account,
   5139                 &cls->orders[0],
   5140                 &cls->signkey,
   5141                 &cls->deposits[0]);
   5142   make_deposit (&cls->instance,
   5143                 &cls->account,
   5144                 &cls->orders[0],
   5145                 &cls->signkey,
   5146                 &cls->deposits[1]);
   5147   make_deposit (&cls->instance,
   5148                 &cls->account,
   5149                 &cls->orders[1],
   5150                 &cls->signkey,
   5151                 &cls->deposits[2]);
   5152 
   5153   /* Refund */
   5154   make_refund (&cls->deposits[0],
   5155                &cls->refunds[0]);
   5156   make_refund (&cls->deposits[2],
   5157                &cls->refunds[1]);
   5158   make_refund (&cls->deposits[2],
   5159                &cls->refunds[2]);
   5160   GNUNET_assert (GNUNET_OK ==
   5161                  TALER_string_to_amount ("EUR:10.00",
   5162                                          &cls->refunds[1].refund_amount));
   5163   cls->refunds[1].reason = "refund 1";
   5164   GNUNET_assert (GNUNET_OK ==
   5165                  TALER_string_to_amount ("EUR:10.00",
   5166                                          &cls->refunds[2].refund_amount));
   5167   cls->refunds[2].reason = "refund 2";
   5168 
   5169   /* Refund proof */
   5170   GNUNET_assert (GNUNET_OK ==
   5171                  TALER_string_to_amount ("EUR:0.02",
   5172                                          &cls->refund_proof.refund_fee));
   5173   memset (&cls->refund_proof.exchange_sig,
   5174           42,
   5175           sizeof (cls->refund_proof.exchange_sig));
   5176 }
   5177 
   5178 
   5179 /**
   5180  * Cleans up after testing refunds.
   5181  * @param cls the closure.
   5182  */
   5183 static void
   5184 post_test_refunds (struct TestRefunds_Closure *cls)
   5185 {
   5186   free_instance_data (&cls->instance);
   5187   free_order_data (&cls->orders[0]);
   5188   free_order_data (&cls->orders[1]);
   5189 }
   5190 
   5191 
   5192 /**
   5193  * Runs the refund tests.
   5194  * @param cls the closure.
   5195  *
   5196  * @return 0 on success, 1 otherwise.
   5197  */
   5198 static int
   5199 run_test_refunds (struct TestRefunds_Closure *cls)
   5200 {
   5201   struct TALER_Amount inc;
   5202   uint64_t refund_serial;
   5203 
   5204   /* Insert an instance */
   5205   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   5206                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5207   /* Insert an account */
   5208   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   5209                                          &cls->account,
   5210                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5211   /* Insert an order */
   5212   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   5213                                        &cls->orders[0],
   5214                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5215   /* Insert contract terms */
   5216   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   5217                                                 &cls->orders[0],
   5218                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5219   /* Insert a signing key */
   5220   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   5221                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5222   /* Insert a deposit */
   5223   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5224                                          &cls->signkey,
   5225                                          &cls->deposits[0],
   5226                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5227   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5228                                          &cls->signkey,
   5229                                          &cls->deposits[1],
   5230                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5231   /* Mark as paid */
   5232   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   5233                                              &cls->orders[0],
   5234                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5235   /* Test refund coin */
   5236   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   5237                          TALER_MERCHANTDB_refund_coin (pg,
   5238                                                        cls->instance.instance.id,
   5239                                                        &cls->deposits[0].h_contract_terms
   5240                                                        ,
   5241                                                        cls->refunds[0].timestamp,
   5242                                                        cls->refunds[0].coin_pub,
   5243                                                        cls->refunds[0].reason),
   5244                          "Refund coin failed\n");
   5245   refund_serial = get_refund_serial (&cls->instance,
   5246                                      &cls->deposits[0].h_contract_terms,
   5247                                      &cls->refunds[0]);
   5248   /* Test double refund fails */
   5249   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS ==
   5250                          TALER_MERCHANTDB_refund_coin (pg,
   5251                                                        cls->instance.instance.id,
   5252                                                        &cls->deposits[0].h_contract_terms
   5253                                                        ,
   5254                                                        cls->refunds[0].timestamp,
   5255                                                        cls->refunds[0].coin_pub,
   5256                                                        cls->refunds[0].reason),
   5257                          "Refund coin failed\n");
   5258   /* Test lookup refunds */
   5259   TEST_RET_ON_FAIL (test_lookup_refunds (&cls->instance,
   5260                                          &cls->deposits[0].h_contract_terms,
   5261                                          1,
   5262                                          cls->refunds[0].coin_pub,
   5263                                          &cls->refunds[0].refund_amount));
   5264   /* Test lookup refunds detailed */
   5265   TEST_RET_ON_FAIL (test_lookup_refunds_detailed (&cls->instance,
   5266                                                   &cls->deposits[0].
   5267                                                   h_contract_terms,
   5268                                                   true,
   5269                                                   1,
   5270                                                   &cls->refunds[0]));
   5271   /* Test insert refund proof */
   5272   TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   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_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS ==
   5281                          TALER_MERCHANTDB_insert_refund_proof (pg,
   5282                                                                refund_serial,
   5283                                                                &cls->refund_proof.
   5284                                                                exchange_sig,
   5285                                                                &cls->signkey.exchange_pub
   5286                                                                ),
   5287                          "Insert refund proof failed\n");
   5288   /* Test that we can't give too much in refunds */
   5289   GNUNET_assert (GNUNET_OK ==
   5290                  TALER_string_to_amount ("EUR:1000.00",
   5291                                          &inc));
   5292   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_TOO_HIGH ==
   5293                          TALER_MERCHANTDB_increase_refund (pg,
   5294                                                            cls->instance.instance.id,
   5295                                                            cls->orders[0].id,
   5296                                                            &inc,
   5297                                                            NULL,
   5298                                                            NULL,
   5299                                                            "more"),
   5300                          "Increase refund failed\n");
   5301   /* Test increase refund */
   5302   GNUNET_assert (GNUNET_OK ==
   5303                  TALER_string_to_amount ("EUR:1.00",
   5304                                          &inc));
   5305   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_SUCCESS ==
   5306                          TALER_MERCHANTDB_increase_refund (pg,
   5307                                                            cls->instance.instance.id,
   5308                                                            cls->orders[0].id,
   5309                                                            &inc,
   5310                                                            NULL,
   5311                                                            NULL,
   5312                                                            "more"),
   5313                          "Increase refund failed\n");
   5314   /* Test lookup refund proof */
   5315   TEST_RET_ON_FAIL (test_lookup_refund_proof (1,
   5316                                               &cls->refund_proof.exchange_sig,
   5317                                               &cls->signkey.exchange_pub));
   5318   TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   5319                                        &cls->orders[1],
   5320                                        GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5321   TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   5322                                                 &cls->orders[1],
   5323                                                 GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5324   TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5325                                          &cls->signkey,
   5326                                          &cls->deposits[2],
   5327                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5328   TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   5329                                              &cls->orders[1],
   5330                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5331   /* Test refunding a small amount of the coin, then increasing it */
   5332   GNUNET_assert (GNUNET_OK ==
   5333                  TALER_string_to_amount ("EUR:10.00",
   5334                                          &inc));
   5335   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_SUCCESS ==
   5336                          TALER_MERCHANTDB_increase_refund (pg,
   5337                                                            cls->instance.instance.id,
   5338                                                            cls->orders[1].id,
   5339                                                            &inc,
   5340                                                            NULL,
   5341                                                            NULL,
   5342                                                            cls->refunds[1].reason),
   5343                          "Increase refund failed\n");
   5344   GNUNET_assert (GNUNET_OK ==
   5345                  TALER_string_to_amount ("EUR:20.00",
   5346                                          &inc));
   5347   TEST_COND_RET_ON_FAIL (TALER_MERCHANTDB_RS_SUCCESS ==
   5348                          TALER_MERCHANTDB_increase_refund (pg,
   5349                                                            cls->instance.instance.id,
   5350                                                            cls->orders[1].id,
   5351                                                            &inc,
   5352                                                            NULL,
   5353                                                            NULL,
   5354                                                            cls->refunds[2].reason),
   5355                          "Increase refund failed\n");
   5356   TEST_RET_ON_FAIL (test_lookup_refunds_detailed (&cls->instance,
   5357                                                   &cls->deposits[2].
   5358                                                   h_contract_terms,
   5359                                                   false,
   5360                                                   2,
   5361                                                   &cls->refunds[1]));
   5362   return 0;
   5363 }
   5364 
   5365 
   5366 /**
   5367  * All logic for testing refunds.
   5368  *
   5369  * @return 0 on success, 1 otherwise.
   5370  */
   5371 static int
   5372 test_refunds (void)
   5373 {
   5374   struct TestRefunds_Closure test_cls;
   5375   int test_result;
   5376 
   5377   pre_test_refunds (&test_cls);
   5378   test_result = run_test_refunds (&test_cls);
   5379   post_test_refunds (&test_cls);
   5380   return test_result;
   5381 }
   5382 
   5383 
   5384 /**
   5385  * Convenience function that reverses an array of orders.
   5386  * @param orders_length length of @e orders.
   5387  * @param orders the array to reverse.
   5388  */
   5389 static void
   5390 reverse_order_data_array (unsigned int orders_length,
   5391                           struct OrderData *orders)
   5392 {
   5393   struct OrderData tmp[orders_length];
   5394   for (unsigned int i = 0; i < orders_length; ++i)
   5395     tmp[i] = orders[orders_length - 1 - i];
   5396   for (unsigned int i = 0; i < orders_length; ++i)
   5397     orders[i] = tmp[i];
   5398 }
   5399 
   5400 
   5401 /**
   5402  * Closure for testing all the filters for looking up orders.
   5403  */
   5404 struct TestLookupOrdersAllFilters_Closure
   5405 {
   5406   /**
   5407    * The instance.
   5408    */
   5409   struct InstanceData instance;
   5410 
   5411   /**
   5412    * The merchant account.
   5413    */
   5414   struct TALER_MERCHANTDB_AccountDetails account;
   5415 
   5416   /**
   5417    * The exchange signing key.
   5418    */
   5419   struct ExchangeSignkeyData signkey;
   5420 
   5421   /**
   5422    * The array of order ids.
   5423    */
   5424   char *order_ids[64];
   5425 
   5426   /**
   5427    * The array of orders.
   5428    */
   5429   struct OrderData orders[64];
   5430 
   5431   /**
   5432    * The array of deposits.
   5433    */
   5434   struct DepositData deposits[64];
   5435 
   5436   /**
   5437    * The array of refunds.
   5438    */
   5439   struct RefundData refunds[64];
   5440 };
   5441 
   5442 
   5443 /**
   5444  * Sets up for testing lookup order filters.
   5445  * @param cls the closure.
   5446  */
   5447 static void
   5448 pre_test_lookup_orders_all_filters (
   5449   struct TestLookupOrdersAllFilters_Closure *cls)
   5450 {
   5451   make_instance ("test_inst_lookup_orders_all_filters",
   5452                  &cls->instance);
   5453   make_account (&cls->account);
   5454   cls->account.instance_id = cls->instance.instance.id;
   5455   make_exchange_signkey (&cls->signkey);
   5456   for (unsigned int i = 0; i < 64; ++i)
   5457   {
   5458     (void) GNUNET_asprintf (&cls->order_ids[i],
   5459                             "test_orders_filter_od_%u",
   5460                             i);
   5461     make_order (cls->order_ids[i],
   5462                 &cls->orders[i]);
   5463     GNUNET_assert (0 ==
   5464                    json_object_set_new (cls->orders[i].contract,
   5465                                         "order_id",
   5466                                         json_string (cls->order_ids[i])));
   5467     make_deposit (&cls->instance,
   5468                   &cls->account,
   5469                   &cls->orders[i],
   5470                   &cls->signkey,
   5471                   &cls->deposits[i]);
   5472     make_refund (&cls->deposits[i],
   5473                  &cls->refunds[i]);
   5474   }
   5475 }
   5476 
   5477 
   5478 /**
   5479  * Cleans up after testing lookup order filters.
   5480  * @param cls the closure.
   5481  */
   5482 static void
   5483 post_test_lookup_orders_all_filters (
   5484   struct TestLookupOrdersAllFilters_Closure *cls)
   5485 {
   5486   free_instance_data (&cls->instance);
   5487   for (unsigned int i = 0; i < 64; ++i)
   5488   {
   5489     free_order_data (&cls->orders[i]);
   5490     GNUNET_free (cls->order_ids[i]);
   5491   }
   5492 }
   5493 
   5494 
   5495 /**
   5496  * Runs the tests for lookup order filters.
   5497  * @param cls the closure.
   5498  *
   5499  * @return 0 on success, 1 otherwise.
   5500  */
   5501 static int
   5502 run_test_lookup_orders_all_filters (
   5503   struct TestLookupOrdersAllFilters_Closure *cls)
   5504 {
   5505   /* Order filter extravaganza */
   5506   struct
   5507   {
   5508     bool claimed;
   5509     bool paid;
   5510     bool refunded;
   5511     bool wired;
   5512   } order_status[64];
   5513   unsigned int *permutation;
   5514 
   5515   /* Pseudorandomly generate variations for the filter to differentiate */
   5516   GNUNET_CRYPTO_seed_weak_random (1);
   5517   permutation = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
   5518                                               64);
   5519   for (unsigned int i = 0; i < 64; ++i)
   5520   {
   5521     unsigned int dest = permutation[i];
   5522     order_status[dest].claimed = (i & 1) ? true : false;
   5523     order_status[dest].paid = (3 == (i & 3)) ? true : false;
   5524     order_status[dest].refunded = (5 == (i & 5)) ? true : false;
   5525     order_status[dest].wired = (9 == (i & 9)) ? true : false;
   5526   }
   5527   GNUNET_free (permutation);
   5528 
   5529 
   5530   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   5531                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5532   TEST_RET_ON_FAIL (test_insert_account (&cls->instance,
   5533                                          &cls->account,
   5534                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5535   TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey,
   5536                                                   GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5537   for (unsigned int i = 0; i < 64; ++i)
   5538   {
   5539     uint64_t order_serial;
   5540 
   5541     TEST_RET_ON_FAIL (test_insert_order (&cls->instance,
   5542                                          &cls->orders[i],
   5543                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5544     order_serial = get_order_serial (&cls->instance,
   5545                                      &cls->orders[i]);
   5546 
   5547     if (order_status[i].claimed)
   5548     {
   5549       TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance,
   5550                                                     &cls->orders[i],
   5551                                                     GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5552     }
   5553     else
   5554     {
   5555       continue;
   5556     }
   5557 
   5558     if (order_status[i].paid)
   5559       TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance,
   5560                                                  &cls->orders[i],
   5561                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5562     if (order_status[i].refunded)
   5563     {
   5564       TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance,
   5565                                              &cls->signkey,
   5566                                              &cls->deposits[i],
   5567                                              GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5568       TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
   5569                              TALER_MERCHANTDB_refund_coin (pg,
   5570                                                            cls->instance.instance.id,
   5571                                                            &cls->deposits[i].
   5572                                                            h_contract_terms,
   5573                                                            cls->refunds[i].timestamp,
   5574                                                            cls->refunds[i].coin_pub,
   5575                                                            cls->refunds[i].reason),
   5576                              "Refund coin failed\n");
   5577     }
   5578 
   5579     if (order_status[i].wired)
   5580       TEST_RET_ON_FAIL (test_mark_order_wired (order_serial,
   5581                                                GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5582   }
   5583 
   5584   /* There are 3^3 = 27 possibilities here, not counting inc/dec and start row */
   5585   for (unsigned int i = 0; i < 27; ++i)
   5586   {
   5587     struct TALER_MERCHANTDB_OrderFilter filter = {
   5588       .paid = (i % 3) + 1,
   5589       .refunded = ((i / 3) % 3) + 1,
   5590       .wired = ((i / 9) % 3) + 1,
   5591       .date = GNUNET_TIME_UNIT_ZERO_TS,
   5592       .start_row = 0,
   5593       .delta = 64
   5594     };
   5595     unsigned int orders_length = 0;
   5596     struct OrderData orders[64];
   5597 
   5598     /* Now figure out which orders should make it through the filter */
   5599     for (unsigned int j = 0; j < 64; ++j)
   5600     {
   5601       if (((TALER_EXCHANGE_YNA_YES == filter.paid) &&
   5602            (true != order_status[j].paid)) ||
   5603           ((TALER_EXCHANGE_YNA_NO == filter.paid) &&
   5604            (false != order_status[j].paid)) ||
   5605           ((TALER_EXCHANGE_YNA_YES == filter.refunded) &&
   5606            (true != order_status[j].refunded)) ||
   5607           ((TALER_EXCHANGE_YNA_NO == filter.refunded) &&
   5608            (false != order_status[j].refunded)) ||
   5609           ((TALER_EXCHANGE_YNA_YES == filter.wired) &&
   5610            (true != order_status[j].wired)) ||
   5611           ((TALER_EXCHANGE_YNA_NO == filter.wired) &&
   5612            (false != order_status[j].wired)))
   5613         continue;
   5614       orders[orders_length] = cls->orders[j];
   5615       orders_length += 1;
   5616     }
   5617 
   5618     /* Test the lookup */
   5619     TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   5620                                           &filter,
   5621                                           orders_length,
   5622                                           orders));
   5623 
   5624     /* Now test decreasing */
   5625     filter.start_row = 256;
   5626     filter.date = GNUNET_TIME_UNIT_FOREVER_TS;
   5627     filter.delta = -64;
   5628 
   5629     reverse_order_data_array (orders_length,
   5630                               orders);
   5631 
   5632     TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance,
   5633                                           &filter,
   5634                                           orders_length,
   5635                                           orders));
   5636   }
   5637 
   5638   return 0;
   5639 }
   5640 
   5641 
   5642 /**
   5643  * Handles all logic for testing lookup order filters.
   5644  *
   5645  * @return 0 on success, 1 otherwise.
   5646  */
   5647 static int
   5648 test_lookup_orders_all_filters (void)
   5649 {
   5650   struct TestLookupOrdersAllFilters_Closure test_cls;
   5651   int test_result;
   5652 
   5653   memset (&test_cls,
   5654           0,
   5655           sizeof (test_cls));
   5656   pre_test_lookup_orders_all_filters (&test_cls);
   5657   test_result = run_test_lookup_orders_all_filters (&test_cls);
   5658   post_test_lookup_orders_all_filters (&test_cls);
   5659   return test_result;
   5660 }
   5661 
   5662 
   5663 static void
   5664 kyc_status_ok (
   5665   void *cls,
   5666   const struct TALER_MerchantWireHashP *h_wire,
   5667   struct TALER_FullPayto payto_uri,
   5668   const char *exchange_url,
   5669   struct GNUNET_TIME_Timestamp last_check,
   5670   bool kyc_ok,
   5671   const struct TALER_AccountAccessTokenP *access_token,
   5672   unsigned int last_http_status,
   5673   enum TALER_ErrorCode last_ec,
   5674   bool in_aml_review,
   5675   const json_t *jlimits)
   5676 {
   5677   bool *fail = cls;
   5678 
   5679   if (kyc_ok)
   5680     *fail = false;
   5681 }
   5682 
   5683 
   5684 static void
   5685 kyc_status_fail (
   5686   void *cls,
   5687   const struct TALER_MerchantWireHashP *h_wire,
   5688   struct TALER_FullPayto payto_uri,
   5689   const char *exchange_url,
   5690   struct GNUNET_TIME_Timestamp last_check,
   5691   bool kyc_ok,
   5692   const struct TALER_AccountAccessTokenP *access_token,
   5693   unsigned int last_http_status,
   5694   enum TALER_ErrorCode last_ec,
   5695   bool in_aml_review,
   5696   const json_t *jlimits)
   5697 {
   5698   bool *fail = cls;
   5699 
   5700   if (! kyc_ok)
   5701     *fail = false;
   5702 }
   5703 
   5704 
   5705 /**
   5706  * Function that tests the KYC table.
   5707  *
   5708  * @return 0 on success, 1 otherwise.
   5709  */
   5710 static int
   5711 test_kyc (void)
   5712 {
   5713   struct InstanceData instance;
   5714   struct TALER_MERCHANTDB_AccountDetails account;
   5715   bool fail;
   5716   struct GNUNET_TIME_Timestamp now;
   5717 
   5718   make_instance ("test_kyc",
   5719                  &instance);
   5720   make_account (&account);
   5721   account.instance_id = instance.instance.id;
   5722   TEST_RET_ON_FAIL (test_insert_instance (&instance,
   5723                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5724   TEST_RET_ON_FAIL (test_insert_account (&instance,
   5725                                          &account,
   5726                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   5727   now = GNUNET_TIME_timestamp_get ();
   5728   TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   5729                     TALER_MERCHANTDB_account_kyc_set_status (pg,
   5730                                                              instance.instance.id,
   5731                                                              &account.h_wire,
   5732                                                              "https://exchange.net/",
   5733                                                              now,
   5734                                                              GNUNET_TIME_UNIT_FOREVER_ABS,
   5735                                                              GNUNET_TIME_UNIT_HOURS,
   5736                                                              MHD_HTTP_OK,
   5737                                                              TALER_EC_NONE,
   5738                                                              42,
   5739                                                              NULL,
   5740                                                              NULL,
   5741                                                              false,
   5742                                                              false));
   5743   TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   5744                     TALER_MERCHANTDB_account_kyc_set_status (pg,
   5745                                                              instance.instance.id,
   5746                                                              &account.h_wire,
   5747                                                              "https://exchange2.com/",
   5748                                                              now,
   5749                                                              GNUNET_TIME_UNIT_FOREVER_ABS,
   5750                                                              GNUNET_TIME_UNIT_HOURS,
   5751                                                              MHD_HTTP_OK,
   5752                                                              TALER_EC_NONE,
   5753                                                              42,
   5754                                                              NULL,
   5755                                                              NULL,
   5756                                                              false,
   5757                                                              false));
   5758   TEST_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
   5759                     TALER_MERCHANTDB_account_kyc_set_status (pg,
   5760                                                              instance.instance.id,
   5761                                                              &account.h_wire,
   5762                                                              "https://exchange.net/",
   5763                                                              now,
   5764                                                              GNUNET_TIME_UNIT_FOREVER_ABS,
   5765                                                              GNUNET_TIME_UNIT_HOURS,
   5766                                                              MHD_HTTP_OK,
   5767                                                              TALER_EC_NONE,
   5768                                                              42,
   5769                                                              NULL,
   5770                                                              NULL,
   5771                                                              false,
   5772                                                              true));
   5773   fail = true;
   5774   TEST_RET_ON_FAIL (1 !=
   5775                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5776                                                              instance.instance.id,
   5777                                                              &account.h_wire,
   5778                                                              "https://exchange.net/",
   5779                                                              &kyc_status_ok,
   5780                                                              &fail));
   5781   TEST_RET_ON_FAIL (fail);
   5782   fail = true;
   5783   TEST_RET_ON_FAIL (1 !=
   5784                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5785                                                              instance.instance.id,
   5786                                                              NULL,
   5787                                                              "https://exchange2.com/",
   5788                                                              &kyc_status_fail,
   5789                                                              &fail));
   5790   TEST_RET_ON_FAIL (fail);
   5791   fail = true;
   5792   TEST_RET_ON_FAIL (2 !=
   5793                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5794                                                              instance.instance.id,
   5795                                                              NULL,
   5796                                                              NULL,
   5797                                                              &kyc_status_fail,
   5798                                                              &fail));
   5799   TEST_RET_ON_FAIL (fail);
   5800   fail = true;
   5801   TEST_RET_ON_FAIL (2 !=
   5802                     TALER_MERCHANTDB_account_kyc_get_status (pg,
   5803                                                              instance.instance.id,
   5804                                                              NULL,
   5805                                                              NULL,
   5806                                                              &kyc_status_ok,
   5807                                                              &fail));
   5808   TEST_RET_ON_FAIL (fail);
   5809   json_decref (instance.instance.address);
   5810   json_decref (instance.instance.jurisdiction);
   5811   return 0;
   5812 }
   5813 
   5814 
   5815 /* *********** Templates ********** */
   5816 
   5817 /**
   5818  * A container for data relevant to a template.
   5819  */
   5820 struct TemplateData
   5821 {
   5822   /**
   5823    * The identifier of the template.
   5824    */
   5825   const char *id;
   5826 
   5827   /**
   5828    * The details of the template.
   5829    */
   5830   struct TALER_MERCHANTDB_TemplateDetails template;
   5831 };
   5832 
   5833 
   5834 /**
   5835  * Creates a template for testing with.
   5836  *
   5837  * @param id the id of the template.
   5838  * @param template the template data to fill.
   5839  */
   5840 static void
   5841 make_template (const char *id,
   5842                struct TemplateData *template)
   5843 {
   5844   template->id = id;
   5845   template->template.template_description = "This is a test template";
   5846   template->template.otp_id = NULL;
   5847   template->template.template_contract = json_array ();
   5848   GNUNET_assert (NULL != template->template.template_contract);
   5849 }
   5850 
   5851 
   5852 /**
   5853  * Frees memory associated with @e TemplateData.
   5854  *
   5855  * @param template the container to free.
   5856  */
   5857 static void
   5858 free_template_data (struct TemplateData *template)
   5859 {
   5860   GNUNET_free (template->template.otp_id);
   5861   json_decref (template->template.template_contract);
   5862 }
   5863 
   5864 
   5865 /**
   5866  * Compare two templates for equality.
   5867  *
   5868  * @param a the first template.
   5869  * @param b the second template.
   5870  * @return 0 on equality, 1 otherwise.
   5871  */
   5872 static int
   5873 check_templates_equal (const struct TALER_MERCHANTDB_TemplateDetails *a,
   5874                        const struct TALER_MERCHANTDB_TemplateDetails *b)
   5875 {
   5876   if ((0 != strcmp (a->template_description,
   5877                     b->template_description)) ||
   5878       ( (NULL == a->otp_id) && (NULL != b->otp_id)) ||
   5879       ( (NULL != a->otp_id) && (NULL == b->otp_id)) ||
   5880       ( (NULL != a->otp_id) && (0 != strcmp (a->otp_id,
   5881                                              b->otp_id))) ||
   5882       (1 != json_equal (a->template_contract,
   5883                         b->template_contract)))
   5884     return 1;
   5885   return 0;
   5886 }
   5887 
   5888 
   5889 /**
   5890  * Tests inserting template data into the database.
   5891  *
   5892  * @param instance the instance to insert the template for.
   5893  * @param template the template data to insert.
   5894  * @param expected_result the result we expect the db to return.
   5895  * @return 0 when successful, 1 otherwise.
   5896  */
   5897 static int
   5898 test_insert_template (const struct InstanceData *instance,
   5899                       const struct TemplateData *template,
   5900                       enum GNUNET_DB_QueryStatus expected_result)
   5901 {
   5902   TEST_COND_RET_ON_FAIL (expected_result ==
   5903                          TALER_MERCHANTDB_insert_template (pg,
   5904                                                            instance->instance.id,
   5905                                                            template->id,
   5906                                                            0,
   5907                                                            &template->template),
   5908                          "Insert template failed\n");
   5909   return 0;
   5910 }
   5911 
   5912 
   5913 /**
   5914  * Tests updating template data in the database.
   5915  *
   5916  * @param instance the instance to update the template for.
   5917  * @param template the template data to update.
   5918  * @param expected_result the result we expect the db to return.
   5919  * @return 0 when successful, 1 otherwise.
   5920  */
   5921 static int
   5922 test_update_template (const struct InstanceData *instance,
   5923                       const struct TemplateData *template,
   5924                       enum GNUNET_DB_QueryStatus expected_result)
   5925 {
   5926   TEST_COND_RET_ON_FAIL (expected_result ==
   5927                          TALER_MERCHANTDB_update_template (pg,
   5928                                                            instance->instance.id,
   5929                                                            template->id,
   5930                                                            &template->template),
   5931                          "Update template failed\n");
   5932   return 0;
   5933 }
   5934 
   5935 
   5936 /**
   5937  * Tests looking up a template from the db.
   5938  *
   5939  * @param instance the instance to query from.
   5940  * @param template the template to query and compare to.
   5941  * @return 0 when successful, 1 otherwise.
   5942  */
   5943 static int
   5944 test_lookup_template (const struct InstanceData *instance,
   5945                       const struct TemplateData *template)
   5946 {
   5947   const struct TALER_MERCHANTDB_TemplateDetails *to_cmp
   5948     = &template->template;
   5949   struct TALER_MERCHANTDB_TemplateDetails lookup_result;
   5950 
   5951   if (0 > TALER_MERCHANTDB_lookup_template (pg,
   5952                                             instance->instance.id,
   5953                                             template->id,
   5954                                             &lookup_result))
   5955   {
   5956     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5957                 "Lookup template failed\n");
   5958     TALER_MERCHANTDB_template_details_free (&lookup_result);
   5959     return 1;
   5960   }
   5961   if (0 != check_templates_equal (&lookup_result,
   5962                                   to_cmp))
   5963   {
   5964     GNUNET_break (0);
   5965     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   5966                 "Lookup template failed: incorrect template returned\n");
   5967     TALER_MERCHANTDB_template_details_free (&lookup_result);
   5968     return 1;
   5969   }
   5970   TALER_MERCHANTDB_template_details_free (&lookup_result);
   5971   return 0;
   5972 }
   5973 
   5974 
   5975 /**
   5976  * Closure for testing template lookup
   5977  */
   5978 struct TestLookupTemplates_Closure
   5979 {
   5980   /**
   5981    * Number of template ids to compare to
   5982    */
   5983   unsigned int templates_to_cmp_length;
   5984 
   5985   /**
   5986    * Pointer to array of template ids
   5987    */
   5988   const struct TemplateData *templates_to_cmp;
   5989 
   5990   /**
   5991    * Pointer to array of number of matches for each template
   5992    */
   5993   unsigned int *results_matching;
   5994 
   5995   /**
   5996    * Total number of results returned
   5997    */
   5998   unsigned int results_length;
   5999 };
   6000 
   6001 
   6002 /**
   6003  * Function called after calling @e test_lookup_templates
   6004  *
   6005  * @param cls a pointer to the lookup closure.
   6006  * @param template_id the identifier of the template found.
   6007  */
   6008 static void
   6009 lookup_templates_cb (void *cls,
   6010                      const char *template_id,
   6011                      const char *template_description)
   6012 {
   6013   struct TestLookupTemplates_Closure *cmp = cls;
   6014 
   6015   if (NULL == cmp)
   6016     return;
   6017   cmp->results_length += 1;
   6018   for (unsigned int i = 0; cmp->templates_to_cmp_length > i; ++i)
   6019   {
   6020     if ( (0 == strcmp (cmp->templates_to_cmp[i].id,
   6021                        template_id)) &&
   6022          (0 == strcmp (cmp->templates_to_cmp[i].template.template_description,
   6023                        template_description)) )
   6024       cmp->results_matching[i] += 1;
   6025   }
   6026 }
   6027 
   6028 
   6029 /**
   6030  * Tests looking up all templates for an instance.
   6031  *
   6032  * @param instance the instance to query from.
   6033  * @param templates_length the number of templates we are expecting.
   6034  * @param templates the list of templates that we expect to be found.
   6035  * @return 0 when successful, 1 otherwise.
   6036  */
   6037 static int
   6038 test_lookup_templates (const struct InstanceData *instance,
   6039                        unsigned int templates_length,
   6040                        const struct TemplateData *templates)
   6041 {
   6042   unsigned int results_matching[templates_length];
   6043   struct TestLookupTemplates_Closure cls = {
   6044     .templates_to_cmp_length = templates_length,
   6045     .templates_to_cmp = templates,
   6046     .results_matching = results_matching,
   6047     .results_length = 0
   6048   };
   6049 
   6050   memset (results_matching,
   6051           0,
   6052           sizeof (unsigned int) * templates_length);
   6053   if (0 > TALER_MERCHANTDB_lookup_templates (pg,
   6054                                              instance->instance.id,
   6055                                              &lookup_templates_cb,
   6056                                              &cls))
   6057   {
   6058     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6059                 "Lookup templates failed\n");
   6060     return 1;
   6061   }
   6062   if (templates_length != cls.results_length)
   6063   {
   6064     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6065                 "Lookup templates failed: incorrect number of results\n");
   6066     return 1;
   6067   }
   6068   for (unsigned int i = 0; templates_length > i; ++i)
   6069   {
   6070     if (1 != cls.results_matching[i])
   6071     {
   6072       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6073                   "Lookup templates failed: mismatched data\n");
   6074       return 1;
   6075     }
   6076   }
   6077   return 0;
   6078 }
   6079 
   6080 
   6081 /**
   6082  * Tests deleting a template.
   6083  *
   6084  * @param instance the instance to delete the template from.
   6085  * @param template the template that should be deleted.
   6086  * @param expected_result the result that we expect the DB to return.
   6087  * @return 0 when successful, 1 otherwise.
   6088  */
   6089 static int
   6090 test_delete_template (const struct InstanceData *instance,
   6091                       const struct TemplateData *template,
   6092                       enum GNUNET_DB_QueryStatus expected_result)
   6093 {
   6094   TEST_COND_RET_ON_FAIL (expected_result ==
   6095                          TALER_MERCHANTDB_delete_template (pg,
   6096                                                            instance->instance.id,
   6097                                                            template->id),
   6098                          "Delete template failed\n");
   6099   return 0;
   6100 }
   6101 
   6102 
   6103 /**
   6104  * Closure for template tests.
   6105  */
   6106 struct TestTemplates_Closure
   6107 {
   6108   /**
   6109    * The instance to use for this test.
   6110    */
   6111   struct InstanceData instance;
   6112 
   6113   /**
   6114    * The array of templates.
   6115    */
   6116   struct TemplateData templates[2];
   6117 };
   6118 
   6119 
   6120 /**
   6121  * Sets up the data structures used in the template tests.
   6122  *
   6123  * @param cls the closure to fill with test data.
   6124  */
   6125 static void
   6126 pre_test_templates (struct TestTemplates_Closure *cls)
   6127 {
   6128   /* Instance */
   6129   make_instance ("test_inst_templates",
   6130                  &cls->instance);
   6131 
   6132   /* Templates */
   6133   make_template ("test_templates_pd_0",
   6134                  &cls->templates[0]);
   6135 
   6136   make_template ("test_templates_pd_1",
   6137                  &cls->templates[1]);
   6138   cls->templates[1].template.template_description =
   6139     "This is a another test template";
   6140 }
   6141 
   6142 
   6143 /**
   6144  * Handles all teardown after testing.
   6145  *
   6146  * @param cls the closure containing memory to be freed.
   6147  */
   6148 static void
   6149 post_test_templates (struct TestTemplates_Closure *cls)
   6150 {
   6151   free_instance_data (&cls->instance);
   6152   free_template_data (&cls->templates[0]);
   6153   free_template_data (&cls->templates[1]);
   6154 }
   6155 
   6156 
   6157 /**
   6158  * Runs the tests for templates.
   6159  *
   6160  * @param cls the container of the test data.
   6161  * @return 0 on success, 1 otherwise.
   6162  */
   6163 static int
   6164 run_test_templates (struct TestTemplates_Closure *cls)
   6165 {
   6166 
   6167   /* Test that insert without an instance fails */
   6168   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6169                                           &cls->templates[0],
   6170                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6171   /* Insert the instance */
   6172   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   6173                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6174   /* Test inserting a template */
   6175   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6176                                           &cls->templates[0],
   6177                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6178   /* Test that double insert fails */
   6179   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6180                                           &cls->templates[0],
   6181                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6182   /* Test lookup of individual templates */
   6183   TEST_RET_ON_FAIL (test_lookup_template (&cls->instance,
   6184                                           &cls->templates[0]));
   6185   /* Make sure it fails correctly for templates that don't exist */
   6186   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   6187       TALER_MERCHANTDB_lookup_template (pg,
   6188                                         cls->instance.instance.id,
   6189                                         "nonexistent_template",
   6190                                         NULL))
   6191   {
   6192     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6193                 "Lookup template failed\n");
   6194     return 1;
   6195   }
   6196   /* Test template update */
   6197   cls->templates[0].template.template_description =
   6198     "This is a test template that has been updated!";
   6199   GNUNET_free (cls->templates[0].template.otp_id);
   6200   cls->templates[0].template.otp_id = GNUNET_strdup ("otp_id");
   6201   {
   6202     /* ensure OTP device exists */
   6203     struct TALER_MERCHANTDB_OtpDeviceDetails td = {
   6204       .otp_description = "my otp",
   6205       .otp_key = "my key",
   6206       .otp_algorithm = 1,
   6207       .otp_ctr = 42
   6208     };
   6209     GNUNET_assert (0 <=
   6210                    TALER_MERCHANTDB_insert_otp (pg,
   6211                                                 cls->instance.instance.id,
   6212                                                 "otp_id",
   6213                                                 &td));
   6214   }
   6215   GNUNET_assert (0 ==
   6216                  json_array_append_new (
   6217                    cls->templates[0].template.template_contract,
   6218                    json_string ("This is a test. 3CH.")));
   6219   TEST_RET_ON_FAIL (test_update_template (&cls->instance,
   6220                                           &cls->templates[0],
   6221                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6222   TEST_RET_ON_FAIL (test_lookup_template (&cls->instance,
   6223                                           &cls->templates[0]));
   6224   TEST_RET_ON_FAIL (test_update_template (&cls->instance,
   6225                                           &cls->templates[1],
   6226                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6227   /* Test collective template lookup */
   6228   TEST_RET_ON_FAIL (test_insert_template (&cls->instance,
   6229                                           &cls->templates[1],
   6230                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6231   TEST_RET_ON_FAIL (test_lookup_templates (&cls->instance,
   6232                                            2,
   6233                                            cls->templates));
   6234 
   6235   /* Test template deletion */
   6236   TEST_RET_ON_FAIL (test_delete_template (&cls->instance,
   6237                                           &cls->templates[1],
   6238                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6239   /* Test double deletion fails */
   6240   TEST_RET_ON_FAIL (test_delete_template (&cls->instance,
   6241                                           &cls->templates[1],
   6242                                           GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6243   TEST_RET_ON_FAIL (test_lookup_templates (&cls->instance,
   6244                                            1,
   6245                                            cls->templates));
   6246   return 0;
   6247 }
   6248 
   6249 
   6250 /**
   6251  * Takes care of template testing.
   6252  *
   6253  * @return 0 on success, 1 otherwise.
   6254  */
   6255 static int
   6256 test_templates (void)
   6257 {
   6258   struct TestTemplates_Closure test_cls;
   6259   int test_result;
   6260 
   6261   memset (&test_cls,
   6262           0,
   6263           sizeof (test_cls));
   6264   pre_test_templates (&test_cls);
   6265   test_result = run_test_templates (&test_cls);
   6266   post_test_templates (&test_cls);
   6267   return test_result;
   6268 }
   6269 
   6270 
   6271 /* *********** Webhooks ********** */
   6272 
   6273 /**
   6274  * A container for data relevant to a webhook.
   6275  */
   6276 struct WebhookData
   6277 {
   6278 
   6279   /**
   6280    * The identifier of the webhook.
   6281    */
   6282   const char *id;
   6283 
   6284   /**
   6285    * The details of the webhook.
   6286    */
   6287   struct TALER_MERCHANTDB_WebhookDetails webhook;
   6288 };
   6289 
   6290 
   6291 /**
   6292  * Creates a webhook for testing with.
   6293  *
   6294  * @param id the id of the webhook.
   6295  * @param webhook the webhook data to fill.
   6296  */
   6297 static void
   6298 make_webhook (const char *id,
   6299               struct WebhookData *webhook)
   6300 {
   6301   webhook->id = id;
   6302   webhook->webhook.event_type = "Paid";
   6303   webhook->webhook.url = "https://exampletest.com";
   6304   webhook->webhook.http_method = "POST";
   6305   webhook->webhook.header_template = "Authorization:XYJAORKJEO";
   6306   webhook->webhook.body_template = "$Amount";
   6307 }
   6308 
   6309 
   6310 /**
   6311  * Compare two webhooks for equality.
   6312  *
   6313  * @param a the first webhook.
   6314  * @param b the second webhook.
   6315  * @return 0 on equality, 1 otherwise.
   6316  */
   6317 static int
   6318 check_webhooks_equal (const struct TALER_MERCHANTDB_WebhookDetails *a,
   6319                       const struct TALER_MERCHANTDB_WebhookDetails *b)
   6320 {
   6321   if ((0 != strcmp (a->event_type,
   6322                     b->event_type)) ||
   6323       (0 != strcmp (a->url,
   6324                     b->url)) ||
   6325       (0 != strcmp (a->http_method,
   6326                     b->http_method)) ||
   6327       (0 != strcmp (a->header_template,
   6328                     b->header_template)) ||
   6329       (0 != strcmp (a->body_template,
   6330                     b->body_template)))
   6331     return 1;
   6332   return 0;
   6333 }
   6334 
   6335 
   6336 /**
   6337  * Tests inserting webhook data into the database.
   6338  *
   6339  * @param instance the instance to insert the webhook for.
   6340  * @param webhook the webhook data to insert.
   6341  * @param expected_result the result we expect the db to return.
   6342  * @return 0 when successful, 1 otherwise.
   6343  */
   6344 static int
   6345 test_insert_webhook (const struct InstanceData *instance,
   6346                      const struct WebhookData *webhook,
   6347                      enum GNUNET_DB_QueryStatus expected_result)
   6348 {
   6349   TEST_COND_RET_ON_FAIL (expected_result ==
   6350                          TALER_MERCHANTDB_insert_webhook (pg,
   6351                                                           instance->instance.id,
   6352                                                           webhook->id,
   6353                                                           &webhook->webhook),
   6354                          "Insert webhook failed\n");
   6355   return 0;
   6356 }
   6357 
   6358 
   6359 /**
   6360  * Tests updating webhook data in the database.
   6361  *
   6362  * @param instance the instance to update the webhook for.
   6363  * @param webhook the webhook data to update.
   6364  * @param expected_result the result we expect the db to return.
   6365  * @return 0 when successful, 1 otherwise.
   6366  */
   6367 static int
   6368 test_update_webhook (const struct InstanceData *instance,
   6369                      const struct WebhookData *webhook,
   6370                      enum GNUNET_DB_QueryStatus expected_result)
   6371 {
   6372   TEST_COND_RET_ON_FAIL (expected_result ==
   6373                          TALER_MERCHANTDB_update_webhook (pg,
   6374                                                           instance->instance.id,
   6375                                                           webhook->id,
   6376                                                           &webhook->webhook),
   6377                          "Update webhook failed\n");
   6378   return 0;
   6379 }
   6380 
   6381 
   6382 /**
   6383  * Tests looking up a webhook from the db.
   6384  *
   6385  * @param instance the instance to query from.
   6386  * @param webhook the webhook to query and compare to.
   6387  * @return 0 when successful, 1 otherwise.
   6388  */
   6389 static int
   6390 test_lookup_webhook (const struct InstanceData *instance,
   6391                      const struct WebhookData *webhook)
   6392 {
   6393   const struct TALER_MERCHANTDB_WebhookDetails *to_cmp = &webhook->webhook;
   6394   struct TALER_MERCHANTDB_WebhookDetails lookup_result;
   6395 
   6396   if (0 > TALER_MERCHANTDB_lookup_webhook (pg,
   6397                                            instance->instance.id,
   6398                                            webhook->id,
   6399                                            &lookup_result))
   6400   {
   6401     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6402                 "Lookup webhook failed\n");
   6403     TALER_MERCHANTDB_webhook_details_free (&lookup_result);
   6404     return 1;
   6405   }
   6406   if (0 != check_webhooks_equal (&lookup_result,
   6407                                  to_cmp))
   6408   {
   6409     GNUNET_break (0);
   6410     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6411                 "Lookup webhook failed: incorrect webhook returned\n");
   6412     TALER_MERCHANTDB_webhook_details_free (&lookup_result);
   6413     return 1;
   6414   }
   6415   TALER_MERCHANTDB_webhook_details_free (&lookup_result);
   6416   return 0;
   6417 }
   6418 
   6419 
   6420 /**
   6421  * Closure for testing webhook lookup
   6422  */
   6423 struct TestLookupWebhooks_Closure
   6424 {
   6425   /**
   6426    * Number of webhook ids to compare to
   6427    */
   6428   unsigned int webhooks_to_cmp_length;
   6429 
   6430   /**
   6431    * Pointer to array of webhook ids
   6432    */
   6433   const struct WebhookData *webhooks_to_cmp;
   6434 
   6435   /**
   6436    * Pointer to array of number of matches for each webhook
   6437    */
   6438   unsigned int *results_matching;
   6439 
   6440   /**
   6441    * Total number of results returned
   6442    */
   6443   unsigned int results_length;
   6444 };
   6445 
   6446 
   6447 /**
   6448  * Function called after calling @e test_lookup_webhooks
   6449  *
   6450  * @param cls a pointer to the lookup closure.
   6451  * @param webhook_id the identifier of the webhook found.
   6452  */
   6453 static void
   6454 lookup_webhooks_cb (void *cls,
   6455                     const char *webhook_id,
   6456                     const char *event_type)
   6457 {
   6458   struct TestLookupWebhooks_Closure *cmp = cls;
   6459   if (NULL == cmp)
   6460     return;
   6461   cmp->results_length += 1;
   6462   for (unsigned int i = 0; cmp->webhooks_to_cmp_length > i; ++i)
   6463   {
   6464     if ((0 == strcmp (cmp->webhooks_to_cmp[i].id,
   6465                       webhook_id)) &&
   6466         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.event_type,
   6467                       event_type)) )
   6468       cmp->results_matching[i] += 1;
   6469   }
   6470 }
   6471 
   6472 
   6473 /**
   6474  * Tests looking up all webhooks for an instance.
   6475  *
   6476  * @param instance the instance to query from.
   6477  * @param webhooks_length the number of webhooks we are expecting.
   6478  * @param webhooks the list of webhooks that we expect to be found.
   6479  * @return 0 when successful, 1 otherwise.
   6480  */
   6481 static int
   6482 test_lookup_webhooks (const struct InstanceData *instance,
   6483                       unsigned int webhooks_length,
   6484                       const struct WebhookData *webhooks)
   6485 {
   6486   unsigned int results_matching[webhooks_length];
   6487   struct TestLookupWebhooks_Closure cls = {
   6488     .webhooks_to_cmp_length = webhooks_length,
   6489     .webhooks_to_cmp = webhooks,
   6490     .results_matching = results_matching,
   6491     .results_length = 0
   6492   };
   6493   memset (results_matching, 0, sizeof (unsigned int) * webhooks_length);
   6494   if (0 > TALER_MERCHANTDB_lookup_webhooks (pg,
   6495                                             instance->instance.id,
   6496                                             &lookup_webhooks_cb,
   6497                                             &cls))
   6498   {
   6499     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6500                 "Lookup webhooks failed\n");
   6501     return 1;
   6502   }
   6503   if (webhooks_length != cls.results_length)
   6504   {
   6505     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6506                 "Lookup webhooks failed: incorrect number of results\n");
   6507     return 1;
   6508   }
   6509   for (unsigned int i = 0; webhooks_length > i; ++i)
   6510   {
   6511     if (1 != cls.results_matching[i])
   6512     {
   6513       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6514                   "Lookup webhooks failed: mismatched data\n");
   6515       return 1;
   6516     }
   6517   }
   6518   return 0;
   6519 }
   6520 
   6521 
   6522 /**
   6523  * Function called after calling @e test_lookup_webhooks
   6524  *
   6525  * @param cls a pointer to the lookup closure.
   6526  * @param webhook_id the identifier of the webhook found.
   6527  */
   6528 static void
   6529 lookup_webhook_by_event_cb (void *cls,
   6530                             uint64_t webhook_serial,
   6531                             const char *event_type,
   6532                             const char *url,
   6533                             const char *http_method,
   6534                             const char *header_template,
   6535                             const char *body_template)
   6536 {
   6537   struct TestLookupWebhooks_Closure *cmp = cls;
   6538   if (NULL == cmp)
   6539     return;
   6540   cmp->results_length += 1;
   6541   for (unsigned int i = 0; cmp->webhooks_to_cmp_length > i; ++i)
   6542   {
   6543     if ((0 == strcmp (cmp->webhooks_to_cmp[i].webhook.event_type,
   6544                       event_type)) &&
   6545         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.url,
   6546                       url)) &&
   6547         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.http_method,
   6548                       http_method)) &&
   6549         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.header_template,
   6550                       header_template)) &&
   6551         (0 == strcmp (cmp->webhooks_to_cmp[i].webhook.body_template,
   6552                       body_template)) )
   6553       cmp->results_matching[i] += 1;
   6554   }
   6555 }
   6556 
   6557 
   6558 /**
   6559  * Tests looking up webhooks by event for an instance.
   6560  *
   6561  * @param instance the instance to query from.
   6562  * @param webhooks_length the number of webhooks we are expecting.
   6563  * @param webhooks the list of webhooks that we expect to be found.
   6564  * @return 0 when successful, 1 otherwise.
   6565  */
   6566 static int
   6567 test_lookup_webhook_by_event (const struct InstanceData *instance,
   6568                               unsigned int webhooks_length,
   6569                               const struct WebhookData *webhooks)
   6570 {
   6571   unsigned int results_matching[webhooks_length];
   6572   struct TestLookupWebhooks_Closure cls = {
   6573     .webhooks_to_cmp_length = webhooks_length,
   6574     .webhooks_to_cmp = webhooks,
   6575     .results_matching = results_matching,
   6576     .results_length = 0
   6577   };
   6578   memset (results_matching, 0, sizeof (unsigned int) * webhooks_length);
   6579   if (0 > TALER_MERCHANTDB_lookup_webhook_by_event (pg,
   6580                                                     instance->instance.id,
   6581                                                     webhooks->webhook.event_type,
   6582                                                     &lookup_webhook_by_event_cb,
   6583                                                     &cls))
   6584   {
   6585     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6586                 "Lookup webhooks by event failed\n");
   6587     return 1;
   6588   }
   6589 
   6590   if (webhooks_length != cls.results_length)
   6591   {
   6592     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6593                 "Lookup webhooks by event failed: incorrect number of results\n");
   6594     return 1;
   6595   }
   6596   for (unsigned int i = 0; webhooks_length > i; ++i)
   6597   {
   6598     if (1 != cls.results_matching[i])
   6599     {
   6600       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6601                   "Lookup webhooks by event failed: mismatched data\n");
   6602       return 1;
   6603     }
   6604   }
   6605   return 0;
   6606 }
   6607 
   6608 
   6609 /**
   6610  * Tests deleting a webhook.
   6611  *
   6612  * @param instance the instance to delete the webhook from.
   6613  * @param webhook the webhook that should be deleted.
   6614  * @param expected_result the result that we expect the DB to return.
   6615  * @return 0 when successful, 1 otherwise.
   6616  */
   6617 static int
   6618 test_delete_webhook (const struct InstanceData *instance,
   6619                      const struct WebhookData *webhook,
   6620                      enum GNUNET_DB_QueryStatus expected_result)
   6621 {
   6622   TEST_COND_RET_ON_FAIL (expected_result ==
   6623                          TALER_MERCHANTDB_delete_webhook (pg,
   6624                                                           instance->instance.id,
   6625                                                           webhook->id),
   6626                          "Delete webhook failed\n");
   6627   return 0;
   6628 }
   6629 
   6630 
   6631 /**
   6632  * Closure for webhook tests.
   6633  */
   6634 struct TestWebhooks_Closure
   6635 {
   6636   /**
   6637    * The instance to use for this test.
   6638    */
   6639   struct InstanceData instance;
   6640 
   6641   /**
   6642    * The array of webhooks.
   6643    */
   6644   struct WebhookData webhooks[3];
   6645 };
   6646 
   6647 
   6648 /**
   6649  * Sets up the data structures used in the webhook tests.
   6650  *
   6651  * @param cls the closure to fill with test data.
   6652  */
   6653 static void
   6654 pre_test_webhooks (struct TestWebhooks_Closure *cls)
   6655 {
   6656   /* Instance */
   6657   make_instance ("test_inst_webhooks",
   6658                  &cls->instance);
   6659 
   6660   /* Webhooks */
   6661   make_webhook ("test_webhooks_wb_0",
   6662                 &cls->webhooks[0]);
   6663 
   6664   make_webhook ("test_webhooks_wb_1",
   6665                 &cls->webhooks[1]);
   6666   cls->webhooks[1].webhook.event_type = "Test paid";
   6667   cls->webhooks[1].webhook.url = "https://example.com";
   6668   cls->webhooks[1].webhook.http_method = "POST";
   6669   cls->webhooks[1].webhook.header_template = "Authorization:1XYJAOR493O";
   6670   cls->webhooks[1].webhook.body_template = "$Amount";
   6671 
   6672   make_webhook ("test_webhooks_wb_2",
   6673                 &cls->webhooks[2]);
   6674   cls->webhooks[2].webhook.event_type = "Test paid";
   6675   cls->webhooks[2].webhook.url = "https://examplerefund.com";
   6676   cls->webhooks[2].webhook.http_method = "POST";
   6677   cls->webhooks[2].webhook.header_template = "Authorization:XY6ORK52JEO";
   6678   cls->webhooks[2].webhook.body_template = "$Amount";
   6679 }
   6680 
   6681 
   6682 /**
   6683  * Handles all teardown after testing.
   6684  *
   6685  * @param cls the closure containing memory to be freed.
   6686  */
   6687 static void
   6688 post_test_webhooks (struct TestWebhooks_Closure *cls)
   6689 {
   6690   free_instance_data (&cls->instance);
   6691 }
   6692 
   6693 
   6694 /**
   6695  * Runs the tests for webhooks.
   6696  *
   6697  * @param cls the container of the test data.
   6698  * @return 0 on success, 1 otherwise.
   6699  */
   6700 static int
   6701 run_test_webhooks (struct TestWebhooks_Closure *cls)
   6702 {
   6703 
   6704   /* Test that insert without an instance fails */
   6705   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6706                                          &cls->webhooks[0],
   6707                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6708   /* Insert the instance */
   6709   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   6710                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6711   /* Test inserting a webhook */
   6712   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6713                                          &cls->webhooks[0],
   6714                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6715   /* Test that double insert fails */
   6716   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6717                                          &cls->webhooks[0],
   6718                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6719   /* Test lookup of individual webhooks */
   6720   TEST_RET_ON_FAIL (test_lookup_webhook (&cls->instance,
   6721                                          &cls->webhooks[0]));
   6722   /* Make sure it fails correctly for webhooks that don't exist */
   6723   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
   6724       TALER_MERCHANTDB_lookup_webhook (pg,
   6725                                        cls->instance.instance.id,
   6726                                        "nonexistent_webhook",
   6727                                        NULL))
   6728   {
   6729     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   6730                 "Lookup webhook failed\n");
   6731     return 1;
   6732   }
   6733   /* Test webhook update */
   6734   cls->webhooks[0].webhook.event_type =
   6735     "Test paid";
   6736   cls->webhooks[0].webhook.url =
   6737     "example.com";
   6738   cls->webhooks[0].webhook.http_method =
   6739     "POST";
   6740   cls->webhooks[0].webhook.header_template =
   6741     "Authorization:WEKFOEKEXZ";
   6742   cls->webhooks[0].webhook.body_template =
   6743     "$Amount";
   6744   TEST_RET_ON_FAIL (test_update_webhook (&cls->instance,
   6745                                          &cls->webhooks[0],
   6746                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6747 
   6748   TEST_RET_ON_FAIL (test_lookup_webhook (&cls->instance,
   6749                                          &cls->webhooks[0]));
   6750   TEST_RET_ON_FAIL (test_update_webhook (&cls->instance,
   6751                                          &cls->webhooks[1],
   6752                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6753   /* Test collective webhook lookup */
   6754   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6755                                          &cls->webhooks[1],
   6756                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6757   TEST_RET_ON_FAIL (test_lookup_webhooks (&cls->instance,
   6758                                           2,
   6759                                           cls->webhooks));
   6760   TEST_RET_ON_FAIL (test_lookup_webhook_by_event (&cls->instance,
   6761                                                   2,
   6762                                                   cls->webhooks));
   6763   TEST_RET_ON_FAIL (test_insert_webhook (&cls->instance,
   6764                                          &cls->webhooks[2],
   6765                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6766 
   6767   /* Test webhook deletion */
   6768   TEST_RET_ON_FAIL (test_delete_webhook (&cls->instance,
   6769                                          &cls->webhooks[1],
   6770                                          GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   6771   /* Test double deletion fails */
   6772   TEST_RET_ON_FAIL (test_delete_webhook (&cls->instance,
   6773                                          &cls->webhooks[1],
   6774                                          GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   6775   cls->webhooks[1] = cls->webhooks[2];
   6776   TEST_RET_ON_FAIL (test_lookup_webhooks (&cls->instance,
   6777                                           2,
   6778                                           cls->webhooks));
   6779   TEST_RET_ON_FAIL (test_lookup_webhook_by_event (&cls->instance,
   6780                                                   2,
   6781                                                   cls->webhooks));
   6782   return 0;
   6783 }
   6784 
   6785 
   6786 /**
   6787  * Takes care of webhook testing.
   6788  *
   6789  * @return 0 on success, 1 otherwise.
   6790  */
   6791 static int
   6792 test_webhooks (void)
   6793 {
   6794   struct TestWebhooks_Closure test_cls;
   6795   int test_result;
   6796 
   6797   pre_test_webhooks (&test_cls);
   6798   test_result = run_test_webhooks (&test_cls);
   6799   post_test_webhooks (&test_cls);
   6800   return test_result;
   6801 }
   6802 
   6803 
   6804 /* *********** Pending Webhooks ********** */
   6805 
   6806 /**
   6807  * A container for data relevant to a pending webhook.
   6808  */
   6809 struct PendingWebhookData
   6810 {
   6811   /**
   6812    * Reference to the configured webhook template.
   6813    */
   6814   uint64_t webhook_serial;
   6815 
   6816   /**
   6817    * The details of the pending webhook.
   6818    */
   6819   struct TALER_MERCHANTDB_PendingWebhookDetails pwebhook;
   6820 };
   6821 
   6822 
   6823 /**
   6824  * Creates a pending webhook for testing with.
   6825  *
   6826  * @param serial reference to the configured webhook template.
   6827  * @param pwebhook the pending webhook data to fill.
   6828  */
   6829 static void
   6830 make_pending_webhook (uint64_t webhook_serial,
   6831                       struct PendingWebhookData *pwebhook)
   6832 {
   6833   pwebhook->webhook_serial = webhook_serial;
   6834   pwebhook->pwebhook.next_attempt = GNUNET_TIME_UNIT_ZERO_ABS;
   6835   pwebhook->pwebhook.retries = 0;
   6836   pwebhook->pwebhook.url = "https://exampletest.com";
   6837   pwebhook->pwebhook.http_method = "POST";
   6838   pwebhook->pwebhook.header = "Authorization:XYJAORKJEO";
   6839   pwebhook->pwebhook.body = "$Amount";
   6840 }
   6841 
   6842 
   6843 /**
   6844  * Tests inserting pending webhook data into the database.
   6845  *
   6846  * @param instance the instance to insert the pending webhook for.
   6847  * @param pending webhook the pending webhook data to insert.
   6848  * @param expected_result the result we expect the db to return.
   6849  * @return 0 when successful, 1 otherwise.
   6850  */
   6851 static int
   6852 test_insert_pending_webhook (const struct InstanceData *instance,
   6853                              struct PendingWebhookData *pwebhook,
   6854                              enum GNUNET_DB_QueryStatus expected_result)
   6855 {
   6856 
   6857   TEST_COND_RET_ON_FAIL (expected_result ==
   6858                          TALER_MERCHANTDB_insert_pending_webhook (pg,
   6859                                                                   instance->instance.id,
   6860                                                                   pwebhook->
   6861                                                                   webhook_serial,
   6862                                                                   pwebhook->pwebhook.url,
   6863                                                                   pwebhook->pwebhook.
   6864                                                                   http_method,
   6865                                                                   pwebhook->pwebhook.
   6866                                                                   header,
   6867                                                                   pwebhook->pwebhook.body
   6868                                                                   ),
   6869                          "Insert pending webhook failed\n");
   6870   return 0;
   6871 }
   6872 
   6873 
   6874 /**
   6875  * Tests updating pending webhook data in the database.
   6876  *
   6877  * @param instance the instance to update the pending webhook for.
   6878  * @param pending webhook the pending webhook data to update.
   6879  * @param expected_result the result we expect the db to return.
   6880  * @return 0 when successful, 1 otherwise.
   6881  */
   6882 static int
   6883 test_update_pending_webhook (const struct InstanceData *instance,
   6884                              struct PendingWebhookData *pwebhook,
   6885                              enum GNUNET_DB_QueryStatus expected_result)
   6886 {
   6887   pwebhook->pwebhook.next_attempt = GNUNET_TIME_relative_to_absolute (
   6888     GNUNET_TIME_UNIT_HOURS);
   6889   pwebhook->pwebhook.retries++;
   6890   TEST_COND_RET_ON_FAIL (expected_result ==
   6891                          TALER_MERCHANTDB_update_pending_webhook (pg,
   6892                                                                   pwebhook->
   6893                                                                   webhook_serial,
   6894                                                                   pwebhook->pwebhook.
   6895                                                                   next_attempt),
   6896                          "Update pending webhook failed\n");
   6897   return 0;
   6898 }
   6899 
   6900 
   6901 /**
   6902  * Container for information for looking up the row number of a deposit.
   6903  */
   6904 struct LookupPendingWebhookSerial_Closure
   6905 {
   6906   /**
   6907    * The pending webhook we're looking for.
   6908    */
   6909   const struct PendingWebhookData *pwebhook;
   6910 
   6911   /**
   6912    * The serial found.
   6913    */
   6914   uint64_t webhook_pending_serial;
   6915 };
   6916 
   6917 
   6918 /**
   6919  * Function called after calling @e test_lookup_all_webhook,
   6920  * test_lookup_future_webhook and test_lookup_pending_webhook
   6921  *
   6922  * @param cls a pointer to the lookup closure.
   6923  * @param webhook_serial reference to the configured webhook template.
   6924  */
   6925 static void
   6926 get_pending_serial_cb (void *cls,
   6927                        uint64_t webhook_pending_serial,
   6928                        struct GNUNET_TIME_Absolute next_attempt,
   6929                        uint32_t retries,
   6930                        const char *url,
   6931                        const char *http_method,
   6932                        const char *header,
   6933                        const char *body)
   6934 {
   6935   struct LookupPendingWebhookSerial_Closure *lpw = cls;
   6936 
   6937   if ((0 == strcmp (lpw->pwebhook->pwebhook.url,
   6938                     url)) &&
   6939       (0 == strcmp (lpw->pwebhook->pwebhook.http_method,
   6940                     http_method)) &&
   6941       (0 == strcmp (lpw->pwebhook->pwebhook.header,
   6942                     header)) &&
   6943       (0 == strcmp (lpw->pwebhook->pwebhook.body,
   6944                     body)) )
   6945   {
   6946     lpw->webhook_pending_serial = webhook_pending_serial;
   6947   }
   6948   /* else
   6949     {
   6950       fprintf(stdout, "next_attempt: %lu vs %lu\n", lpw->pwebhook->pwebhook.next_attempt.abs_value_us, next_attempt.abs_value_us);
   6951       fprintf(stdout, "retries: %d vs %d\n", lpw->pwebhook->pwebhook.retries, retries);
   6952       fprintf(stdout, "url: %s vs %s\n", lpw->pwebhook->pwebhook.url, url);
   6953       fprintf(stdout, "http_method: %s vs %s\n", lpw->pwebhook->pwebhook.http_method, http_method);
   6954       fprintf(stdout, "header: %s vs %s\n", lpw->pwebhook->pwebhook.header, header);
   6955       fprintf(stdout, "body: %s vs %s\n", lpw->pwebhook->pwebhook.body, body);
   6956       }*/
   6957 }
   6958 
   6959 
   6960 /**
   6961  * Convenience function to retrieve the row number of a webhook pending in the database.
   6962  *
   6963  * @param instance the instance to get webhook pending(wp) from.
   6964  * @param webhook pending the wp to lookup the serial for.
   6965  * @return the row number of the deposit.
   6966  */
   6967 static uint64_t
   6968 get_pending_serial (const struct InstanceData *instance,
   6969                     const struct PendingWebhookData *pwebhook)
   6970 {
   6971   struct LookupPendingWebhookSerial_Closure lpw = {
   6972     .pwebhook = pwebhook,
   6973     .webhook_pending_serial = 0
   6974   };
   6975 
   6976   GNUNET_assert (0 <
   6977                  TALER_MERCHANTDB_lookup_all_webhooks (pg,
   6978                                                        instance->instance.id,
   6979                                                        0,
   6980                                                        INT_MAX,
   6981                                                        &get_pending_serial_cb,
   6982                                                        &lpw));
   6983   GNUNET_assert (0 != lpw.webhook_pending_serial);
   6984 
   6985   return lpw.webhook_pending_serial;
   6986 }
   6987 
   6988 
   6989 /**
   6990  * Closure for testing pending webhook lookup
   6991  */
   6992 struct TestLookupPendingWebhooks_Closure
   6993 {
   6994   /**
   6995    * Number of webhook serial to compare to
   6996    */
   6997   unsigned int webhooks_to_cmp_length;
   6998 
   6999   /**
   7000    * Pointer to array of webhook serials
   7001    */
   7002   const struct PendingWebhookData *webhooks_to_cmp;
   7003 
   7004   /**
   7005    * Pointer to array of number of matches for each pending webhook
   7006    */
   7007   unsigned int *results_matching;
   7008 
   7009   /**
   7010    * Total number of results returned
   7011    */
   7012   unsigned int results_length;
   7013 };
   7014 
   7015 
   7016 /**
   7017  * Function called after calling @e test_lookup_all_webhook,
   7018  * test_lookup_future_webhook and test_lookup_pending_webhook
   7019  *
   7020  * @param cls a pointer to the lookup closure.
   7021  * @param webhook_serial reference to the configured webhook template.
   7022  */
   7023 static void
   7024 lookup_pending_webhooks_cb (void *cls,
   7025                             uint64_t webhook_pending_serial,
   7026                             struct GNUNET_TIME_Absolute next_attempt,
   7027                             uint32_t retries,
   7028                             const char *url,
   7029                             const char *http_method,
   7030                             const char *header,
   7031                             const char *body)
   7032 {
   7033   struct TestLookupPendingWebhooks_Closure *cmp = cls;
   7034 
   7035   cmp->results_length++;
   7036   for (unsigned int i = 0; cmp->webhooks_to_cmp_length > i; ++i)
   7037   {
   7038     if ((0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.url,
   7039                       url)) &&
   7040         (0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.http_method,
   7041                       http_method)) &&
   7042         (0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.header,
   7043                       header)) &&
   7044         (0 == strcmp (cmp->webhooks_to_cmp[i].pwebhook.body,
   7045                       body)) )
   7046     {
   7047       cmp->results_matching[i]++;
   7048     }
   7049   }
   7050 }
   7051 
   7052 
   7053 /**
   7054  * Tests looking up the pending webhook for an instance.
   7055  *
   7056  * @param instance the instance to query from.
   7057  * @param pwebhooks_length the number of pending webhook we are expecting.
   7058  * @param pwebhooks the list of pending webhooks that we expect to be found.
   7059  * @return 0 when successful, 1 otherwise.
   7060  */
   7061 static int
   7062 test_lookup_pending_webhooks (const struct InstanceData *instance,
   7063                               unsigned int pwebhooks_length,
   7064                               const struct PendingWebhookData *pwebhooks)
   7065 {
   7066   unsigned int results_matching[pwebhooks_length];
   7067   struct TestLookupPendingWebhooks_Closure cls = {
   7068     .webhooks_to_cmp_length = pwebhooks_length,
   7069     .webhooks_to_cmp = pwebhooks,
   7070     .results_matching = results_matching,
   7071     .results_length = 0
   7072   };
   7073 
   7074   memset (results_matching, 0, sizeof (results_matching));
   7075   if (0 > TALER_MERCHANTDB_lookup_pending_webhooks (pg,
   7076                                                     &lookup_pending_webhooks_cb,
   7077                                                     &cls))
   7078   {
   7079     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7080                 "Lookup pending webhook failed\n");
   7081     return 1;
   7082   }
   7083   if (pwebhooks_length != cls.results_length)
   7084   {
   7085     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7086                 "Lookup pending webhook failed: incorrect number of results\n");
   7087     return 1;
   7088   }
   7089   for (unsigned int i = 0; i < pwebhooks_length; i++)
   7090   {
   7091     if (1 != cls.results_matching[i])
   7092     {
   7093       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7094                   "Lookup pending webhook failed: mismatched data\n");
   7095       return 1;
   7096     }
   7097   }
   7098   return 0;
   7099 }
   7100 
   7101 
   7102 /**
   7103  * Tests looking up the future webhook to send for an instance.
   7104  *
   7105  * @param instance the instance to query from.
   7106  * @param pwebhooks_length the number of pending webhook we are expecting.
   7107  * @param pwebhooks the list of pending webhooks that we expect to be found.
   7108  * @return 0 when successful, 1 otherwise.
   7109  */
   7110 static int
   7111 test_lookup_future_webhook (const struct InstanceData *instance,
   7112                             unsigned int pwebhooks_length,
   7113                             const struct PendingWebhookData *pwebhooks)
   7114 {
   7115   unsigned int results_matching[pwebhooks_length];
   7116   struct TestLookupPendingWebhooks_Closure cls = {
   7117     .webhooks_to_cmp_length = pwebhooks_length,
   7118     .webhooks_to_cmp = pwebhooks,
   7119     .results_matching = results_matching,
   7120     .results_length = 0
   7121   };
   7122 
   7123   memset (results_matching, 0, sizeof (results_matching));
   7124   if (0 > TALER_MERCHANTDB_lookup_future_webhook (pg,
   7125                                                   &lookup_pending_webhooks_cb,
   7126                                                   &cls))
   7127   {
   7128     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7129                 "Lookup future webhook failed\n");
   7130     return 1;
   7131   }
   7132   if (pwebhooks_length != cls.results_length)
   7133   {
   7134     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7135                 "Lookup future webhook failed: incorrect number of results\n");
   7136     return 1;
   7137   }
   7138   for (unsigned int i = 0; pwebhooks_length > i; ++i)
   7139   {
   7140     if (1 != cls.results_matching[i])
   7141     {
   7142       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7143                   "Lookup future webhook failed: mismatched data\n");
   7144       return 1;
   7145     }
   7146   }
   7147   return 0;
   7148 }
   7149 
   7150 
   7151 /**
   7152  * Tests looking up all the pending webhook for an instance.
   7153  *
   7154  * @param instance the instance to query from.
   7155  * @param pwebhooks_length the number of pending webhook we are expecting.
   7156  * @param pwebhooks the list of pending webhooks that we expect to be found.
   7157  * @return 0 when successful, 1 otherwise.
   7158  */
   7159 static int
   7160 test_lookup_all_webhooks (const struct InstanceData *instance,
   7161                           unsigned int pwebhooks_length,
   7162                           const struct PendingWebhookData *pwebhooks)
   7163 {
   7164   uint64_t max_results = 2;
   7165   uint64_t min_row = 0;
   7166   unsigned int results_matching[GNUNET_NZL (pwebhooks_length)];
   7167   struct TestLookupPendingWebhooks_Closure cls = {
   7168     .webhooks_to_cmp_length = pwebhooks_length,
   7169     .webhooks_to_cmp = pwebhooks,
   7170     .results_matching = results_matching,
   7171     .results_length = 0
   7172   };
   7173 
   7174   memset (results_matching,
   7175           0,
   7176           sizeof (results_matching));
   7177   if (0 > TALER_MERCHANTDB_lookup_all_webhooks (pg,
   7178                                                 instance->instance.id,
   7179                                                 min_row,
   7180                                                 max_results,
   7181                                                 &lookup_pending_webhooks_cb,
   7182                                                 &cls))
   7183   {
   7184     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7185                 "Lookup all webhooks failed\n");
   7186     return 1;
   7187   }
   7188   if (pwebhooks_length != cls.results_length)
   7189   {
   7190     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7191                 "Lookup all webhooks failed: incorrect number of results\n");
   7192     return 1;
   7193   }
   7194   for (unsigned int i = 0; pwebhooks_length > i; ++i)
   7195   {
   7196     if (1 != cls.results_matching[i])
   7197     {
   7198       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7199                   "Lookup all webhooks failed: mismatched data\n");
   7200       return 1;
   7201     }
   7202   }
   7203   return 0;
   7204 }
   7205 
   7206 
   7207 /**
   7208  * Tests deleting a pending webhook.
   7209  *
   7210  * @param instance the instance to delete the pending webhook from.
   7211  * @param pwebhook the pending webhook that should be deleted.
   7212  * @param expected_result the result that we expect the DB to return.
   7213  * @return 0 when successful, 1 otherwise.
   7214  */
   7215 static int
   7216 test_delete_pending_webhook (uint64_t webhooks_pending_serial,
   7217                              enum GNUNET_DB_QueryStatus expected_result)
   7218 {
   7219 
   7220   TEST_COND_RET_ON_FAIL (expected_result ==
   7221                          TALER_MERCHANTDB_delete_pending_webhook (pg,
   7222                                                                   webhooks_pending_serial),
   7223                          "Delete webhook failed\n");
   7224   return 0;
   7225 }
   7226 
   7227 
   7228 /**
   7229  * Closure for pending webhook tests.
   7230  */
   7231 struct TestPendingWebhooks_Closure
   7232 {
   7233   /**
   7234    * The instance to use for this test.
   7235    */
   7236   struct InstanceData instance;
   7237 
   7238   /**
   7239    * The array of pending webhooks.
   7240    */
   7241   struct PendingWebhookData pwebhooks[2];
   7242 };
   7243 
   7244 
   7245 /**
   7246  * Sets up the data structures used in the pending webhook tests.
   7247  *
   7248  * @param cls the closure to fill with test data.
   7249  */
   7250 static void
   7251 pre_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls)
   7252 {
   7253   /* Instance */
   7254   make_instance ("test_inst_pending_webhooks",
   7255                  &cls->instance);
   7256 
   7257   /* Webhooks */
   7258   make_pending_webhook (1,
   7259                         &cls->pwebhooks[0]);
   7260 
   7261   make_pending_webhook (4,
   7262                         &cls->pwebhooks[1]);
   7263   cls->pwebhooks[1].pwebhook.url = "https://test.com";
   7264   cls->pwebhooks[1].pwebhook.http_method = "POST";
   7265   cls->pwebhooks[1].pwebhook.header = "Authorization:XYJAO5R06EO";
   7266   cls->pwebhooks[1].pwebhook.body = "$Amount";
   7267 }
   7268 
   7269 
   7270 /**
   7271  * Handles all teardown after testing.
   7272  *
   7273  * @param cls the closure containing memory to be freed.
   7274  */
   7275 static void
   7276 post_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls)
   7277 {
   7278   free_instance_data (&cls->instance);
   7279 }
   7280 
   7281 
   7282 /**
   7283  * Runs the tests for pending webhooks.
   7284  *
   7285  * @param cls the container of the test data.
   7286  * @return 0 on success, 1 otherwise.
   7287  */
   7288 static int
   7289 run_test_pending_webhooks (struct TestPendingWebhooks_Closure *cls)
   7290 {
   7291   uint64_t webhook_pending_serial0;
   7292   uint64_t webhook_pending_serial1;
   7293 
   7294   /* Test that insert without an instance fails */
   7295   TEST_RET_ON_FAIL (test_insert_pending_webhook (&cls->instance,
   7296                                                  &cls->pwebhooks[0],
   7297                                                  GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   7298 
   7299   /* Insert the instance */
   7300   TEST_RET_ON_FAIL (test_insert_instance (&cls->instance,
   7301                                           GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7302 
   7303   /* Test inserting a pending webhook */
   7304   TEST_RET_ON_FAIL (test_insert_pending_webhook (&cls->instance,
   7305                                                  &cls->pwebhooks[0],
   7306                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7307   TEST_RET_ON_FAIL (test_insert_pending_webhook (&cls->instance,
   7308                                                  &cls->pwebhooks[1],
   7309                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7310   /* Test collective pending webhook lookup */
   7311   TEST_RET_ON_FAIL (test_lookup_pending_webhooks (&cls->instance,
   7312                                                   2,
   7313                                                   cls->pwebhooks));
   7314   /* Test pending webhook update */
   7315   TEST_RET_ON_FAIL (test_update_pending_webhook (&cls->instance,
   7316                                                  &cls->pwebhooks[0],
   7317                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7318   TEST_RET_ON_FAIL (test_lookup_future_webhook (&cls->instance,
   7319                                                 1,
   7320                                                 &cls->pwebhooks[1]));
   7321   TEST_RET_ON_FAIL (test_update_pending_webhook (&cls->instance,
   7322                                                  &cls->pwebhooks[1],
   7323                                                  GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   7324   // ???
   7325   TEST_RET_ON_FAIL (test_lookup_all_webhooks (&cls->instance,
   7326                                               2,
   7327                                               cls->pwebhooks));
   7328 
   7329   webhook_pending_serial0 = get_pending_serial (&cls->instance,
   7330                                                 &cls->pwebhooks[0]);
   7331   webhook_pending_serial1 = get_pending_serial (&cls->instance,
   7332                                                 &cls->pwebhooks[1]);
   7333 
   7334   /* Test webhook deletion */
   7335   TEST_RET_ON_FAIL (test_delete_pending_webhook (webhook_pending_serial1,
   7336                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7337   /* Test double deletion fails */
   7338   TEST_RET_ON_FAIL (test_delete_pending_webhook (webhook_pending_serial1,
   7339                                                  GNUNET_DB_STATUS_SUCCESS_NO_RESULTS));
   7340   TEST_RET_ON_FAIL (test_delete_pending_webhook (webhook_pending_serial0,
   7341                                                  GNUNET_DB_STATUS_SUCCESS_ONE_RESULT));
   7342   TEST_RET_ON_FAIL (test_lookup_all_webhooks (&cls->instance,
   7343                                               0,
   7344                                               NULL));
   7345   return 0;
   7346 }
   7347 
   7348 
   7349 /**
   7350  * Takes care of pending webhook testing.
   7351  *
   7352  * @return 0 on success, 1 otherwise.
   7353  */
   7354 static int
   7355 test_pending_webhooks (void)
   7356 {
   7357   struct TestPendingWebhooks_Closure test_cls;
   7358   int test_result;
   7359 
   7360   pre_test_pending_webhooks (&test_cls);
   7361   test_result = run_test_pending_webhooks (&test_cls);
   7362   post_test_pending_webhooks (&test_cls);
   7363   return test_result;
   7364 }
   7365 
   7366 
   7367 /**
   7368  * Function that runs all tests.
   7369  *
   7370  * @return 0 on success, 1 otherwise.
   7371  */
   7372 static int
   7373 run_tests (void)
   7374 {
   7375   TEST_RET_ON_FAIL (test_instances ());
   7376   TEST_RET_ON_FAIL (test_products ());
   7377   TEST_RET_ON_FAIL (test_orders ());
   7378   TEST_RET_ON_FAIL (test_deposits ());
   7379   TEST_RET_ON_FAIL (test_transfers ());
   7380   TEST_RET_ON_FAIL (test_refunds ());
   7381   TEST_RET_ON_FAIL (test_lookup_orders_all_filters ());
   7382   TEST_RET_ON_FAIL (test_kyc ());
   7383   TEST_RET_ON_FAIL (test_templates ());
   7384   TEST_RET_ON_FAIL (test_webhooks ());
   7385   TEST_RET_ON_FAIL (test_pending_webhooks ());
   7386   return 0;
   7387 }
   7388 
   7389 
   7390 /**
   7391  * Main function that will be run by the scheduler.
   7392  *
   7393  * @param cls closure with config
   7394  */
   7395 static void
   7396 run (void *cls)
   7397 {
   7398   struct GNUNET_CONFIGURATION_Handle *cfg = cls;
   7399 
   7400   /* Drop the tables to cleanup anything that might cause issues */
   7401   (void) TALER_MERCHANTDB_drop_tables (cfg);
   7402   if (GNUNET_OK !=
   7403       TALER_MERCHANTDB_create_tables (cfg))
   7404   {
   7405     result = 77;
   7406     return;
   7407   }
   7408   if (NULL == (pg = TALER_MERCHANTDB_connect (cfg)))
   7409   {
   7410     result = 77;
   7411     return;
   7412   }
   7413   /* Run the preflight */
   7414   TALER_MERCHANTDB_preflight (pg);
   7415 
   7416   result = run_tests ();
   7417   /* if (0 == result) result = run_test_templates (); */
   7418 
   7419   TALER_MERCHANTDB_disconnect (pg);
   7420   pg = NULL;
   7421   if (0 != result)
   7422     return;
   7423   if (GNUNET_OK !=
   7424       TALER_MERCHANTDB_drop_tables (cfg))
   7425   {
   7426     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   7427                 "Dropping tables failed\n");
   7428     result = 1;
   7429     return;
   7430   }
   7431 }
   7432 
   7433 
   7434 /**
   7435  * Entry point for the tests.
   7436  */
   7437 int
   7438 main (int argc,
   7439       char *const argv[])
   7440 {
   7441   struct GNUNET_CONFIGURATION_Handle *cfg;
   7442 
   7443   GNUNET_log_setup (argv[0],
   7444                     "DEBUG",
   7445                     NULL);
   7446   cfg = GNUNET_CONFIGURATION_create (TALER_MERCHANT_project_data ());
   7447   if (GNUNET_OK !=
   7448       GNUNET_CONFIGURATION_parse (cfg,
   7449                                   "test-merchantdb-postgres.conf"))
   7450   {
   7451     GNUNET_break (0);
   7452     return 2;
   7453   }
   7454   GNUNET_SCHEDULER_run (&run,
   7455                         cfg);
   7456   GNUNET_CONFIGURATION_destroy (cfg);
   7457   return result;
   7458 }
   7459 
   7460 
   7461 /* end of test_merchantdb.c */