merchant

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

test_merchantdb.c (243434B)


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