merchant

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

commit 3b2b43cbab432fd5609f57f38e97699f01df21e3
parent 909a9a2d1be422ba69b0b7abdba0fad28ff4880c
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue,  4 Jul 2017 23:43:14 +0200

merge conflict resolution

Diffstat:
Msrc/lib/test_merchant_api.c | 390++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
1 file changed, 266 insertions(+), 124 deletions(-)

diff --git a/src/lib/test_merchant_api.c b/src/lib/test_merchant_api.c @@ -96,6 +96,11 @@ unsigned int ninstances = 0; static char *instance; /** + * Current instance key + */ +struct GNUNET_CRYPTO_EddsaPrivateKey *instance_priv; + +/** * Current instance being tested */ unsigned int instance_idx = 0; @@ -640,6 +645,11 @@ struct Command */ const char *reason; + /** + * Refund fee (MUST match the value given in config) + */ + const char *refund_fee; + } refund_increase; struct { @@ -654,6 +664,23 @@ struct Command */ struct TALER_MERCHANT_RefundLookupOperation *rlo; + /** + * Used to retrieve the asked refund amount. + * This information helps the callback to mock a GET /refund + * response and match it against what the backend actually + * responded. + */ + char *increase_ref; + + /** + * Used to retrieve the number and denomination of coins + * used to pay for the related contract. + * This information helps the callback to mock a GET /refund + * response and match it against what the backend actually + * responded. + */ + char *pay_ref; + } refund_lookup; } details; @@ -695,6 +722,40 @@ struct InterpreterState */ static struct GNUNET_DISK_PipeHandle *sigpipe; +/** + * Return instance private key from config + * + * @param config configuration handle + * @param instance instance name + * @return pointer to private key, NULL on error + */ +struct GNUNET_CRYPTO_EddsaPrivateKey * +get_instance_priv (struct GNUNET_CONFIGURATION_Handle *config, + const char *instance) +{ + char *config_section; + char *filename; + struct GNUNET_CRYPTO_EddsaPrivateKey *ret; + + (void) GNUNET_asprintf (&config_section, + "merchant-instance-%s", + instance); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (config, + config_section, + "KEYFILE", + &filename)) + { + GNUNET_break (0); + return NULL; + } + if (NULL == + (ret = GNUNET_CRYPTO_eddsa_key_create_from_file (filename))) + GNUNET_break (0); + + return ret; +} /** * The testcase failed, return with an error code. @@ -1162,12 +1223,12 @@ refund_increase_cb (void *cls, } /** - * Process GET /refund (increase) response + * Process GET /refund (increase) response. * * @param cls closure * @param http_status HTTP status code * @param ec taler-specific error object - * @param obj response body; is NULL on success. + * @param obj response body; is NULL on error. */ static void refund_lookup_cb (void *cls, @@ -1177,6 +1238,29 @@ refund_lookup_cb (void *cls, { struct InterpreterState *is = cls; struct Command *cmd = &is->commands[is->ip]; + const struct Command *pay_ref; + const struct Command *increase_ref; + const struct Command *coin_ref; + struct TALER_Amount refund_amount; + struct TALER_Amount resp_refund_amount; + struct TALER_Amount refund_fee; + struct TALER_Amount resp_refund_fee; + struct TALER_Amount coin_amount; + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_CoinSpendPublicKeyP resp_coin_pub; + struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub; + struct GNUNET_CRYPTO_EddsaPublicKey resp_merchant_pub; + struct json_t *resp_element; + const char *error_name; + unsigned int error_line; + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("coin_pub", &resp_coin_pub), + GNUNET_JSON_spec_fixed_auto ("merchant_pub", &resp_merchant_pub), + TALER_JSON_spec_amount ("refund_amount", &resp_refund_amount), + TALER_JSON_spec_amount ("refund_fee", &resp_refund_fee), + GNUNET_JSON_spec_end () + }; if (MHD_HTTP_OK != http_status) { @@ -1190,6 +1274,59 @@ refund_lookup_cb (void *cls, "/refund lookup:\n%s\n", json_dumps (obj, JSON_INDENT (2))); + increase_ref = find_command (is, cmd->details.refund_lookup.increase_ref); + GNUNET_assert (NULL != increase_ref); + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (increase_ref->details.refund_increase.refund_amount, + &refund_amount)); + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (increase_ref->details.refund_increase.refund_fee, + &refund_fee)); + + pay_ref = find_command (is, cmd->details.refund_lookup.pay_ref); + GNUNET_assert (NULL != pay_ref); + + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (pay_ref->details.pay.amount_without_fee, + &coin_amount)); + + /* Get coin pub */ + coin_ref = find_command (is, pay_ref->details.pay.coin_ref); + GNUNET_assert (NULL != coin_ref); + + GNUNET_CRYPTO_eddsa_key_get_public (&coin_ref->details.reserve_withdraw.coin_priv.eddsa_priv, + &coin_pub.eddsa_pub); + + GNUNET_assert (NULL != (resp_element = json_array_get (obj, 0))); + + GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (resp_element, + spec, + &error_name, + &error_line)); + GNUNET_CRYPTO_eddsa_key_get_public (instance_priv, + &merchant_pub); + + if (0 != memcmp (&refund_amount, + &resp_refund_amount, + sizeof (struct TALER_Amount)) || + 0 != memcmp (&refund_fee, + &resp_refund_fee, + sizeof (struct TALER_Amount)) || + 0 != memcmp (&coin_pub, + &resp_coin_pub, + sizeof (struct TALER_CoinSpendPublicKeyP)) || + 0 != memcmp (&merchant_pub, + &resp_merchant_pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))) + /*FIXME: match doable with json_equal() now!*/ + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad refund given\n"); + fail (is); + + } + cmd->details.refund_lookup.rlo = NULL; next_command (is); } @@ -1636,137 +1773,138 @@ interpreter_run (void *cls) struct Command *cmd = &is->commands[is->ip]; const struct Command *ref; struct TALER_ReservePublicKeyP reserve_pub; - struct TALER_CoinSpendPublicKeyP coin_pub; - struct TALER_Amount amount; - struct GNUNET_TIME_Absolute execution_date; - json_t *sender_details; - json_t *transfer_details; - - is->task = NULL; - tc = GNUNET_SCHEDULER_get_task_context (); - if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) - { - fprintf (stderr, - "Test aborted by shutdown request\n"); - fail (is); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Interpreter runs command %u/%s(%u)\n", - is->ip, - cmd->label, - cmd->oc); - switch (cmd->oc) - { - case OC_END: - result = GNUNET_OK; - if (instance_idx + 1 == ninstances) + struct TALER_CoinSpendPublicKeyP coin_pub; + struct TALER_Amount amount; + struct GNUNET_TIME_Absolute execution_date; + json_t *sender_details; + json_t *transfer_details; + + is->task = NULL; + tc = GNUNET_SCHEDULER_get_task_context (); + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { - GNUNET_SCHEDULER_shutdown (); + fprintf (stderr, + "Test aborted by shutdown request\n"); + fail (is); return; } - cleanup_state (is); - is->ip = 0; - instance_idx++; - instance = instances[instance_idx]; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Switching instance: `%s'\n", - instance); - is->task = GNUNET_SCHEDULER_add_now (interpreter_run, - is); - return; - - case OC_PROPOSAL_LOOKUP: - { - const char *order_id; - - GNUNET_assert (NULL != cmd->details.proposal_lookup.proposal_reference); - ref = find_command (is, cmd->details.proposal_lookup.proposal_reference); - GNUNET_assert (NULL != ref); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Interpreter runs command %u/%s(%u)\n", + is->ip, + cmd->label, + cmd->oc); + switch (cmd->oc) + { + case OC_END: + result = GNUNET_OK; + if (instance_idx + 1 == ninstances) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + cleanup_state (is); + is->ip = 0; + instance_idx++; + instance = instances[instance_idx]; + instance_priv = get_instance_priv (cfg, instance); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Switching instance: `%s'\n", + instance); + is->task = GNUNET_SCHEDULER_add_now (interpreter_run, + is); + return; - order_id = - json_string_value (json_object_get (ref->details.proposal.contract_terms, - "order_id")); - GNUNET_assert (NULL != - (cmd->details.proposal_lookup.plo - = TALER_MERCHANT_proposal_lookup (ctx, - MERCHANT_URI, - order_id, - instance, - proposal_lookup_cb, - is))); - } + case OC_PROPOSAL_LOOKUP: + { + const char *order_id; + + GNUNET_assert (NULL != cmd->details.proposal_lookup.proposal_reference); + ref = find_command (is, cmd->details.proposal_lookup.proposal_reference); + GNUNET_assert (NULL != ref); + + order_id = + json_string_value (json_object_get (ref->details.proposal.contract_terms, + "order_id")); + GNUNET_assert (NULL != + (cmd->details.proposal_lookup.plo + = TALER_MERCHANT_proposal_lookup (ctx, + MERCHANT_URI, + order_id, + instance, + proposal_lookup_cb, + is))); + } - return; + return; - case OC_ADMIN_ADD_INCOMING: - if (NULL != - cmd->details.admin_add_incoming.reserve_reference) - { - ref = find_command (is, - cmd->details.admin_add_incoming.reserve_reference); - GNUNET_assert (NULL != ref); - GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); - cmd->details.admin_add_incoming.reserve_priv - = ref->details.admin_add_incoming.reserve_priv; - } - else - { - struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + case OC_ADMIN_ADD_INCOMING: + if (NULL != + cmd->details.admin_add_incoming.reserve_reference) + { + ref = find_command (is, + cmd->details.admin_add_incoming.reserve_reference); + GNUNET_assert (NULL != ref); + GNUNET_assert (OC_ADMIN_ADD_INCOMING == ref->oc); + cmd->details.admin_add_incoming.reserve_priv + = ref->details.admin_add_incoming.reserve_priv; + } + else + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; - priv = GNUNET_CRYPTO_eddsa_key_create (); - cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv; - GNUNET_free (priv); - } - GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv, - &reserve_pub.eddsa_pub); - if (GNUNET_OK != - TALER_string_to_amount (cmd->details.admin_add_incoming.amount, - &amount)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse amount `%s' at %u\n", - cmd->details.admin_add_incoming.amount, - is->ip); - fail (is); - return; - } + priv = GNUNET_CRYPTO_eddsa_key_create (); + cmd->details.admin_add_incoming.reserve_priv.eddsa_priv = *priv; + GNUNET_free (priv); + } + GNUNET_CRYPTO_eddsa_key_get_public (&cmd->details.admin_add_incoming.reserve_priv.eddsa_priv, + &reserve_pub.eddsa_pub); + if (GNUNET_OK != + TALER_string_to_amount (cmd->details.admin_add_incoming.amount, + &amount)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse amount `%s' at %u\n", + cmd->details.admin_add_incoming.amount, + is->ip); + fail (is); + return; + } - execution_date = GNUNET_TIME_absolute_get (); - GNUNET_TIME_round_abs (&execution_date); - sender_details = json_loads (cmd->details.admin_add_incoming.sender_details, - JSON_REJECT_DUPLICATES, - NULL); - if (NULL == sender_details) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse sender details `%s' at %u\n", - cmd->details.admin_add_incoming.sender_details, - is->ip); - fail (is); - return; - } - transfer_details = json_loads (cmd->details.admin_add_incoming.transfer_details, - JSON_REJECT_DUPLICATES, - NULL); + execution_date = GNUNET_TIME_absolute_get (); + GNUNET_TIME_round_abs (&execution_date); + sender_details = json_loads (cmd->details.admin_add_incoming.sender_details, + JSON_REJECT_DUPLICATES, + NULL); + if (NULL == sender_details) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse sender details `%s' at %u\n", + cmd->details.admin_add_incoming.sender_details, + is->ip); + fail (is); + return; + } + transfer_details = json_loads (cmd->details.admin_add_incoming.transfer_details, + JSON_REJECT_DUPLICATES, + NULL); - if (NULL == transfer_details) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse transfer details `%s' at %u\n", - cmd->details.admin_add_incoming.transfer_details, - is->ip); - fail (is); - return; - } + if (NULL == transfer_details) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse transfer details `%s' at %u\n", + cmd->details.admin_add_incoming.transfer_details, + is->ip); + fail (is); + return; + } - cmd->details.admin_add_incoming.aih - = TALER_EXCHANGE_admin_add_incoming (exchange, - "http://localhost:18080/", - &reserve_pub, - &amount, - execution_date, - sender_details, + cmd->details.admin_add_incoming.aih + = TALER_EXCHANGE_admin_add_incoming (exchange, + "http://localhost:18080/", + &reserve_pub, + &amount, + execution_date, + sender_details, transfer_details, &add_incoming_cb, is); @@ -2564,12 +2702,15 @@ run (void *cls) { .oc = OC_REFUND_INCREASE, .label = "refund-increase-1", .details.refund_increase.refund_amount = "EUR:0.1", + .details.refund_increase.refund_fee = "EUR:0.01", .details.refund_increase.reason = "refund test", .details.refund_increase.order_id = "1" }, { .oc = OC_REFUND_LOOKUP, .label = "refund-lookup-1", - .details.refund_lookup.order_id = "1" + .details.refund_lookup.order_id = "1", + .details.refund_lookup.increase_ref = "refund-increase-1", + .details.refund_lookup.pay_ref = "deposit-simple" }, /* end of testcase */ { .oc = OC_END } @@ -2651,6 +2792,7 @@ main (int argc, GNUNET_strdup (token)); GNUNET_free (_instances); instance = instances[instance_idx]; + instance_priv = get_instance_priv (cfg, instance); db = TALER_MERCHANTDB_plugin_load (cfg); if (NULL == db) {