diff options
author | Christian Grothoff <christian@grothoff.org> | 2020-05-02 23:24:22 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2020-05-02 23:24:22 +0200 |
commit | 35623b7bc44210bc55a429a4f81b1194bb798034 (patch) | |
tree | 15659bbdf23c4db6547730fdaac7da594f221be3 /src/testing/testing_api_cmd_abort_order.c | |
parent | 9e90a4432b414382344ea525a34af27e661523f4 (diff) | |
download | merchant-35623b7bc44210bc55a429a4f81b1194bb798034.tar.gz merchant-35623b7bc44210bc55a429a4f81b1194bb798034.tar.bz2 merchant-35623b7bc44210bc55a429a4f81b1194bb798034.zip |
implement abort client lib
Diffstat (limited to 'src/testing/testing_api_cmd_abort_order.c')
-rw-r--r-- | src/testing/testing_api_cmd_abort_order.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/testing/testing_api_cmd_abort_order.c b/src/testing/testing_api_cmd_abort_order.c new file mode 100644 index 00000000..4444c349 --- /dev/null +++ b/src/testing/testing_api_cmd_abort_order.c @@ -0,0 +1,460 @@ +/* + This file is part of TALER + Copyright (C) 2014-2018, 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3, or + (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, see + <http://www.gnu.org/licenses/> +*/ +/** + * @file lib/testing_api_cmd_abort_order.c + * @brief command to test the abort feature. + * @author Marcello Stanisci + */ +#include "platform.h" +#include <taler/taler_exchange_service.h> +#include <taler/taler_testing_lib.h> +#include <taler/taler_signatures.h> +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + +#define AMOUNT_WITH_FEE 0 + +/** + * State for a " abort" CMD. + */ +struct AbortState +{ + + /** + * Merchant public key. + */ + struct TALER_MerchantPublicKeyP merchant_pub; + + /** + * Reference to the "pay" command to abort. + */ + const char *pay_reference; + + /** + * Merchant URL. + */ + const char *merchant_url; + + /** + * Handle to a "abort" operation. + */ + struct TALER_MERCHANT_OrderAbortHandle *oah; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * The actual abort/refund data. + */ + struct TALER_MERCHANT_AbortedCoin *acs; + + /** + * Expected HTTP response code. + */ + unsigned int http_status; + + /** + * How many refund permissions this CMD got + * the right for. Roughly, there is one refund + * permission for one coin. + */ + unsigned int acs_length; + +}; + + +/** + * Parse the @a coins specification and grow the @a ac + * array with the coins found, updating @a nac. + * + * @param[in,out] ac pointer to array of coins found + * @param[in,out] nac length of array at @a pc + * @param[in] coins string specifying coins to add to @a pc, + * clobbered in the process + * @param is interpreter state + * @param amount_with_fee total amount to be paid for a contract. + * @param amount_without_fee to be removed, there is no + * per-contract fee, only per-coin exists. + * @param refund_fee per-contract? per-coin? + * @return #GNUNET_OK on success + */ +static int +build_coins (struct TALER_MERCHANT_AbortCoin **ac, + unsigned int *nac, + char *coins, + struct TALER_TESTING_Interpreter *is, + const char *amount_with_fee) +{ + char *token; + + for (token = strtok (coins, ";"); + NULL != token; + token = strtok (NULL, ";")) + { + char *ctok; + unsigned int ci; + struct TALER_MERCHANT_AbortCoin *icoin; + + /* Token syntax is "LABEL[/NUMBER]" */ + ctok = strchr (token, '/'); + ci = 0; + if (NULL != ctok) + { + *ctok = '\0'; + ctok++; + if (1 != sscanf (ctok, + "%u", + &ci)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + } + // FIXME: ci not used!? + { + const struct TALER_TESTING_Command *coin_cmd; + coin_cmd = TALER_TESTING_interpreter_lookup_command (is, + token); + if (NULL == coin_cmd) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + GNUNET_array_grow (*pc, + *npc, + (*npc) + 1); + icoin = &((*pc)[(*npc) - 1]); + + { + const struct TALER_CoinSpendPublicKeyP *coin_pub; + + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_coin_pub (coin_cmd, + 0, + &coin_pub)); + icoin->coin_pub = *coin_pub; + } + GNUNET_assert (GNUNET_OK == + TALER_TESTING_get_trait_url (coin_cmd, + TALER_TESTING_UT_EXCHANGE_BASE_URL, + &icoin->exchange_url)); + // FIXME: initialize icon->amount_with_fee! + } + } + return GNUNET_OK; +} + + +/** + * Callback for a "pay abort" operation. Mainly, check HTTP + * response code was as expected and stores refund permissions + * in the state. + * + * @param cls closure. + * @param hr HTTP response + * @param merchant_pub public key of the merchant refunding the + * contract. + * @param h_contract the contract involved in the refund. + * @param num_refunds length of the @a res array + * @param res array containing the abort confirmations + */ +static void +abort_cb (void *cls, + const struct TALER_MERCHANT_HttpResponse *hr, + const struct TALER_MerchantPublicKeyP *merchant_pub, + unsigned int num_aborts, + const struct TALER_MERCHANT_AbortedCoin res[]) +{ + struct AbortState *as = cls; + + as->pao = NULL; + if (as->http_status != hr->http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u (%d) to command %s\n", + hr->http_status, + (int) hr->ec, + TALER_TESTING_interpreter_get_current_label (as->is)); + TALER_TESTING_FAIL (as->is); + } + if ( (MHD_HTTP_OK == hr->http_status) && + (TALER_EC_NONE == hr->ec) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received %u refunds\n", + num_refunds); + as->acs_length = num_aborts; + as->acs = GNUNET_new_array (num_aborts, + struct TALER_MERCHANT_AbortedCoin); + memcpy (as->res, + res, + num_refunds * sizeof (struct TALER_MERCHANT_AbortedCoin)); + as->merchant_pub = *merchant_pub; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successful pay-abort (HTTP status: %u)\n", + hr->http_status); + TALER_TESTING_interpreter_next (as->is); +} + + +/** + * Run an "abort" CMD. + * + * @param cls closure + * @param cmd command being run. + * @param is interpreter state + */ +static void +abort_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct AbortState *as = cls; + const struct TALER_TESTING_Command *pay_cmd; + const char *proposal_reference; + const char *coin_reference; + const char *amount_with_fee; + const struct TALER_TESTING_Command *proposal_cmd; + const char *order_id; + struct TALER_MerchantPublicKeyP merchant_pub; + const struct GNUNET_HashCode *h_proposal; + struct TALER_Amount total_amount; + const char *error_name; + unsigned int error_line; + struct TALER_MERCHANT_AbortCoin *abort_coins; + unsigned int nabort_coins; + char *cr; + struct TALER_MERCHANT_OrderAbortHandle *oah; + + as->is = is; + pay_cmd = TALER_TESTING_interpreter_lookup_command (is, + as->pay_reference); + if (NULL == pay_cmd) + TALER_TESTING_FAIL (is); + if (GNUNET_OK != + TALER_TESTING_get_trait_proposal_reference (pay_cmd, + 0, + &proposal_reference)) + TALER_TESTING_FAIL (is); + if (GNUNET_OK != + TALER_TESTING_get_trait_coin_reference (pay_cmd, + 0, + &coin_reference)) + TALER_TESTING_FAIL (is); + if (GNUNET_OK != + TALER_TESTING_get_trait_string (pay_cmd, + AMOUNT_WITH_FEE, + &amount_with_fee)) + TALER_TESTING_FAIL (is); + proposal_cmd = TALER_TESTING_interpreter_lookup_command (is, + proposal_reference); + + if (NULL == proposal_cmd) + { + GNUNET_break (0); + return NULL; + } + + { + const json_t *contract_terms; + + if (GNUNET_OK != + TALER_TESTING_get_trait_contract_terms (proposal_cmd, + 0, + &contract_terms)) + { + GNUNET_break (0); + return NULL; + } + { + /* Get information that needs to be put verbatim in the + * deposit permission */ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("order_id", + &order_id), + GNUNET_JSON_spec_fixed_auto ("merchant_pub", + &as->merchant_pub), + TALER_JSON_spec_amount ("amount", + &total_amount), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (contract_terms, + spec, + &error_name, + &error_line)) + { + char *js; + + js = json_dumps (contract_terms, + JSON_INDENT (1)); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Parser failed on %s:%u for input `%s'\n", + error_name, + error_line, + js); + free (js); + GNUNET_break_op (0); + return NULL; + } + } + } + + cr = GNUNET_strdup (coin_reference); + pay_coins = NULL; + npay_coins = 0; + if (GNUNET_OK != + build_coins (&abort_coins, + &nabort_coins, + cr, + is, + amount_with_fee)) + { + GNUNET_array_grow (pay_coins, + npay_coins, + 0); + GNUNET_free (cr); + GNUNET_break (0); + return NULL; + } + GNUNET_free (cr); + + if (GNUNET_OK != + TALER_TESTING_get_trait_h_contract_terms (proposal_cmd, + 0, + &h_proposal)) + { + GNUNET_break (0); + return NULL; + } + as->oah = TALER_MERCHANT_order_abort (is->ctx, + merchant_url, + order_id, + &as->merchant_pub, + h_proposal, + nabort_coins, + abort_coins, + api_cb, + api_cb_cls); + GNUNET_array_grow (pay_coins, + npay_coins, + 0); + if (NULL == as->pao) + TALER_TESTING_FAIL (is); +} + + +/** + * Free a "pay abort" CMD, and cancel it if need be. + * + * @param cls closure. + * @param cmd command currently being freed. + */ +static void +abort_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct AbortState *as = cls; + + if (NULL != as->pao) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Command `%s' did not complete.\n", + TALER_TESTING_interpreter_get_current_label ( + as->is)); + TALER_MERCHANT_pay_cancel (as->pao); + } + GNUNET_free_non_null (as->res); + GNUNET_free (as); +} + + +/** + * Offer internal data useful to other commands. + * + * @param cls closure + * @param ret[out] result (could be anything) + * @param trait name of the trait + * @param index index number of the object to extract. + * @return #GNUNET_OK on success + */ +static int +abort_traits (void *cls, + const void **ret, + const char *trait, + unsigned int index) +{ + struct AbortState *as = cls; + struct TALER_TESTING_Trait traits[] = { + TALER_TESTING_make_trait_merchant_pub (0, + &as->merchant_pub), + TALER_TESTING_make_trait_refund_entry (0, + as->acs), + TALER_TESTING_make_trait_uint (0, + &as->num_refunds), + TALER_TESTING_trait_end () + }; + + return TALER_TESTING_get_trait (traits, + ret, + trait, + index); +} + + +/** + * Make an "abort" test command. + * + * @param label command label + * @param merchant_url merchant base URL + * @param pay_reference reference to the payment to abort + * @param http_status expected HTTP response code + * @return the command + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_abort (const char *label, + const char *merchant_url, + const char *pay_reference, + unsigned int http_status) +{ + struct AbortState *as; + + as = GNUNET_new (struct AbortState); + as->http_status = http_status; + as->pay_reference = pay_reference; + as->merchant_url = merchant_url; + { + struct TALER_TESTING_Command cmd = { + .cls = as, + .label = label, + .run = &abort_run, + .cleanup = &abort_cleanup, + .traits = &abort_traits + }; + + return cmd; + } +} + + +/* end of testing_api_cmd_abort_order.c */ |