add retry support to withdraw test logic

This commit is contained in:
Christian Grothoff 2018-08-10 12:39:47 +02:00
parent 04055de75a
commit 866df0fb66
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 106 additions and 1 deletions

View File

@ -24,6 +24,7 @@
*/ */
#include "platform.h" #include "platform.h"
#include "taler_json_lib.h" #include "taler_json_lib.h"
#include <microhttpd.h>
#include <gnunet/gnunet_curl_lib.h> #include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h" #include "exchange_api_handle.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -87,14 +88,61 @@ struct WithdrawState
*/ */
struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh; struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
/**
* Task scheduled to try later.
*/
struct GNUNET_SCHEDULER_Task *retry_task;
/**
* How long do we wait until we retry?
*/
struct GNUNET_TIME_Relative backoff;
/** /**
* Expected HTTP response code to the request. * Expected HTTP response code to the request.
*/ */
unsigned int expected_response_code; unsigned int expected_response_code;
/**
* Was this command modified via
* #TALER_TESTING_cmd_withdraw_with_retry to
* enable retries?
*/
int do_retry;
}; };
/**
* Run the command.
*
* @param cls closure.
* @param cmd the commaind being run.
* @param is interpreter state.
*/
static void
withdraw_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is);
/**
* Task scheduled to re-try #withdraw_run.
*
* @param cls a `struct WithdrawState`
*/
static void
do_retry (void *cls)
{
struct WithdrawState *ws = cls;
ws->retry_task = NULL;
withdraw_run (ws,
NULL,
ws->is);
}
/** /**
* "reserve withdraw" operation callback; checks that the * "reserve withdraw" operation callback; checks that the
* response code is expected and store the exchange signature * response code is expected and store the exchange signature
@ -119,6 +167,24 @@ reserve_withdraw_cb (void *cls,
ws->wsh = NULL; ws->wsh = NULL;
if (ws->expected_response_code != http_status) if (ws->expected_response_code != http_status)
{ {
if (GNUNET_YES == ws->do_retry)
{
if ( (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
(TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS == ec) ||
(TALER_EC_WITHDRAW_RESERVE_UNKNOWN == ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
{
/* on DB conflicts, do not use backoff */
if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
ws->backoff = GNUNET_TIME_UNIT_ZERO;
else
ws->backoff = GNUNET_TIME_STD_BACKOFF (ws->backoff);
ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff,
&do_retry,
ws);
return;
}
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d to command %s in %s:%u\n", "Unexpected response code %u/%d to command %s in %s:%u\n",
http_status, http_status,
@ -164,7 +230,7 @@ reserve_withdraw_cb (void *cls,
* Run the command. * Run the command.
* *
* @param cls closure. * @param cls closure.
* @param cmd the commaind being run. * @param cmd the command being run, NULL when called from #do_retry()
* @param is interpreter state. * @param is interpreter state.
*/ */
static void static void
@ -176,6 +242,7 @@ withdraw_run (void *cls,
struct TALER_ReservePrivateKeyP *rp; struct TALER_ReservePrivateKeyP *rp;
const struct TALER_TESTING_Command *create_reserve; const struct TALER_TESTING_Command *create_reserve;
(void) cmd;
create_reserve = TALER_TESTING_interpreter_lookup_command create_reserve = TALER_TESTING_interpreter_lookup_command
(is, ws->reserve_reference); (is, ws->reserve_reference);
if (NULL == create_reserve) if (NULL == create_reserve)
@ -232,6 +299,11 @@ withdraw_cleanup (void *cls,
TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh); TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh);
ws->wsh = NULL; ws->wsh = NULL;
} }
if (NULL != ws->retry_task)
{
GNUNET_SCHEDULER_cancel (ws->retry_task);
ws->retry_task = NULL;
}
if (NULL != ws->sig.rsa_signature) if (NULL != ws->sig.rsa_signature)
{ {
GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature); GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature);
@ -413,4 +485,25 @@ TALER_TESTING_cmd_withdraw_denomination
return cmd; return cmd;
} }
/**
* Modify a withdraw command to enable retries when the
* reserve is not yet full or we get other transient
* errors from the exchange.
*
* @param cmd a withdraw command
* @return the command with retries enabled
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd)
{
struct WithdrawState *ws;
GNUNET_assert (&withdraw_run == cmd.run);
ws = cmd.cls;
ws->do_retry = GNUNET_YES;
return cmd;
}
/* end of testing_api_cmd_withdraw.c */ /* end of testing_api_cmd_withdraw.c */

View File

@ -736,6 +736,18 @@ TALER_TESTING_cmd_withdraw_denomination
unsigned int expected_response_code); unsigned int expected_response_code);
/**
* Modify a withdraw command to enable retries when the
* reserve is not yet full or we get other transient
* errors from the exchange.
*
* @param cmd a withdraw command
* @return the command with retries enabled
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd);
/** /**
* Create a "wire" command. * Create a "wire" command.
* *