/*
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_tip.c
* @brief command to test the tipping.
* @author Marcello Stanisci
*/
#include "platform.h"
#include
#include
#include "taler_merchant_service.h"
#include "taler_merchant_testing_lib.h"
/**
* State for a /tip-pickup CMD.
*/
struct TipPickupState
{
/**
* Merchant base URL.
*/
const char *merchant_url;
/**
* Exchange base URL.
*/
const char *exchange_url;
/**
* Expected HTTP response code.
*/
unsigned int http_status;
/**
* Reference to a /tip/authorize CMD. This will be used to
* get the tip id to make the request with.
*/
const char *authorize_reference;
/**
* If set to non NULL, it references another pickup CMD
* that will provide all the data which is needed to issue
* the request (like planchet secrets, denomination keys..).
*/
const char *replay_reference;
/**
* Handle to a on-going /tip/pickup request.
*/
struct TALER_MERCHANT_TipPickupOperation *tpo;
/**
* The interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* An array of string-defined amounts that indicates
* which denominations are going to be used to receive
* tips.
*/
const char **amounts;
/**
* The object version of the above @a amounts.
*/
struct TALER_Amount *amounts_obj;
/**
* How many coins are involved in the tipping operation.
*/
unsigned int num_coins;
/**
* The array of denomination keys, in the same order of @a
* amounts.
*/
const struct TALER_EXCHANGE_DenomPublicKey **dks;
/**
* The array of planchet secrets, in the same order of @a
* amounts.
*/
struct TALER_PlanchetSecretsP *psa;
/**
* Temporary data structure of @e num_coins entries for the
* withdraw operations.
*/
struct WithdrawHandle *withdraws;
/**
* Set (by the interpreter) to an array of @a num_coins
* signatures created from the (successful) tip operation.
*/
struct TALER_DenominationSignature *sigs;
/**
* Expected Taler error code (NOTE: this is NOT the HTTP
* response code).
*/
enum TALER_ErrorCode expected_ec;
};
/**
* State for a /tip-query CMD.
*/
struct TipQueryState
{
/**
* The merchant base URL.
*/
const char *merchant_url;
/**
* Expected HTTP response code for this CMD.
*/
unsigned int http_status;
/**
* Which merchant instance is running this CMD.
*/
const char *instance;
/**
* The handle to the current /tip-query request.
*/
struct TALER_MERCHANT_TipQueryOperation *tqo;
/**
* The interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Expected amount to be picked up.
*/
const char *expected_amount_picked_up;
/**
* Expected amount to be tip-authorized.
*/
const char *expected_amount_authorized;
/**
* Amount that is expected to be still available
* from the tip reserve.
*/
const char *expected_amount_available;
};
/**
* State for a /tip-authorize CMD.
*/
struct TipAuthorizeState
{
/**
* Merchant base URL.
*/
const char *merchant_url;
/**
* Expected HTTP response code.
*/
unsigned int http_status;
/**
* Merchant instance running this CMD.
*/
const char *instance;
/**
* Human-readable justification for the
* tip authorization carried on by this CMD.
*/
const char *justification;
/**
* Amount that should be authorized for tipping.
*/
const char *amount;
/**
* Expected Taler error code for this CMD.
*/
enum TALER_ErrorCode expected_ec;
/**
* Base URL of the involved exchange.
*/
const char *exchange_url;
/**
* The tip id; set when the CMD succeeds.
*/
struct GNUNET_HashCode tip_id;
/**
* Expiration date for this tip.
*/
struct GNUNET_TIME_Absolute tip_expiration;
/**
* Handle to the on-going /tip-authorize request.
*/
struct TALER_MERCHANT_TipAuthorizeOperation *tao;
/**
* The interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
/**
* Callback for a /tip-authorize request. Set into the state
* what was returned from the backend (@a tip_id and @a
* tip_expiration).
*
* @param cls closure
* @param http_status HTTP status returned by the merchant backend
* @param ec taler-specific error code
* @param tip_id which tip ID should be used to pickup the tip
* @param tip_expiration when does the tip expire (needs to be
* picked up before this time)
* @param exchange_url at what exchange can the tip be picked up
*/
static void
tip_authorize_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const struct GNUNET_HashCode *tip_id,
struct GNUNET_TIME_Absolute tip_expiration,
const char *exchange_url)
{
struct TipAuthorizeState *tas = cls;
tas->tao = NULL;
if (tas->http_status != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u (%d)"
" to command %s\n",
http_status,
ec,
TALER_TESTING_interpreter_get_current_label
(tas->is));
TALER_TESTING_interpreter_fail (tas->is);
return;
}
if (tas->expected_ec != ec)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected error code %d (%u) to command %s\n",
ec,
http_status,
TALER_TESTING_interpreter_get_current_label
(tas->is));
TALER_TESTING_interpreter_fail (tas->is);
return;
}
if ( (MHD_HTTP_OK == http_status) &&
(TALER_EC_NONE == ec) )
{
if (0 != strcmp (exchange_url,
tas->exchange_url))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected exchange URL %s to command %s\n",
exchange_url,
TALER_TESTING_interpreter_get_current_label
(tas->is));
TALER_TESTING_interpreter_fail (tas->is);
return;
}
tas->tip_id = *tip_id;
tas->tip_expiration = tip_expiration;
}
TALER_TESTING_interpreter_next (tas->is);
}
/**
* Offers information from the /tip-authorize 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
tip_authorize_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct TipAuthorizeState *tas = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_tip_id (0, &tas->tip_id),
TALER_TESTING_trait_end (),
};
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
return GNUNET_SYSERR;
}
/**
* Runs the /tip-authorize CMD
*
* @param cls closure
* @param cmd the CMD representing _this_ command
* @param is interpreter state
*/
static void
tip_authorize_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct TipAuthorizeState *tas = cls;
struct TALER_Amount amount;
tas->is = is;
if (GNUNET_OK != TALER_string_to_amount (tas->amount,
&amount))
TALER_TESTING_FAIL (is);
tas->tao = TALER_MERCHANT_tip_authorize
(is->ctx,
tas->merchant_url,
"http://merchant.com/pickup",
"http://merchant.com/continue",
&amount,
tas->instance,
tas->justification,
tip_authorize_cb,
tas);
GNUNET_assert (NULL != tas->tao);
}
/**
* Run the /tip-authorize CMD, the "fake" version of it.
*
* @param cls closure
* @param cmd the CMD representing _this_ command
* @param is interpreter state *
*/
static void
tip_authorize_fake_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct TipAuthorizeState *tas = cls;
/* Make up a tip id. */
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&tas->tip_id,
sizeof (struct GNUNET_HashCode));
TALER_TESTING_interpreter_next (is);
}
/**
* Free the state from a /tip-authorize CMD, and possibly
* cancel any pending operation.
*
* @param cls closure
* @param cmd the /tip-authorize CMD that is about to be freed.
*/
static void
tip_authorize_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct TipAuthorizeState *tas = cls;
if (NULL != tas->tao)
{
TALER_LOG_WARNING ("Tip-autorize operation"
" did not complete\n");
TALER_MERCHANT_tip_authorize_cancel (tas->tao);
}
GNUNET_free (tas);
}
/**
* Create a /tip-authorize CMD, specifying the Taler error code
* that is expected to be returned by the backend.
*
* @param label this command label
* @param merchant_url the base URL of the merchant that will
* serve the /tip-authorize request.
* @param exchange_url the base URL of the exchange that owns
* the reserve from which the tip is going to be gotten.
* @param http_status the HTTP response code which is expected
* for this operation.
* @param instance which merchant instance is running this CMD.
* @param justification human-readable justification for this
* tip authorization.
* @param amount the amount to authorize for tipping.
* @param ec expected Taler-defined error code.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_authorize_with_ec
(const char *label,
const char *merchant_url,
const char *exchange_url,
unsigned int http_status,
const char *instance,
const char *justification,
const char *amount,
enum TALER_ErrorCode ec)
{
struct TipAuthorizeState *tas;
tas = GNUNET_new (struct TipAuthorizeState);
tas->merchant_url = merchant_url;
tas->exchange_url = exchange_url;
tas->instance = instance;
tas->justification = justification;
tas->amount = amount;
tas->http_status = http_status;
tas->expected_ec = ec;
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = tas,
.run = &tip_authorize_run,
.cleanup = &tip_authorize_cleanup,
.traits = &tip_authorize_traits
};
return cmd;
}
/**
* Create a /tip-authorize CMD.
*
* @param label this command label
* @param merchant_url the base URL of the merchant that will
* serve the /tip-authorize request.
* @param exchange_url the base URL of the exchange that owns
* the reserve from which the tip is going to be gotten.
* @param http_status the HTTP response code which is expected
* for this operation.
* @param instance which merchant instance is running this CMD.
* @param justification human-readable justification for this
* tip authorization.
* @param amount the amount to authorize for tipping.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_authorize (const char *label,
const char *merchant_url,
const char *exchange_url,
unsigned int http_status,
const char *instance,
const char *justification,
const char *amount)
{
struct TipAuthorizeState *tas;
tas = GNUNET_new (struct TipAuthorizeState);
tas->merchant_url = merchant_url;
tas->exchange_url = exchange_url;
tas->instance = instance;
tas->justification = justification;
tas->amount = amount;
tas->http_status = http_status;
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = tas,
.run = &tip_authorize_run,
.cleanup = &tip_authorize_cleanup,
.traits = &tip_authorize_traits
};
return cmd;
}
/**
* Callback to process a GET /tip-query request, it mainly
* checks that what the backend returned matches the command's
* expectations.
*
* @param cls closure
* @param http_status HTTP status code for this request
* @param ec Taler-specific error code
* @param raw raw response body
* @param reserve_expiration when the tip reserve will expire
* @param reserve_pub tip reserve public key
* @param amount_authorized total amount authorized on tip reserve
* @param amount_available total amount still available on
* tip reserve
* @param amount_picked_up total amount picked up from tip reserve
*/
static void
tip_query_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *raw,
struct GNUNET_TIME_Absolute reserve_expiration,
struct TALER_ReservePublicKeyP *reserve_pub,
struct TALER_Amount *amount_authorized,
struct TALER_Amount *amount_available,
struct TALER_Amount *amount_picked_up)
{
struct TipQueryState *tqs = cls;
struct TALER_Amount a;
tqs->tqo = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Tip query callback at command `%s'\n",
TALER_TESTING_interpreter_get_current_label
(tqs->is));
GNUNET_assert (NULL != reserve_pub);
GNUNET_assert (NULL != amount_authorized);
GNUNET_assert (NULL != amount_available);
GNUNET_assert (NULL != amount_picked_up);
if (tqs->expected_amount_available)
{
GNUNET_assert (GNUNET_OK == TALER_string_to_amount
(tqs->expected_amount_available, &a));
TALER_LOG_INFO ("expected available %s, actual %s\n",
TALER_amount_to_string (&a),
TALER_amount_to_string (amount_available));
if (0 != TALER_amount_cmp (amount_available, &a))
TALER_TESTING_FAIL (tqs->is);
}
if (tqs->expected_amount_authorized)
{
GNUNET_assert (GNUNET_OK == TALER_string_to_amount
(tqs->expected_amount_authorized, &a));
TALER_LOG_INFO ("expected authorized %s, actual %s\n",
TALER_amount_to_string (&a),
TALER_amount_to_string (amount_authorized));
if (0 != TALER_amount_cmp (amount_authorized, &a))
TALER_TESTING_FAIL (tqs->is);
}
if (tqs->expected_amount_picked_up)
{
GNUNET_assert (GNUNET_OK == TALER_string_to_amount
(tqs->expected_amount_picked_up, &a));
TALER_LOG_INFO ("expected picked_up %s, actual %s\n",
TALER_amount_to_string (&a),
TALER_amount_to_string (amount_picked_up));
if (0 != TALER_amount_cmp (amount_picked_up, &a))
TALER_TESTING_FAIL (tqs->is);
}
if (tqs->http_status != http_status)
TALER_TESTING_FAIL (tqs->is);
TALER_TESTING_interpreter_next (tqs->is);
}
/**
* Free the state from a /tip-query CMD, and possibly cancel
* a pending /tip-query request.
*
* @param cls closure.
* @param cmd the /tip-query CMD to free.
*/
static void
tip_query_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct TipQueryState *tqs = cls;
if (NULL != tqs->tqo)
{
TALER_LOG_WARNING ("Tip-query operation"
" did not complete\n");
TALER_MERCHANT_tip_query_cancel (tqs->tqo);
}
GNUNET_free (tqs);
}
/**
* Run a /tip-query CMD.
*
* @param cls closure.
* @param cmd the current /tip-query CMD.
* @param is the interpreter state.
*/
static void
tip_query_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct TipQueryState *tqs = cls;
tqs->is = is;
tqs->tqo = TALER_MERCHANT_tip_query (is->ctx,
tqs->merchant_url,
tqs->instance,
&tip_query_cb,
tqs);
GNUNET_assert (NULL != tqs->tqo);
}
/**
* Define a /tip-query CMD equipped with a expected amount.
*
* @param label the command label
* @param merchant_url base URL of the merchant which will
* server the /tip-query request.
* @param http_status expected HTTP response code for the
* /tip-query request.
* @param instance the merchant instance running this CMD.
* @param expected_amount_picked_up expected amount already
* picked up.
* @param expected_amount_authorized expected amount that was
* authorized in the first place.
* @param expected_amount_available expected amount which is
* still available from the tip reserve
* @return the command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_query_with_amounts
(const char *label,
const char *merchant_url,
unsigned int http_status,
const char *instance,
const char *expected_amount_picked_up,
const char *expected_amount_authorized,
const char *expected_amount_available)
{
struct TipQueryState *tqs;
tqs = GNUNET_new (struct TipQueryState);
tqs->merchant_url = merchant_url;
tqs->instance = instance;
tqs->http_status = http_status;
tqs->expected_amount_picked_up = expected_amount_picked_up;
tqs->expected_amount_authorized = expected_amount_authorized;
tqs->expected_amount_available = expected_amount_available;
struct TALER_TESTING_Command cmd = {
.cls = tqs,
.label = label,
.run = &tip_query_run,
.cleanup = &tip_query_cleanup
};
return cmd;
}
/**
* Define a /tip-query CMD.
*
* @param label the command label
* @param merchant_url base URL of the merchant which will
* server the /tip-query request.
* @param http_status expected HTTP response code for the
* /tip-query request.
* @param instance the merchant instance running this CMD.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_query (const char *label,
const char *merchant_url,
unsigned int http_status,
const char *instance)
{
struct TipQueryState *tqs;
tqs = GNUNET_new (struct TipQueryState);
tqs->merchant_url = merchant_url;
tqs->instance = instance;
tqs->http_status = http_status;
struct TALER_TESTING_Command cmd = {
.cls = tqs,
.label = label,
.run = &tip_query_run,
.cleanup = &tip_query_cleanup
};
return cmd;
}
/**
* Internal withdraw handle used when withdrawing tips.
*/
struct WithdrawHandle
{
/**
* Withdraw operation this handle represents.
*/
struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Offset of this withdraw operation in the current
* @e is command.
*/
unsigned int off;
/**
* Internal state of the "pickup" CMD.
*/
struct TipPickupState *tps;
};
/**
* This callback handles the response of a withdraw operation
* from the exchange, that is the final step in getting the tip.
*
* @param cls closure, a `struct WithdrawHandle *`
* @param http_status HTTP response code, #MHD_HTTP_OK (200)
* for successful status request, 0 if the exchange's
* reply is bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param sig signature over the coin, NULL on error
* @param full_response full response from the exchange
* (for logging, in case of errors)
*/
static void
pickup_withdraw_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_DenominationSignature *sig,
const json_t *full_response)
{
struct WithdrawHandle *wh = cls;
struct TALER_TESTING_Interpreter *is = wh->is;
struct TipPickupState *tps = wh->tps;
wh->wsh = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Withdraw operation %u completed with %u (%d)\n",
wh->off,
http_status,
ec);
GNUNET_assert (wh->off < tps->num_coins);
if ( (MHD_HTTP_OK != http_status) ||
(TALER_EC_NONE != ec) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u (%d)"
" to command %s when withdrawing\n",
http_status,
ec,
TALER_TESTING_interpreter_get_current_label (is));
TALER_TESTING_interpreter_fail (is);
return;
}
if (NULL == tps->sigs)
tps->sigs = GNUNET_new_array
(tps->num_coins, struct TALER_DenominationSignature);
GNUNET_assert (NULL == tps->sigs[wh->off].rsa_signature);
tps->sigs[wh->off].rsa_signature
= GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
for (unsigned int i=0; inum_coins; i++)
if (NULL != tps->withdraws[wh->off].wsh)
return; /* still some ops ongoing */
GNUNET_free (tps->withdraws);
tps->withdraws = NULL;
TALER_TESTING_interpreter_next (is);
}
/**
* Callback for a /tip-pickup request, it mainly checks if
* values returned from the backend are as expected, and if so
* (and if the status was 200 OK) proceede with the withdrawal.
*
* @param cls closure
* @param http_status HTTP status returned by the merchant
* backend, "200 OK" on success
* @param ec taler-specific error code
* @param reserve_pub public key of the reserve that made the
* @a reserve_sigs, NULL on error
* @param num_reserve_sigs length of the @a reserve_sigs array,
* 0 on error
* @param reserve_sigs array of signatures authorizing withdrawals,
* NULL on error
* @param json original json response
*/
static void
pickup_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ReservePublicKeyP *reserve_pub,
unsigned int num_reserve_sigs,
const struct TALER_ReserveSignatureP *reserve_sigs,
const json_t *json)
{
struct TipPickupState *tps = cls;
tps->tpo = NULL;
if (http_status != tps->http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u (%d) to command %s\n",
http_status,
ec,
TALER_TESTING_interpreter_get_current_label
(tps->is));
TALER_TESTING_FAIL (tps->is);
}
if (ec != tps->expected_ec)
TALER_TESTING_FAIL (tps->is);
/* Safe to go ahead: http status was expected. */
if ( (MHD_HTTP_OK != http_status) ||
(TALER_EC_NONE != ec) )
{
TALER_TESTING_interpreter_next (tps->is);
return;
}
if (num_reserve_sigs != tps->num_coins)
TALER_TESTING_FAIL (tps->is);
/* pickup successful, now withdraw! */
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Obtained %u signatures for withdrawal"
" from picking up a tip\n",
num_reserve_sigs);
GNUNET_assert (NULL == tps->withdraws);
tps->withdraws = GNUNET_new_array
(num_reserve_sigs, struct WithdrawHandle);
for (unsigned int i=0;iwithdraws[i];
wh->off = i;
wh->is = tps->is;
wh->tps = tps;
GNUNET_assert
( (NULL == wh->wsh) &&
( (NULL == tps->sigs) ||
(NULL == tps->sigs[wh->off].rsa_signature) ) );
wh->wsh = TALER_EXCHANGE_reserve_withdraw2
(tps->is->exchange,
tps->dks[i],
&reserve_sigs[i],
reserve_pub,
&tps->psa[i],
&pickup_withdraw_cb,
wh);
if (NULL == wh->wsh)
TALER_TESTING_FAIL (tps->is);
}
if (0 == num_reserve_sigs)
TALER_TESTING_interpreter_next (tps->is);
}
/**
* Run a /tip-pickup CMD.
*
* @param cls closure
* @param cmd the current /tip-pickup CMD.
* @param is interpreter state.
*/
static void
tip_pickup_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct TipPickupState *tps = cls;
unsigned int num_planchets;
const struct TALER_TESTING_Command *replay_cmd;
const struct TALER_TESTING_Command *authorize_cmd;
const struct GNUNET_HashCode *tip_id;
tps->is = is;
tps->exchange_url = TALER_EXCHANGE_get_base_url (is->exchange);
if (NULL == tps->replay_reference)
{
replay_cmd = NULL;
/* Count planchets. */
for (num_planchets=0;
NULL != tps->amounts[num_planchets];
num_planchets++);
}
else
{
const unsigned int *np;
if ( NULL == /* looking for "parent" tip-pickup command */
( replay_cmd = TALER_TESTING_interpreter_lookup_command
(is, tps->replay_reference)) )
TALER_TESTING_FAIL (is);
if (GNUNET_OK != TALER_TESTING_get_trait_uint
(replay_cmd, 0, &np))
TALER_TESTING_FAIL (is);
num_planchets = *np;
}
if (NULL ==
( authorize_cmd = TALER_TESTING_interpreter_lookup_command
(is, tps->authorize_reference)) )
TALER_TESTING_FAIL (is);
tps->num_coins = num_planchets;
{
struct TALER_PlanchetDetail planchets[num_planchets];
tps->psa = GNUNET_new_array (num_planchets,
struct TALER_PlanchetSecretsP);
tps->dks = GNUNET_new_array
(num_planchets,
const struct TALER_EXCHANGE_DenomPublicKey *);
tps->amounts_obj = GNUNET_new_array
(num_planchets, struct TALER_Amount);
for (unsigned int i=0;iamounts[i], &tps->amounts_obj[i]));
tps->dks[i] = TALER_TESTING_find_pk
(is->keys,
&tps->amounts_obj[i]);
if (NULL == tps->dks[i])
TALER_TESTING_FAIL (is);
TALER_planchet_setup_random (&tps->psa[i]);
}
else
{
if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
(replay_cmd, i, &tps->dks[i]))
TALER_TESTING_FAIL (is);
struct TALER_PlanchetSecretsP *ps;
if (GNUNET_OK != TALER_TESTING_get_trait_planchet_secrets
(replay_cmd, i, &ps))
TALER_TESTING_FAIL (is);
tps->psa[i] = *ps;
}
if (GNUNET_OK != TALER_planchet_prepare (&tps->dks[i]->key,
&tps->psa[i],
&planchets[i]))
TALER_TESTING_FAIL (is);
}
if (GNUNET_OK != TALER_TESTING_get_trait_tip_id
(authorize_cmd, 0, &tip_id))
TALER_TESTING_FAIL (is);
tps->tpo = TALER_MERCHANT_tip_pickup (is->ctx,
tps->merchant_url,
tip_id,
num_planchets,
planchets,
&pickup_cb,
tps);
GNUNET_assert (NULL != tps->tpo);
}
}
/**
* Free a /tip-pickup CMD state, and possibly cancel a
* pending /tip-pickup request.
*
* @param cls closure.
* @param cmd current CMD to be freed.
*/
static void
tip_pickup_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct TipPickupState *tps = cls;
GNUNET_free_non_null (tps->amounts_obj);
GNUNET_free_non_null (tps->dks);
GNUNET_free_non_null (tps->psa);
GNUNET_free_non_null (tps->withdraws);
GNUNET_free_non_null (tps->sigs);
if (NULL != tps->tpo)
{
TALER_LOG_WARNING ("Tip-pickup operation"
" did not complete\n");
TALER_MERCHANT_tip_pickup_cancel (tps->tpo);
}
GNUNET_free (tps);
}
/**
* Offers information from the /tip-pickup 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
tip_pickup_traits (void *cls,
const void **ret,
const char *trait,
unsigned int index)
{
struct TipPickupState *tps = cls;
#define NUM_TRAITS (tps->num_coins * 5) + 2
struct TALER_TESTING_Trait traits[NUM_TRAITS];
for (unsigned int i=0; inum_coins; i++)
{
traits[i] = TALER_TESTING_make_trait_planchet_secrets
(i, &tps->psa[i]);
traits[i + tps->num_coins] =
TALER_TESTING_make_trait_coin_priv
(i, &tps->psa[i].coin_priv);
traits[i + (tps->num_coins * 2)] =
TALER_TESTING_make_trait_denom_pub (i, tps->dks[i]);
traits[i + (tps->num_coins *3)] =
TALER_TESTING_make_trait_denom_sig (i, &tps->sigs[i]);
traits[i + (tps->num_coins *4)] =
TALER_TESTING_make_trait_amount_obj
(i, &tps->amounts_obj[i]);
}
traits[NUM_TRAITS - 2] = TALER_TESTING_make_trait_url
(0, tps->exchange_url);
traits[NUM_TRAITS - 1] = TALER_TESTING_trait_end ();
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
return GNUNET_SYSERR;
}
/**
* Define a /tip-pickup CMD, equipped with the expected error
* code.
*
* @param label the command label
* @param merchant_url base URL of the backend which will serve
* the /tip-pickup request.
* @param http_status expected HTTP response code.
* @param authorize_reference reference to a /tip-autorize CMD
* that offers a tip id to pick up.
* @param amounts array of string-defined amounts that specifies
* which denominations will be accepted for tipping.
* @param exchange connection handle to the exchange that will
* eventually serve the withdraw operation.
* @param ec expected Taler error code.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_pickup_with_ec
(const char *label,
const char *merchant_url,
unsigned int http_status,
const char *authorize_reference,
const char **amounts,
enum TALER_ErrorCode ec)
{
struct TipPickupState *tps;
tps = GNUNET_new (struct TipPickupState);
tps->merchant_url = merchant_url;
tps->authorize_reference = authorize_reference;
tps->amounts = amounts;
tps->http_status = http_status;
tps->expected_ec = ec;
struct TALER_TESTING_Command cmd = {
.cls = tps,
.label = label,
.run = &tip_pickup_run,
.cleanup = &tip_pickup_cleanup,
.traits = &tip_pickup_traits
};
return cmd;
}
/**
* Define a /tip-pickup CMD.
*
* @param label the command label
* @param merchant_url base URL of the backend which will serve
* the /tip-pickup request.
* @param http_status expected HTTP response code.
* @param authorize_reference reference to a /tip-autorize CMD
* that offers a tip id to pick up.
* @param amounts array of string-defined amounts that specifies
* which denominations will be accepted for tipping.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_pickup
(const char *label,
const char *merchant_url,
unsigned int http_status,
const char *authorize_reference,
const char **amounts)
{
struct TipPickupState *tps;
tps = GNUNET_new (struct TipPickupState);
tps->merchant_url = merchant_url;
tps->authorize_reference = authorize_reference;
tps->amounts = amounts;
tps->http_status = http_status;
struct TALER_TESTING_Command cmd = {
.cls = tps,
.label = label,
.run = &tip_pickup_run,
.cleanup = &tip_pickup_cleanup,
.traits = &tip_pickup_traits
};
return cmd;
}
/**
* This commands does not query the backend at all,
* but just makes up a fake authorization id that will
* be subsequently used by the "pick up" CMD in order
* to test against such a case.
*
* @param label command label.
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_tip_authorize_fake (const char *label)
{
struct TipAuthorizeState *tas;
tas = GNUNET_new (struct TipAuthorizeState);
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = tas,
.run = &tip_authorize_fake_run,
.cleanup = &tip_authorize_cleanup,
.traits = &tip_authorize_traits
};
return cmd;
}
/* end of testing_api_cmd_tip.c */