/* 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_post_reserves.c * @brief command to test POST /reserves * @author Jonathan Buchanan */ #include "platform.h" #include #include #include "taler_merchant_service.h" #include "taler_merchant_testing_lib.h" /** * State of a "POST /reserves" CMD. */ struct PostReservesState { /** * Handle for a "POST /reserves" request. */ struct TALER_MERCHANT_PostReservesHandle *prh; /** * The interpreter state. */ struct TALER_TESTING_Interpreter *is; /** * Base URL of the merchant */ const char *merchant_url; /** * Base URL of the exchange. */ const char *exchange_url; /** * Wire method for the reserve. */ const char *wire_method; /** * The initial balance of the reserve. */ struct TALER_Amount initial_balance; /** * Expected HTTP response code. */ unsigned int http_status; /** * Public key assigned to the reserve */ struct TALER_ReservePublicKeyP reserve_pub; }; /** * Callbacks of this type are used to work the result of submitting a * POST /reserves request to a merchant * * @param cls closure * @param hr HTTP response details * @param reserve_pub public key of the created reserve, NULL on error * @param payto_uri where to make the payment to for filling the reserve, NULL on error */ static void post_reserves_cb (void *cls, const struct TALER_MERCHANT_HttpResponse *hr, const struct TALER_ReservePublicKeyP *reserve_pub, const char *payto_uri) { struct PostReservesState *prs = cls; prs->prh = NULL; if (prs->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 (prs->is)); TALER_TESTING_interpreter_fail (prs->is); return; } switch (hr->http_status) { case MHD_HTTP_NO_CONTENT: break; case MHD_HTTP_CONFLICT: break; case MHD_HTTP_OK: break; // FIXME: add other legitimate states here... default: GNUNET_break (0); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unhandled HTTP status (%d).\n", hr->http_status); } prs->reserve_pub = *reserve_pub; TALER_TESTING_interpreter_next (prs->is); } /** * Offers information from the POST /reserves CMD state 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 post_reserves_traits (void *cls, const void **ret, const char *trait, unsigned int index) { struct PostReservesState *prs = cls; struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_reserve_pub (0, &prs->reserve_pub), TALER_TESTING_make_trait_amount_obj (0, &prs->initial_balance), TALER_TESTING_trait_end (), }; return TALER_TESTING_get_trait (traits, ret, trait, index); } /** * Run the "POST /reserves" CMD. * * @param cls closure. * @param cmd command being run now. * @param is interpreter state. */ static void post_reserves_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) { struct PostReservesState *prs = cls; prs->is = is; prs->prh = TALER_MERCHANT_reserves_post (is->ctx, prs->merchant_url, &prs->initial_balance, prs->exchange_url, prs->wire_method, &post_reserves_cb, prs); GNUNET_assert (NULL != prs->prh); } /** * Run the fake "POST /reserves" CMD. * * @param cls closure. * @param cmd command being run now. * @param is interpreter state. */ static void post_reserves_fake_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) { struct PostReservesState *prs = cls; struct TALER_ReservePrivateKeyP reserve_priv; prs->is = is; GNUNET_CRYPTO_eddsa_key_create (&reserve_priv.eddsa_priv); GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv.eddsa_priv, &prs->reserve_pub.eddsa_pub); GNUNET_assert (GNUNET_OK == TALER_string_to_amount ("EUR:100.00", &prs->initial_balance)); TALER_TESTING_interpreter_next (prs->is); } /** * Free the state of a "POST /reserves" CMD, and possibly * cancel a pending operation thereof. * * @param cls closure. * @param cmd command being run. */ static void post_reserves_cleanup (void *cls, const struct TALER_TESTING_Command *cmd) { struct PostReservesState *prs = cls; if (NULL != prs->prh) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "POST /reserves operation did not complete\n"); TALER_MERCHANT_reserves_post_cancel (prs->prh); } GNUNET_free (prs); } /** * Define a "POST /reserves" CMD * * @param label command label. * @param merchant_url url to the merchant. * @param initial_balance initial amount in the reserve. * @param exchange_url url to the exchange * @param wire_method wire transfer method to use for this reserve * @param http_status expected HTTP response code. * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_merchant_post_reserves (const char *label, const char *merchant_url, const char *initial_balance, const char *exchange_url, const char *wire_method, unsigned int http_status) { struct PostReservesState *prs; prs = GNUNET_new (struct PostReservesState); prs->merchant_url = merchant_url; prs->exchange_url = exchange_url; prs->wire_method = wire_method; prs->http_status = http_status; GNUNET_assert (GNUNET_OK == TALER_string_to_amount (initial_balance, &prs->initial_balance)); { struct TALER_TESTING_Command cmd = { .cls = prs, .label = label, .run = &post_reserves_run, .cleanup = &post_reserves_cleanup, .traits = &post_reserves_traits }; return cmd; } } /** * This commands does not query the backend at all, * but just makes up a fake reserve. * * @param label command label. * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_merchant_post_reserves_fake (const char *label) { struct PostReservesState *prs; prs = GNUNET_new (struct PostReservesState); { struct TALER_TESTING_Command cmd = { .cls = prs, .label = label, .run = &post_reserves_fake_run, .cleanup = &post_reserves_cleanup, .traits = &post_reserves_traits }; return cmd; } }