summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2020-05-26 18:25:52 -0400
committerJonathan Buchanan <jonathan.russ.buchanan@gmail.com>2020-05-26 18:25:52 -0400
commite2333817a6767933608c6d3bd3216a9fcd3033e7 (patch)
tree445308b732a8716f460cb9921d7b4dbe99f6367c
parent35a94ff2407b5bfd0be8bed56b284f1727e0ef67 (diff)
downloadmerchant-e2333817a6767933608c6d3bd3216a9fcd3033e7.tar.gz
merchant-e2333817a6767933608c6d3bd3216a9fcd3033e7.tar.bz2
merchant-e2333817a6767933608c6d3bd3216a9fcd3033e7.zip
wrote tests for deposits in the db api
-rw-r--r--src/backenddb/Makefile.am1
-rw-r--r--src/backenddb/test_merchantdb.c480
2 files changed, 479 insertions, 2 deletions
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 3edc4509..bec76cc7 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -54,6 +54,7 @@ libtaler_plugin_merchantdb_postgres_la_LDFLAGS = \
-ltalerpq \
-ltalerutil \
-ltalerjson \
+ -ltalermhd \
-lpq \
-lgnunetutil $(XLIB)
diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c
index d45089a0..6ed0b217 100644
--- a/src/backenddb/test_merchantdb.c
+++ b/src/backenddb/test_merchantdb.c
@@ -22,6 +22,7 @@
#include "platform.h"
#include <taler/taler_util.h>
#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
#include "taler_merchantdb_lib.h"
@@ -375,7 +376,8 @@ run_test_instances (struct TestInstances_Closure *cls)
instances));
/* Test account creation */
- TEST_RET_ON_FAIL (test_insert_account ("test_inst", &cls->accounts[0]));
+ TEST_RET_ON_FAIL (test_insert_account (cls->is.id,
+ &cls->accounts[0]));
/* Test accounts from instance lookup */
instances[0].accounts_length = 1;
@@ -399,9 +401,36 @@ run_test_instances (struct TestInstances_Closure *cls)
/* Test multiple accounts */
+ /* Test lookup account */
+ uint64_t account_serial;
+ if (1 != plugin->lookup_account (plugin->cls,
+ cls->is.id,
+ cls->accounts[0].payto_uri,
+ &account_serial))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup account failed\n");
+ return 1;
+ }
+ if (1 != account_serial)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup account failed: incorrect serial number found\n");
+ return 1;
+ }
+ if (1 == plugin->lookup_account (plugin->cls,
+ cls->is.id,
+ "payto://other-uri",
+ &account_serial))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup account failed: account found where there is none\n");
+ return 1;
+ }
+
/* Test instance private key deletion */
if (0 > plugin->delete_instance_private_key (plugin->cls,
- "test_inst"))
+ cls->is.id))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Delete instance private key failed\n");
@@ -1162,6 +1191,452 @@ test_orders (void *cls)
/**
+ * A container for deposit data.
+ */
+struct DepositData
+{
+ struct GNUNET_TIME_Absolute timestamp;
+
+ struct GNUNET_HashCode h_contract_terms;
+
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+
+ const char *exchange_url;
+
+ struct TALER_Amount amount_with_fee;
+
+ struct TALER_Amount deposit_fee;
+
+ struct TALER_Amount refund_fee;
+
+ struct TALER_Amount wire_fee;
+
+ struct GNUNET_HashCode h_wire;
+
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+};
+
+
+/**
+ * Closure for testing deposit lookup
+ */
+struct TestLookupDeposits_Closure
+{
+ /**
+ * Number of deposits to compare to
+ */
+ unsigned int deposits_to_cmp_length;
+
+ /**
+ * Pointer to array of deposit data
+ */
+ const struct DepositData *deposits_to_cmp;
+
+ /**
+ * Pointer to array of number of matches per deposit
+ */
+ unsigned int *results_matching;
+
+ /**
+ * Total number of results returned
+ */
+ unsigned int results_length;
+};
+
+
+static void
+lookup_deposits_cb (void *cls,
+ const char *exchange_url,
+ const struct TALER_CoinSpendPublicKeyP *coin_pub,
+ const struct TALER_Amount *amount_with_fee,
+ const struct TALER_Amount *deposit_fee,
+ const struct TALER_Amount *refund_fee,
+ const struct TALER_Amount *wire_fee)
+{
+ if (NULL == cls)
+ return;
+ struct TestLookupDeposits_Closure *cmp = cls;
+ cmp->results_length += 1;
+ for (unsigned int i = 0; cmp->deposits_to_cmp_length > i; ++i)
+ {
+ if ((GNUNET_OK == TALER_amount_cmp_currency (
+ &cmp->deposits_to_cmp[i].amount_with_fee,
+ amount_with_fee)) &&
+ (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].amount_with_fee,
+ amount_with_fee)) &&
+ (GNUNET_OK == TALER_amount_cmp_currency (
+ &cmp->deposits_to_cmp[i].deposit_fee,
+ deposit_fee)) &&
+ (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].deposit_fee,
+ deposit_fee)) &&
+ (GNUNET_OK == TALER_amount_cmp_currency (
+ &cmp->deposits_to_cmp[i].refund_fee,
+ refund_fee)) &&
+ (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].refund_fee,
+ refund_fee)) &&
+ (GNUNET_OK == TALER_amount_cmp_currency (
+ &cmp->deposits_to_cmp[i].wire_fee,
+ wire_fee)) &&
+ (0 == TALER_amount_cmp (&cmp->deposits_to_cmp[i].wire_fee,
+ wire_fee)))
+ {
+ cmp->results_matching[i] += 1;
+ }
+
+ }
+}
+
+
+static int
+test_insert_deposit (const char *is,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const struct DepositData *deposit)
+{
+ if (1 != plugin->insert_deposit (plugin->cls,
+ is,
+ deposit->timestamp,
+ &deposit->h_contract_terms,
+ &deposit->coin_pub,
+ deposit->exchange_url,
+ &deposit->amount_with_fee,
+ &deposit->deposit_fee,
+ &deposit->refund_fee,
+ &deposit->wire_fee,
+ &deposit->h_wire,
+ &deposit->exchange_sig,
+ exchange_pub))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Insert deposit failed\n");
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
+test_lookup_deposits (const char *is,
+ const struct GNUNET_HashCode *h_contract_terms,
+ unsigned int deposits_length,
+ const struct DepositData *deposits)
+{
+ struct TestLookupDeposits_Closure cls;
+ cls.deposits_to_cmp_length = deposits_length;
+ cls.deposits_to_cmp = deposits;
+ unsigned int results_matching[deposits_length];
+ for (unsigned int i = 0; deposits_length > i; ++i)
+ results_matching[i] = 0;
+ cls.results_matching = results_matching;
+ cls.results_length = 0;
+ if (0 > plugin->lookup_deposits (plugin->cls,
+ is,
+ h_contract_terms,
+ &lookup_deposits_cb,
+ &cls))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup deposits failed\n");
+ return 1;
+ }
+ if (deposits_length != cls.results_length)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup deposits failed: incorrect number of results returned\n");
+ return 1;
+ }
+ for (unsigned int i = 0; deposits_length > i; ++i)
+ {
+ if (cls.results_matching[i] != 1)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Lookup deposits failed: mismatched data\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Closure for deposit tests.
+ */
+struct TestDeposits_Closure
+{
+ /**
+ * The instance settings
+ */
+ struct TALER_MERCHANTDB_InstanceSettings is;
+
+ /**
+ * The instance public key
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * The instance private key
+ */
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+
+ /**
+ * The merchant account
+ */
+ struct TALER_MERCHANTDB_AccountDetails account;
+
+ /**
+ * The exchange public key
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * The exchange private key
+ */
+ struct TALER_ExchangePrivateKeyP exchange_priv;
+
+ /**
+ * The master public key
+ */
+ struct TALER_MasterPublicKeyP master_pub;
+
+ /**
+ * The master private key
+ */
+ struct TALER_MasterPrivateKeyP master_priv;
+
+ /**
+ * The master signature
+ */
+ struct TALER_MasterSignatureP master_sig;
+
+ /**
+ * The exchange signkey start date
+ */
+ struct GNUNET_TIME_Absolute signkey_start;
+
+ /**
+ * The exchange signkey expire date
+ */
+ struct GNUNET_TIME_Absolute signkey_expire;
+
+ /**
+ * The exchange signkey end date
+ */
+ struct GNUNET_TIME_Absolute signkey_end;
+
+ /**
+ * The order data
+ */
+ struct OrderData order;
+
+ /**
+ * The array of deposits
+ */
+ struct DepositData deposits[2];
+};
+
+
+static void
+pre_test_deposits (struct TestDeposits_Closure *cls)
+{
+ /* Instance */
+ GNUNET_CRYPTO_eddsa_key_create (&cls->merchant_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&cls->merchant_priv.eddsa_priv,
+ &cls->merchant_pub.eddsa_pub);
+ cls->is.id = "test_inst_deposits";
+ cls->is.name = "Test";
+ cls->is.address = json_array ();
+ GNUNET_assert (NULL != cls->is.address);
+ GNUNET_assert (0 == json_array_append (cls->is.address,
+ json_string ("123 Example St")));
+ cls->is.jurisdiction = json_array ();
+ GNUNET_assert (NULL != cls->is.jurisdiction);
+ GNUNET_assert (0 == json_array_append (cls->is.jurisdiction,
+ json_string ("Ohio")));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:1200.40",
+ &cls->is.default_max_deposit_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:1200.40",
+ &cls->is.default_max_wire_fee));
+ cls->is.default_wire_fee_amortization = 1;
+ cls->is.default_wire_transfer_delay = GNUNET_TIME_relative_get_minute_ ();
+ cls->is.default_pay_delay = GNUNET_TIME_relative_get_second_ ();
+
+ /* Account */
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG,
+ &cls->account.h_wire);
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG,
+ &cls->account.salt);
+ cls->account.payto_uri = "payto://x-taler-bank/bank.demo.taler.net/4";
+ cls->account.active = true;
+
+ /* Signing key */
+ GNUNET_CRYPTO_eddsa_key_create (&cls->exchange_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&cls->exchange_priv.eddsa_priv,
+ &cls->exchange_pub.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_key_create (&cls->master_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&cls->master_priv.eddsa_priv,
+ &cls->master_pub.eddsa_pub);
+ struct TALER_ExchangeSigningKeyValidityPS exch_sign;
+ exch_sign.purpose.size = htonl (sizeof (struct
+ TALER_ExchangeSigningKeyValidityPS));
+ exch_sign.purpose.purpose = htonl (
+ TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY);
+ GNUNET_CRYPTO_eddsa_sign (&cls->master_priv.eddsa_priv,
+ &exch_sign,
+ &cls->master_sig.eddsa_signature);
+ cls->signkey_start = GNUNET_TIME_absolute_get ();
+ cls->signkey_expire = GNUNET_TIME_absolute_get ();
+ cls->signkey_end = GNUNET_TIME_absolute_get ();
+
+ /* Order */
+ struct GNUNET_TIME_Absolute pay_deadline =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_UNIT_DAYS);
+ struct GNUNET_TIME_Absolute refund_deadline =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_UNIT_WEEKS);
+ GNUNET_TIME_round_abs (&pay_deadline);
+ GNUNET_TIME_round_abs (&refund_deadline);
+ cls->order.id = "test_orders_od_1";
+ cls->order.pay_deadline = pay_deadline;
+ cls->order.contract = json_object ();
+ json_object_set (cls->order.contract,
+ "fulfillment_url",
+ json_string ("a"));
+ json_object_set (cls->order.contract,
+ "pay_deadline",
+ GNUNET_JSON_from_time_abs (pay_deadline));
+ json_object_set (cls->order.contract,
+ "refund_deadline",
+ GNUNET_JSON_from_time_abs (refund_deadline));
+
+ /* Deposit */
+ cls->deposits[0].timestamp = GNUNET_TIME_absolute_get ();
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_hash (cls->order.contract,
+ &cls->deposits[0].h_contract_terms));
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+ GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
+ &cls->deposits[0].coin_pub.eddsa_pub);
+ cls->deposits[0].exchange_url = "test-exchange";
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:50.00",
+ &cls->deposits[0].amount_with_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:1.00",
+ &cls->deposits[0].deposit_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:1.50",
+ &cls->deposits[0].refund_fee));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount ("EUR:2.00",
+ &cls->deposits[0].wire_fee));
+ cls->deposits[0].h_wire = cls->account.h_wire;
+ struct TALER_DepositRequestPS deposit_sign;
+ deposit_sign.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
+ deposit_sign.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ deposit_sign.h_contract_terms = cls->deposits[0].h_contract_terms;
+ deposit_sign.h_wire = cls->deposits[0].h_wire;
+ deposit_sign.wallet_timestamp = GNUNET_TIME_absolute_hton (
+ GNUNET_TIME_absolute_get ());
+ deposit_sign.refund_deadline = GNUNET_TIME_absolute_hton (
+ GNUNET_TIME_absolute_get ());
+ TALER_amount_hton (&deposit_sign.amount_with_fee,
+ &cls->deposits[0].amount_with_fee);
+ TALER_amount_hton (&deposit_sign.deposit_fee,
+ &cls->deposits[0].deposit_fee);
+ deposit_sign.merchant = cls->merchant_pub;
+ deposit_sign.coin_pub = cls->deposits[0].coin_pub;
+ GNUNET_CRYPTO_eddsa_sign (&cls->exchange_priv.eddsa_priv,
+ &deposit_sign,
+ &cls->deposits[0].exchange_sig.eddsa_signature);
+}
+
+
+static void
+post_test_deposits (struct TestDeposits_Closure *cls)
+{
+ /* Instance */
+ json_decref (cls->is.address);
+ json_decref (cls->is.jurisdiction);
+
+ /* Order */
+ json_decref (cls->order.contract);
+}
+
+
+static int
+run_test_deposits (struct TestDeposits_Closure *cls)
+{
+ /* Insert the instance */
+ TEST_RET_ON_FAIL (test_insert_instance (&cls->merchant_pub,
+ &cls->merchant_priv,
+ &cls->is));
+
+ /* Insert an account */
+ TEST_RET_ON_FAIL (test_insert_account (cls->is.id,
+ &cls->account));
+
+ /* Insert a signing key */
+ if (1 != plugin->insert_exchange_signkey (plugin->cls,
+ &cls->master_pub,
+ &cls->exchange_pub,
+ cls->signkey_start,
+ cls->signkey_expire,
+ cls->signkey_end,
+ &cls->master_sig))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Insert signing key failed\n");
+ return 1;
+ }
+
+ /* Insert an order */
+ TEST_RET_ON_FAIL (test_insert_order (cls->is.id,
+ cls->order.id,
+ cls->order.pay_deadline,
+ cls->order.contract));
+
+ /* Insert contract terms */
+ if (1 != plugin->insert_contract_terms (plugin->cls,
+ cls->is.id,
+ cls->order.id,
+ cls->order.contract))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Insert contract terms failed\n");
+ return 1;
+ }
+
+ /* Test inserting a deposit */
+ TEST_RET_ON_FAIL (test_insert_deposit (cls->is.id,
+ &cls->exchange_pub,
+ &cls->deposits[0]));
+
+ /* Test lookup deposits */
+ TEST_RET_ON_FAIL (test_lookup_deposits (cls->is.id,
+ &cls->deposits[0].h_contract_terms,
+ 1,
+ cls->deposits));
+
+ return 0;
+}
+
+
+static int
+test_deposits (void *cls)
+{
+ struct TestDeposits_Closure test_cls;
+ pre_test_deposits (&test_cls);
+ int test_result = run_test_deposits (&test_cls);
+ post_test_deposits (&test_cls);
+ return test_result;
+}
+
+
+/**
* Function that runs all tests and returns 1 upon error, 0 on success.
*/
static int
@@ -1170,6 +1645,7 @@ run_tests (void *cls)
TEST_RET_ON_FAIL (test_instances (cls));
TEST_RET_ON_FAIL (test_products (cls));
TEST_RET_ON_FAIL (test_orders (cls));
+ TEST_RET_ON_FAIL (test_deposits (cls));
return 0;
}