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

Generated by: LCOV version 1.16