merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit d809c7b29120f2f33e078e402a2b42f624dd20aa
parent 6b908a8147b98312bc447a6c0bf2705789d197cb
Author: Jonathan Buchanan <jonathan.russ.buchanan@gmail.com>
Date:   Thu, 28 May 2020 01:36:04 -0400

more db tests for transfers and tips

Diffstat:
Msrc/backenddb/plugin_merchantdb_postgres.c | 8++++----
Msrc/backenddb/test_merchantdb.c | 373+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/taler_merchantdb_plugin.h | 2+-
3 files changed, 378 insertions(+), 5 deletions(-)

diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c @@ -1334,14 +1334,14 @@ postgres_insert_order_lock (void *cls, const char *instance_id, const char *order_id, const char *product_id, - uint32_t quantity) + uint64_t quantity) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (instance_id), GNUNET_PQ_query_param_string (order_id), GNUNET_PQ_query_param_string (product_id), - GNUNET_PQ_query_param_uint32 (&quantity), + GNUNET_PQ_query_param_uint64 (&quantity), GNUNET_PQ_query_param_end }; @@ -6660,10 +6660,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " JOIN tmp USING(merchant_serial)" " WHERE order_id=$2 AND" " tmp.total_stock - tmp.total_sold - tmp.total_lost - $4 >= " - " (SELECT SUM(total_locked)" + " (SELECT COALESCE(SUM(total_locked), 0)" " FROM merchant_inventory_locks" " WHERE product_serial=tmp.product_serial) + " - " (SELECT SUM(total_locked)" + " (SELECT COALESCE(SUM(total_locked), 0)" " FROM merchant_order_locks" " WHERE product_serial=tmp.product_serial)", 4), diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c @@ -1171,6 +1171,16 @@ struct TestOrders_Closure struct TALER_MerchantPrivateKeyP merchant_priv; /** + * The product details + */ + struct TALER_MERCHANTDB_ProductDetails product; + + /** + * The product id + */ + const char *product_id; + + /** * The array of orders */ struct OrderData orders[2]; @@ -1212,6 +1222,26 @@ pre_test_orders (struct TestOrders_Closure *cls) cls->is.default_wire_transfer_delay = GNUNET_TIME_relative_get_minute_ (); cls->is.default_pay_delay = GNUNET_TIME_relative_get_second_ (); + /* Product */ + cls->product_id = "test_products_pd_0"; + cls->product.description = "This is a test product"; + cls->product.description_i18n = json_array (); + GNUNET_assert (NULL != cls->product.description_i18n); + cls->product.unit = "boxes"; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:120.40", + &cls->product.price)); + cls->product.taxes = json_array (); + GNUNET_assert (NULL != cls->product.taxes); + cls->product.total_stock = 55; + cls->product.total_sold = 0; + cls->product.total_lost = 0; + cls->product.image = json_array (); + GNUNET_assert (NULL != cls->product.image); + cls->product.address = json_array (); + GNUNET_assert (NULL != cls->product.address); + cls->product.next_restock = GNUNET_TIME_absolute_get_zero_ (); + /* Orders */ cls->orders[0].id = "test_orders_od_0"; cls->orders[0].pay_deadline = GNUNET_TIME_absolute_get_zero_ (); @@ -1248,6 +1278,11 @@ post_test_orders (struct TestOrders_Closure *cls) json_decref (cls->is.address); json_decref (cls->is.jurisdiction); + json_decref (cls->product.description_i18n); + json_decref (cls->product.taxes); + json_decref (cls->product.image); + json_decref (cls->product.address); + json_decref (cls->orders[0].contract); json_decref (cls->orders[1].contract); } @@ -1308,6 +1343,22 @@ run_test_orders (struct TestOrders_Closure *cls) cls->orders[0].id, cls->orders[0].contract)); + /* Test order lock */ + TEST_RET_ON_FAIL (test_insert_product (cls->is.id, + cls->product_id, + &cls->product)); + // TEST_RET_ON_FAIL (test) + if (1 != plugin->insert_order_lock (plugin->cls, + cls->is.id, + cls->orders[0].id, + cls->product_id, + 5)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Insert order lock failed\n"); + return 1; + } + /* Test lookup contract terms */ TEST_RET_ON_FAIL (test_lookup_contract_terms (cls->is.id, cls->orders[0].id, @@ -2111,6 +2162,56 @@ test_lookup_transfer_details (const char *exchange_url, } +static int +test_lookup_wire_fee (const struct TALER_MasterPublicKeyP *master_pub, + const char *wire_method, + struct GNUNET_TIME_Absolute contract_date, + struct TALER_Amount *expected_wire_fee, + struct TALER_Amount *expected_closing_fee, + struct GNUNET_TIME_Absolute *expected_start_date, + struct GNUNET_TIME_Absolute *expected_end_date, + struct TALER_MasterSignatureP *expected_master_sig) +{ + struct TALER_Amount wire_fee; + struct TALER_Amount closing_fee; + struct GNUNET_TIME_Absolute start_date; + struct GNUNET_TIME_Absolute end_date; + struct TALER_MasterSignatureP master_sig; + if (1 != plugin->lookup_wire_fee (plugin->cls, + master_pub, + wire_method, + contract_date, + &wire_fee, + &closing_fee, + &start_date, + &end_date, + &master_sig)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup wire fee failed\n"); + return 1; + } + if ((GNUNET_OK != TALER_amount_cmp_currency (expected_wire_fee, + &wire_fee)) || + (0 != TALER_amount_cmp (expected_wire_fee, + &wire_fee)) || + (GNUNET_OK != TALER_amount_cmp_currency (expected_closing_fee, + &closing_fee)) || + (0 != TALER_amount_cmp (expected_closing_fee, + &closing_fee)) || + (expected_start_date->abs_value_us != start_date.abs_value_us) || + (expected_end_date->abs_value_us != end_date.abs_value_us) || + (0 != GNUNET_memcmp (expected_master_sig, + &master_sig))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup wire fee failed: mismatched data\n"); + return 1; + } + return 0; +} + + struct TestTransfers_Closure { /** @@ -2321,6 +2422,9 @@ run_test_transfers (struct TestTransfers_Closure *cls) return 1; } + /* Test lookup wire fee */ + + /* Test lookup transfer */ GNUNET_assert (0 <= TALER_amount_add (&total_with_fee, &transfer_data.total_amount, @@ -2380,6 +2484,274 @@ test_transfers (void *cls) } +struct TestLookupReserve_Callback +{ + const struct GNUNET_TIME_Absolute *creation_time; + + const struct GNUNET_TIME_Absolute *expiration_time; + + const struct TALER_Amount *merchant_initial_amount; + + const struct TALER_Amount *exchange_initial_amount; + + const struct TALER_Amount *picked_up_amount; + + const struct TALER_Amount *committed_amount; + + unsigned int tips_length; + + const struct TALER_MERCHANTDB_TipDetails *tips; + + int result_matches; +}; + + +static void +lookup_reserve_cb (void *cls, + struct GNUNET_TIME_Absolute creation_time, + struct GNUNET_TIME_Absolute expiration_time, + const struct TALER_Amount *merchant_initial_amount, + const struct TALER_Amount *exchange_initial_amount, + const struct TALER_Amount *picked_up_amount, + const struct TALER_Amount *committed_amount, + unsigned int tips_length, + const struct TALER_MERCHANTDB_TipDetails *tips) +{ + struct TestLookupReserve_Callback *cmp = cls; + if (NULL == cmp) + return; + if ((cmp->creation_time->abs_value_us != creation_time.abs_value_us) || + (cmp->expiration_time->abs_value_us != expiration_time.abs_value_us) || + (GNUNET_OK != TALER_amount_cmp_currency (cmp->merchant_initial_amount, + merchant_initial_amount)) || + (0 != TALER_amount_cmp (cmp->merchant_initial_amount, + merchant_initial_amount)) || + (GNUNET_OK != TALER_amount_cmp_currency (cmp->exchange_initial_amount, + exchange_initial_amount)) || + (0 != TALER_amount_cmp (cmp->exchange_initial_amount, + exchange_initial_amount)) || + (GNUNET_OK != TALER_amount_cmp_currency (cmp->picked_up_amount, + picked_up_amount)) || + (0 != TALER_amount_cmp (cmp->picked_up_amount, + picked_up_amount)) || + (GNUNET_OK != TALER_amount_cmp_currency (cmp->committed_amount, + committed_amount)) || + (0 != TALER_amount_cmp (cmp->committed_amount, + committed_amount)) || + (cmp->tips_length != tips_length)) + { + cmp->result_matches = 1; + return; + } + for (unsigned int i = 0; tips_length > i; ++i) + { + + } + cmp->result_matches = 0; +} + + +static int +test_lookup_reserve (const char *instance_id, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct GNUNET_TIME_Absolute *expected_creation_time, + const struct + GNUNET_TIME_Absolute *expected_expiration_time, + const struct TALER_Amount *expected_merchant_amount, + const struct TALER_Amount *expected_exchange_amount, + const struct TALER_Amount *expected_picked_up_amount, + const struct TALER_Amount *expected_committed_amount, + unsigned int expected_tips_length, + const struct TALER_MERCHANTDB_TipDetails *expected_tips) +{ + struct TestLookupReserve_Callback cmp = { + .creation_time = expected_creation_time, + .expiration_time = expected_expiration_time, + .merchant_initial_amount = expected_merchant_amount, + .exchange_initial_amount = expected_exchange_amount, + .picked_up_amount = expected_picked_up_amount, + .committed_amount = expected_committed_amount, + .tips_length = expected_tips_length, + .tips = expected_tips + }; + if (1 != plugin->lookup_reserve (plugin->cls, + instance_id, + reserve_pub, + false, + &lookup_reserve_cb, + &cmp)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup reserve failed\n"); + return 1; + } + if (0 != cmp.result_matches) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup reserve failed: result does not match\n"); + return 1; + } + return 0; +} + + +struct TestTips_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 reserve public key + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * The reserve private key + */ + struct TALER_ReservePrivateKeyP reserve_priv; +}; + + +static void +pre_test_tips (struct TestTips_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_tips"; + 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_ (); + + /* Reserve */ + GNUNET_CRYPTO_eddsa_key_create (&cls->reserve_priv.eddsa_priv); + GNUNET_CRYPTO_eddsa_key_get_public (&cls->reserve_priv.eddsa_priv, + &cls->reserve_pub.eddsa_pub); +} + + +static void +post_test_tips (struct TestTips_Closure *cls) +{ + json_decref (cls->is.address); + json_decref (cls->is.jurisdiction); +} + + +static int +run_test_tips (struct TestTips_Closure *cls) +{ + TEST_RET_ON_FAIL (test_insert_instance (&cls->merchant_pub, + &cls->merchant_priv, + &cls->is)); + + /* Test insert reserve */ + struct TALER_Amount initial_amount; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:99.99", + &initial_amount)); + struct GNUNET_TIME_Absolute expiration = + GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), + GNUNET_TIME_UNIT_WEEKS); + if (TALER_EC_NONE != plugin->insert_reserve (plugin->cls, + cls->is.id, + &cls->reserve_priv, + &cls->reserve_pub, + "exch-url", + &initial_amount, + expiration)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Insert reserve failed\n"); + return 1; + } + + /* Test lookup reserve */ + /* + struct GNUNET_TIME_Absolute creation = GNUNET_TIME_absolute_get (); + struct TALER_Amount zero_amount; + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero ("EUR", + &zero_amount)); + TEST_RET_ON_FAIL (test_lookup_reserve (cls->is.id, + &cls->reserve_pub, + &creation, + &expiration, + &initial_amount, + &zero_amount, + &zero_amount, + &zero_amount, + 0, + NULL)); + */ + + /* Test inserting a tip */ + /* + struct TALER_Amount tip_amount; + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount ("EUR:0.99", + &tip_amount)); + struct GNUNET_HashCode tip_id; + GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_STRONG, + &tip_id); + if (TALER_EC_NONE != plugin->authorize_tip (plugin->cls, + cls->is.id, + &cls->reserve_pub, + &tip_amount, + "because", + "https://taler.net", + &tip_id, + &expiration)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Authorize tip failed\n"); + return 1; + } + */ + + return 0; +} + + +static int +test_tips (void *cls) +{ + struct TestTips_Closure test_cls; + pre_test_tips (&test_cls); + int test_result = run_test_tips (&test_cls); + post_test_tips (&test_cls); + return test_result; +} + + /** * Function that runs all tests and returns 1 upon error, 0 on success. */ @@ -2391,6 +2763,7 @@ run_tests (void *cls) TEST_RET_ON_FAIL (test_orders (cls)); TEST_RET_ON_FAIL (test_deposits (cls)); TEST_RET_ON_FAIL (test_transfers (cls)); + TEST_RET_ON_FAIL (test_tips (cls)); return 0; } diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h @@ -1031,7 +1031,7 @@ struct TALER_MERCHANTDB_Plugin const char *instance_id, const char *order_id, const char *product_id, - uint32_t quantity); + uint64_t quantity); /**