merchant

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

test_merchantdb.c (260464B)


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