/* This file is part of TALER Copyright (C) 2014-2018 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_track_transaction.c * @brief command to test /track/transaction * @author Marcello Stanisci */ #include "platform.h" #include #include #include "taler_merchant_service.h" #include "taler_merchant_testing_lib.h" /** * State for a "track transaction" CMD. */ struct TrackTransactionState { /** * Handle for a pending /track/transaction request. */ struct TALER_MERCHANT_TrackTransactionHandle *tth; /** * The interpreter state. */ struct TALER_TESTING_Interpreter *is; /** * Base URL of the merchant serving the request. */ const char *merchant_url; /** * Expected HTTP response code. */ unsigned int http_status; /** * Reference to a "pay" CMD, used to get the order * id to issue the track against. */ const char *pay_reference; /** * Subject line of the wire transfer that paid * the tracked contract back. WARNING: impredictible * behaviour if _multiple_ wire transfers were * issued to pay this contract back. */ const char *wtid_str; /** * Binary form of @a wtid_str, expected by other commands * in this form. */ struct TALER_WireTransferIdentifierRawP wtid; /** * base URL of the exchange that issued (or was supposed to, * in case 202 Accepted was returned) the wire transfer to * pay the tracked contract back. */ const char *exchange_url; }; /** * Function called with detailed wire transfer data; checks * if HTTP response code matches the expectation, and stores * in the state what came from the backend. * * @param cls closure * @param hr HTTP response */ static void track_transaction_cb (void *cls, const struct TALER_MERCHANT_HttpResponse *hr) { struct TrackTransactionState *tts = cls; tts->tth = NULL; if (tts->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 (tts->is)); TALER_TESTING_interpreter_fail (tts->is); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "/track/transaction, response code: %u\n", hr->http_status); if (MHD_HTTP_OK == hr->http_status) { /* Only storing first element's wtid, as this works around * the disability of the real bank to provide a "bank check" * CMD as the fakebank does. */ json_t *wtid_str; json_t *exchange_url; if (NULL == (wtid_str = json_object_get (json_array_get (hr->reply, 0), "wtid"))) { TALER_TESTING_interpreter_fail (tts->is); return; } if (NULL == (exchange_url = json_object_get (json_array_get (hr->reply, 0), "exchange"))) { TALER_TESTING_interpreter_fail (tts->is); return; } tts->exchange_url = GNUNET_strdup (json_string_value (exchange_url)); tts->wtid_str = GNUNET_strdup (json_string_value (wtid_str)); } TALER_TESTING_interpreter_next (tts->is); } /** * Run the "track transaction" CMD. * * @param cls closure. * @param cmd command being run now. * @param is interpreter state. */ static void track_transaction_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) { struct TrackTransactionState *tts = cls; const char *order_id; const struct TALER_TESTING_Command *pay_cmd; tts->is = is; if (NULL == (pay_cmd = TALER_TESTING_interpreter_lookup_command (is, tts->pay_reference))) TALER_TESTING_FAIL (is); if (GNUNET_OK != TALER_TESTING_get_trait_order_id (pay_cmd, 0, &order_id)) TALER_TESTING_FAIL (is); tts->tth = TALER_MERCHANT_track_transaction (is->ctx, tts->merchant_url, order_id, &track_transaction_cb, tts); GNUNET_assert (NULL != tts->tth); } /** * Free the state of a "track transaction" CMD, and possibly * cancel a pending operation thereof. * * @param cls closure. * @param cmd command being run. */ static void track_transaction_cleanup (void *cls, const struct TALER_TESTING_Command *cmd) { struct TrackTransactionState *tts = cls; if (NULL != tts->tth) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "/track/transaction (test) operation" " did not complete\n"); TALER_MERCHANT_track_transaction_cancel (tts->tth); } /* Need to discard 'const' before freeing. */ GNUNET_free_non_null ((char *) tts->exchange_url); GNUNET_free_non_null ((char *) tts->wtid_str); GNUNET_free (tts); } /** * Offer internal data of a "track transaction" CMD, for * other CMDs to use. * * @param cls closure. * @param ret[out] return value. * @param trait name of the trait. * @param index index of the trait. * @return #GNUNET_OK if it is successful. */ static int track_transaction_traits (void *cls, const void **ret, const char *trait, unsigned int index) { struct TrackTransactionState *tts = cls; struct TALER_WireTransferIdentifierRawP *wtid_ptr; if (MHD_HTTP_OK != tts->http_status) return GNUNET_SYSERR; if ( (NULL != tts->wtid_str) && (GNUNET_OK != GNUNET_STRINGS_string_to_data (tts->wtid_str, strlen (tts->wtid_str), &tts->wtid, sizeof (struct TALER_WireTransferIdentifierRawP))) ) wtid_ptr = NULL; else wtid_ptr = &tts->wtid; { struct TALER_TESTING_Trait traits[] = { TALER_TESTING_make_trait_wtid (0, wtid_ptr), TALER_TESTING_make_trait_url (0, tts->exchange_url), TALER_TESTING_trait_end () }; return TALER_TESTING_get_trait (traits, ret, trait, index); } } /** * Define a "track transaction" CMD. * * @param label command label. * @param merchant_url base URL of the merchant serving the * /track/transaction request. * @param http_status expected HTTP response code. * @param pay_reference used to retrieve the order id to track. * @return the command. */ struct TALER_TESTING_Command TALER_TESTING_cmd_merchant_track_transaction (const char *label, const char *merchant_url, unsigned int http_status, const char *pay_reference) { struct TrackTransactionState *tts; tts = GNUNET_new (struct TrackTransactionState); tts->merchant_url = merchant_url; tts->http_status = http_status; tts->pay_reference = pay_reference; { struct TALER_TESTING_Command cmd = { .cls = tts, .label = label, .run = &track_transaction_run, .cleanup = &track_transaction_cleanup, .traits = &track_transaction_traits }; return cmd; } } /* end of testing_api_cmd_track_transaction.c */