merchant

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

test_merchantdb.c (260186B)


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