LCOV - code coverage report
Current view: top level - backenddb - test_merchantdb.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 87.5 % 1872 1638
Test Date: 2025-12-02 20:17:27 Functions: 100.0 % 150 150

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

Generated by: LCOV version 2.0-1