LCOV - code coverage report
Current view: top level - backenddb - test_merchantdb.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 24 1869 1.3 %
Date: 2025-08-28 06:06:54 Functions: 2 150 1.3 %

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

Generated by: LCOV version 1.16