From d8e64ae258b911d4243a0fd62e46585f54bb445b Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Mon, 17 Aug 2020 21:03:45 -0400 Subject: testing and lib sources for new endpoint --- .../testing_api_cmd_wallet_post_orders_refund.c | 316 +++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 src/testing/testing_api_cmd_wallet_post_orders_refund.c (limited to 'src/testing/testing_api_cmd_wallet_post_orders_refund.c') diff --git a/src/testing/testing_api_cmd_wallet_post_orders_refund.c b/src/testing/testing_api_cmd_wallet_post_orders_refund.c new file mode 100644 index 00000000..0df41eda --- /dev/null +++ b/src/testing/testing_api_cmd_wallet_post_orders_refund.c @@ -0,0 +1,316 @@ +/* + This file is part of TALER + Copyright (C) 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 + +*/ +/** + * @file lib/testing_api_cmd_wallet_post_orders_refund.c + * @brief command to test refunds. + * @author Marcello Stanisci + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include "taler_merchant_service.h" +#include "taler_merchant_testing_lib.h" + + +/** + * State for an "obtain refunds" CMD. + */ +struct WalletRefundState +{ + /** + * Operation handle for a (public) POST /orders/$ID/refund request. + */ + struct TALER_MERCHANT_WalletOrderRefundHandle *orh; + + /** + * Base URL of the merchant serving the request. + */ + const char *merchant_url; + + /** + * Interpreter state. + */ + struct TALER_TESTING_Interpreter *is; + + /** + * Expected HTTP response code. + */ + unsigned int http_code; + + /** + * Label of the command that created the order we want to obtain refunds for. + */ + const char *proposal_reference; + + /** + * A list of refunds associated with this order. + */ + const char **refunds; + + /** + * The length of @e refunds. + */ + unsigned int refunds_length; +}; + + +/** + * Process POST /refund (increase) response; just checking + * if the HTTP response code is the one expected. + * + * @param cls closure + * @param hr HTTP response + */ +static void +refund_cb ( + void *cls, + const struct TALER_MERCHANT_HttpResponse *hr, + const struct TALER_Amount *refund_amount, + const struct TALER_MerchantPublicKeyP *merchant_pub, + struct TALER_MERCHANT_RefundDetail refunds[], + unsigned int refunds_length) +{ + struct WalletRefundState *wrs = cls; + + wrs->orh = NULL; + if (wrs->http_code != hr->http_status) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected status %u, got %u(%d) for refund increase\n", + wrs->http_code, + hr->http_status, + (int) hr->ec); + TALER_TESTING_FAIL (wrs->is); + } + switch (hr->http_status) + { + case MHD_HTTP_OK: + { + struct TALER_Amount refunded_total; + if (refunds_length > 0) + GNUNET_assert (GNUNET_OK == + TALER_amount_get_zero (refunds[0].refund_amount.currency, + &refunded_total)); + for (unsigned int i = 0; i < refunds_length; ++i) + { + const struct TALER_TESTING_Command *refund_cmd; + const char *expected_amount_str; + struct TALER_Amount expected_amount; + + refund_cmd = TALER_TESTING_interpreter_lookup_command ( + wrs->is, + wrs->refunds[i]); + + if (GNUNET_OK != + TALER_TESTING_get_trait_string (refund_cmd, + 0, + &expected_amount_str)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not fetch refund amount\n"); + TALER_TESTING_interpreter_fail (wrs->is); + return; + } + GNUNET_assert (GNUNET_OK == + TALER_string_to_amount (expected_amount_str, + &expected_amount)); + /* The most recent refunds are returned first */ + GNUNET_assert (0 <= TALER_amount_add (&refunded_total, + &refunded_total, + &refunds[refunds_length - 1 - i].refund_amount)); + if ((GNUNET_OK != + TALER_amount_cmp_currency (&expected_amount, + &refunded_total)) || + (0 != TALER_amount_cmp (&expected_amount, + &refunded_total))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Refund amounts do not match\n"); + TALER_TESTING_interpreter_fail (wrs->is); + return; + } + } + } + break; + default: + + break; + } + TALER_TESTING_interpreter_next (wrs->is); +} + + +/** + * Run the "refund increase" CMD. + * + * @param cls closure. + * @param cmd command currently being run. + * @param is the interpreter state. + */ +static void +obtain_refunds_run (void *cls, + const struct TALER_TESTING_Command *cmd, + struct TALER_TESTING_Interpreter *is) +{ + struct WalletRefundState *wrs = cls; + const struct TALER_TESTING_Command *proposal_cmd = + TALER_TESTING_interpreter_lookup_command (is, + wrs->proposal_reference); + const struct GNUNET_HashCode *h_contract_terms; + const char *order_id; + + if (NULL == proposal_cmd) + TALER_TESTING_FAIL (is); + if (GNUNET_OK != + TALER_TESTING_get_trait_h_contract_terms (proposal_cmd, + 0, + &h_contract_terms)) + TALER_TESTING_FAIL (is); + + { + const json_t *contract_terms; + const char *error_name; + unsigned int error_line; + + if (GNUNET_OK != + TALER_TESTING_get_trait_contract_terms (proposal_cmd, + 0, + &contract_terms)) + TALER_TESTING_FAIL (is); + { + /* 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_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); + TALER_TESTING_FAIL (is); + } + } + } + + wrs->is = is; + wrs->orh = TALER_MERCHANT_wallet_post_order_refund ( + is->ctx, + wrs->merchant_url, + order_id, + h_contract_terms, + &refund_cb, + wrs); + if (NULL == wrs->orh) + TALER_TESTING_FAIL (is); +} + + +/** + * Free the state of a "refund increase" CMD, and + * possibly cancel a pending "refund increase" operation. + * + * @param cls closure + * @param cmd command currently being freed. + */ +static void +obtain_refunds_cleanup (void *cls, + const struct TALER_TESTING_Command *cmd) +{ + struct WalletRefundState *wrs = cls; + + if (NULL != wrs->orh) + { + TALER_LOG_WARNING ("Refund operation did not complete\n"); + TALER_MERCHANT_wallet_post_order_refund_cancel (wrs->orh); + } + GNUNET_array_grow (wrs->refunds, + wrs->refunds_length, + 0); + GNUNET_free (wrs); +} + + +/** + * Define a "refund order" CMD. + * + * @param label command label. + * @param merchant_url base URL of the backend serving the + * "refund increase" request. + * @param order_ref order id of the contract to refund. + * @param http_code expected HTTP response code. + * @param ... NULL-terminated list of labels (const char *) of + * refunds (commands) we expect to be aggregated in the transfer + * (assuming @a http_code is #MHD_HTTP_OK). If @e refunded is false, + * this parameter is ignored. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_wallet_order_refund (const char *label, + const char *merchant_url, + const char *order_ref, + unsigned int http_code, + ...) +{ + struct WalletRefundState *wrs; + + wrs = GNUNET_new (struct WalletRefundState); + wrs->merchant_url = merchant_url; + wrs->proposal_reference = order_ref; + wrs->http_code = http_code; + wrs->refunds_length = 0; + { + const char *clabel; + va_list ap; + + va_start (ap, http_code); + while (NULL != (clabel = va_arg (ap, const char *))) + { + GNUNET_array_append (wrs->refunds, + wrs->refunds_length, + clabel); + } + va_end (ap); + } + { + struct TALER_TESTING_Command cmd = { + .cls = wrs, + .label = label, + .run = &obtain_refunds_run, + .cleanup = &obtain_refunds_cleanup + }; + + return cmd; + } +} -- cgit v1.2.3