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

Generated by: LCOV version 2.0-1