merchant

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

test_merchantdb.c (245288B)


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