/history-range.

Implementing the "lib" and "testing-lib" functions to use it.
This commit is contained in:
Marcello Stanisci 2019-04-08 23:53:52 +02:00
parent 5ec20870a4
commit ed0da1fdb3
No known key found for this signature in database
GPG Key ID: 8D526861953F4C0F
11 changed files with 653 additions and 128 deletions

View File

@ -79,6 +79,7 @@ handle_admin_add_incoming_finished (void *cls,
{ {
struct TALER_BANK_AdminAddIncomingHandle *aai = cls; struct TALER_BANK_AdminAddIncomingHandle *aai = cls;
uint64_t row_id = UINT64_MAX; uint64_t row_id = UINT64_MAX;
struct GNUNET_TIME_Absolute timestamp;
enum TALER_ErrorCode ec; enum TALER_ErrorCode ec;
const json_t *j = response; const json_t *j = response;
@ -93,6 +94,8 @@ handle_admin_add_incoming_finished (void *cls,
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_uint64 ("row_id", GNUNET_JSON_spec_uint64 ("row_id",
&row_id), &row_id),
GNUNET_JSON_spec_absolute_time ("timestamp",
&timestamp),
GNUNET_JSON_spec_end() GNUNET_JSON_spec_end()
}; };
@ -148,6 +151,7 @@ handle_admin_add_incoming_finished (void *cls,
response_code, response_code,
ec, ec,
row_id, row_id,
timestamp,
j); j);
TALER_BANK_admin_add_incoming_cancel (aai); TALER_BANK_admin_add_incoming_cancel (aai);
} }

View File

@ -2,22 +2,26 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2017 GNUnet e.V. & Inria Copyright (C) 2017 GNUnet e.V. & Inria
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or
terms of the GNU General Public License as published by the Free Software modify it under the terms of the GNU General Public License
Foundation; either version 3, or (at your option) any later version. 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 TALER is distributed in the hope that it will be useful,
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR but WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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 You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not,
<http://www.gnu.org/licenses/> see <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file bank-lib/bank_api_history.c * @file bank-lib/bank_api_history.c
* @brief Implementation of the /history requests of the bank's HTTP API * @brief Implementation of the /history[-range]
* requests of the bank's HTTP API.
* @author Christian Grothoff * @author Christian Grothoff
* @author Marcello Stanisci
*/ */
#include "platform.h" #include "platform.h"
#include "bank_api_common.h" #include "bank_api_common.h"
@ -60,7 +64,23 @@ struct TALER_BANK_HistoryHandle
* Closure for @a cb. * Closure for @a cb.
*/ */
void *hcb_cls; void *hcb_cls;
};
/**
* Represent a URL argument+value pair.
*/
struct HistoryArgumentURL
{
/**
* Name of the URL argument.
*/
char argument[20];
/**
* Value of the URL argument.
*/
char value[20];
}; };
@ -248,101 +268,39 @@ handle_history_finished (void *cls,
} }
/** /**
* Request the wire transfer history of a bank account. * Backend of both the /history[-range] requests.
* *
* @param ctx curl context for the event loop * @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this request) * @param bank_base_url base URL of the bank.
* @param urlargs path + URL arguments.
* @param auth authentication data to use * @param auth authentication data to use
* @param account_number which account number should we query * @param hres_cb the callback to call with the transaction
* @param direction what kinds of wire transfers should be returned * history
* @param ascending if GNUNET_YES, history elements will be returned in chronological order.
* @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive
* @param num_results how many results do we want; negative numbers to go into the past,
* positive numbers to go into the future starting at @a start_row;
* must not be zero.
* @param hres_cb the callback to call with the transaction history
* @param hres_cb_cls closure for the above callback * @param hres_cb_cls closure for the above callback
* @return NULL * @return NULL if the inputs are invalid (i.e. zero value for
* if the inputs are invalid (i.e. zero value for @e num_results). * @e num_results). In this case, the callback is not
* In this case, the callback is not called. * called.
*/ */
struct TALER_BANK_HistoryHandle * static struct TALER_BANK_HistoryHandle *
TALER_BANK_history (struct GNUNET_CURL_Context *ctx, put_history_job (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url, const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth, const char *urlargs,
uint64_t account_number, const struct TALER_BANK_AuthenticationData *auth,
enum TALER_BANK_Direction direction, TALER_BANK_HistoryResultCallback hres_cb,
unsigned int ascending, void *hres_cb_cls)
uint64_t start_row,
int64_t num_results,
TALER_BANK_HistoryResultCallback hres_cb,
void *hres_cb_cls)
{ {
struct TALER_BANK_HistoryHandle *hh; struct TALER_BANK_HistoryHandle *hh;
CURL *eh; CURL *eh;
char *url;
const char *dir;
const char *can;
if (0 == num_results)
{
GNUNET_break (0);
return NULL;
}
if (TALER_BANK_DIRECTION_NONE == direction)
{
GNUNET_break (0);
return NULL;
}
dir = NULL;
if (TALER_BANK_DIRECTION_BOTH == (TALER_BANK_DIRECTION_BOTH & direction))
dir = "both";
else if (TALER_BANK_DIRECTION_CREDIT == (TALER_BANK_DIRECTION_CREDIT & direction))
dir = "credit";
else if (TALER_BANK_DIRECTION_DEBIT == (TALER_BANK_DIRECTION_BOTH & direction))
dir = "debit";
if (NULL == dir)
{
GNUNET_break (0);
return NULL;
}
if (TALER_BANK_DIRECTION_CANCEL == (TALER_BANK_DIRECTION_CANCEL & direction))
can = "show";
else
can = "omit";
if (UINT64_MAX == start_row)
{
GNUNET_asprintf (&url,
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s",
(unsigned long long) account_number,
(long long) num_results,
dir,
can,
(GNUNET_YES == ascending) ? "ascending" : "descending");
}
else
{
GNUNET_asprintf (&url,
"/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s&cancelled=%s&ordering=%s",
(unsigned long long) account_number,
(long long) num_results,
(unsigned long long) start_row,
dir,
can,
(GNUNET_YES == ascending) ? "ascending" : "descending");
}
hh = GNUNET_new (struct TALER_BANK_HistoryHandle); hh = GNUNET_new (struct TALER_BANK_HistoryHandle);
hh->hcb = hres_cb; hh->hcb = hres_cb;
hh->hcb_cls = hres_cb_cls; hh->hcb_cls = hres_cb_cls;
hh->bank_base_url = GNUNET_strdup (bank_base_url); hh->bank_base_url = GNUNET_strdup (bank_base_url);
hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, hh->request_url = TALER_BANK_path_to_url_ (bank_base_url,
url); urlargs);
GNUNET_free (url);
hh->authh = TALER_BANK_make_auth_header_ (auth); hh->authh = TALER_BANK_make_auth_header_ (auth);
eh = curl_easy_init (); eh = curl_easy_init ();
GNUNET_assert (CURLE_OK == GNUNET_assert (CURLE_OK ==
@ -363,8 +321,201 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
/** /**
* Cancel a history request. This function cannot be used on a request * Convert fixed value 'direction' into string.
* handle if a response is already served for it. *
* @param direction the value to convert.
* @return string representation of @a direction. When length
* is zero, an error occurred.
*/
static struct HistoryArgumentURL
conv_direction (enum TALER_BANK_Direction direction)
{
struct HistoryArgumentURL ret;
if (TALER_BANK_DIRECTION_NONE == direction)
{
/* Should just never happen. */
GNUNET_assert (0);
return ret;
}
if (TALER_BANK_DIRECTION_BOTH ==
(TALER_BANK_DIRECTION_BOTH & direction))
strcpy (&ret.value[0],
"both");
else if (TALER_BANK_DIRECTION_CREDIT ==
(TALER_BANK_DIRECTION_CREDIT & direction))
strcpy (&ret.value[0],
"credit");
else if (TALER_BANK_DIRECTION_DEBIT ==
(TALER_BANK_DIRECTION_BOTH & direction)) /*why use 'both' flag?*/
strcpy (&ret.value[0],
"debit");
return ret;
}
/**
* Convert fixed value 'direction' into string representation
* of the "cancel" argument.
*
* @param direction the value to convert.
* @return string representation of @a direction. When length
* is zero, an error occurred.
*/
static struct HistoryArgumentURL
conv_cancel (enum TALER_BANK_Direction direction)
{
struct HistoryArgumentURL ret;
if (TALER_BANK_DIRECTION_CANCEL ==
(TALER_BANK_DIRECTION_CANCEL & direction))
strcpy (&ret.value[0],
"show");
else
strcpy (&ret.value[0],
"omit");
return ret;
}
/**
* Request the wire transfer history of a bank account,
* using time stamps to narrow the results.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this
* request)
* @param auth authentication data to use
* @param account_number which account number should we query
* @param direction what kinds of wire transfers should be
* returned
* @param ascending if GNUNET_YES, history elements will
* be returned in chronological order.
* @param start_date threshold for oldest result.
* @param end_date threshold for youngest result.
* @param hres_cb the callback to call with the transaction
* history
* @param hres_cb_cls closure for the above callback
* @return NULL if the inputs are invalid (i.e. zero value for
* @e num_results). In this case, the callback is not
* called.
*/
struct TALER_BANK_HistoryHandle *
TALER_BANK_history_range (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
enum TALER_BANK_Direction direction,
unsigned int ascending,
struct GNUNET_TIME_Absolute start_date,
struct GNUNET_TIME_Absolute end_date,
TALER_BANK_HistoryResultCallback hres_cb,
void *hres_cb_cls)
{
struct TALER_BANK_HistoryHandle *hh;
char *url;
GNUNET_TIME_round_abs (&start_date);
GNUNET_TIME_round_abs (&end_date);
GNUNET_asprintf (&url,
"/history?auth=basic&account_number=%llu&start=%llu&end=%llu&direction=%s&cancelled=%s&ordering=%s",
(unsigned long long) account_number,
start_date.abs_value_us / 1000LL / 1000LL,
end_date.abs_value_us / 1000LL / 1000LL,
conv_direction (direction).value,
conv_cancel (direction).value,
(GNUNET_YES == ascending) ? "ascending" : "descending");
hh = put_history_job (ctx,
bank_base_url,
url,
auth,
hres_cb,
hres_cb_cls);
GNUNET_free (url);
return hh;
}
/**
* Request the wire transfer history of a bank account.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this
* request)
* @param auth authentication data to use
* @param account_number which account number should we query
* @param direction what kinds of wire transfers should be
* returned
* @param ascending if GNUNET_YES, history elements will
* be returned in chronological order.
* @param start_row from which row on do we want to get results,
* use UINT64_MAX for the latest; exclusive
* @param num_results how many results do we want;
* negative numbers to go into the past, positive numbers
* to go into the future starting at @a start_row;
* must not be zero.
* @param hres_cb the callback to call with the transaction
* history
* @param hres_cb_cls closure for the above callback
* @return NULL if the inputs are invalid (i.e. zero value for
* @e num_results). In this case, the callback is not
* called.
*/
struct TALER_BANK_HistoryHandle *
TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
enum TALER_BANK_Direction direction,
unsigned int ascending,
uint64_t start_row,
int64_t num_results,
TALER_BANK_HistoryResultCallback hres_cb,
void *hres_cb_cls)
{
struct TALER_BANK_HistoryHandle *hh;
char *url;
if (0 == num_results)
{
GNUNET_break (0);
return NULL;
}
GNUNET_asprintf (&url,
"/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s&start=%llu",
(unsigned long long) account_number,
(long long) num_results,
conv_direction (direction).value,
conv_cancel (direction).value,
(GNUNET_YES == ascending) ? "ascending" : "descending",
start_row);
/* Locate and "cut" the 'start' argument,
* if the user didn't provide one. */
if (UINT64_MAX == start_row)
*strstr (url, "&start=") = '\0';
hh = put_history_job (ctx,
bank_base_url,
url,
auth,
hres_cb,
hres_cb_cls);
GNUNET_free (url);
return hh;
}
/**
* Cancel a history request. This function cannot be
* used on a request handle if a response is already
* served for it.
* *
* @param hh the history request handle * @param hh the history request handle
*/ */

View File

@ -160,11 +160,12 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,
struct Transaction *t; struct Transaction *t;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Making transfer from %llu to %llu over %s and subject %s\n", "Making transfer from %llu to %llu over %s and subject %s; for exchange: %s\n",
(unsigned long long) debit_account, (unsigned long long) debit_account,
(unsigned long long) credit_account, (unsigned long long) credit_account,
TALER_amount2s (amount), TALER_amount2s (amount),
subject); subject,
exchange_base_url);
t = GNUNET_new (struct Transaction); t = GNUNET_new (struct Transaction);
t->debit_account = debit_account; t->debit_account = debit_account;
t->credit_account = credit_account; t->credit_account = credit_account;
@ -463,9 +464,11 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
void *json_str; void *json_str;
size_t json_len; size_t json_len;
json = json_pack ("{s:I}", json = json_pack ("{s:I, s:s}",
"row_id", "row_id",
(json_int_t) row_id); (json_int_t) row_id,
"timestamp", "/Date(0)/"); /*dummy tmp */
json_str = json_dumps (json, json_str = json_dumps (json,
JSON_INDENT(2)); JSON_INDENT(2));
json_decref (json); json_decref (json);

View File

@ -530,6 +530,7 @@ next (struct InterpreterState *is)
* 0 if the bank's reply is bogus (fails to follow the protocol) * 0 if the bank's reply is bogus (fails to follow the protocol)
* @param ec taler status code * @param ec taler status code
* @param row_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error * @param row_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param timestamp time stamp of when the transaction settled at the bank
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
*/ */
static void static void
@ -537,6 +538,7 @@ add_incoming_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec, enum TALER_ErrorCode ec,
uint64_t row_id, uint64_t row_id,
struct GNUNET_TIME_Absolute timestamp,
const json_t *json) const json_t *json)
{ {
struct InterpreterState *is = cls; struct InterpreterState *is = cls;

View File

@ -90,6 +90,27 @@ struct HistoryState
* chronological order. * chronological order.
*/ */
unsigned int ascending; unsigned int ascending;
/**********************************
* Following defs are specific to *
* the "/history-range" version. *
**********************************/
/**
* Last row number we want in the result. Only used
* as a trait source when using the /history-range API.
*/
const char *end_row_reference;
/**
* Start date for /history-range.
*/
struct GNUNET_TIME_Absolute start_date;
/**
* End date for /history-range.
*/
struct GNUNET_TIME_Absolute end_date;
}; };
/** /**
@ -669,6 +690,8 @@ history_cb (void *cls,
struct TALER_TESTING_Interpreter *is = cls; struct TALER_TESTING_Interpreter *is = cls;
struct HistoryState *hs = is->commands[is->ip].cls; struct HistoryState *hs = is->commands[is->ip].cls;
/* Possibly we got the 204 status code
* as a "end of list" marker. */
if (MHD_HTTP_OK != http_status) if (MHD_HTTP_OK != http_status)
{ {
hs->hh = NULL; hs->hh = NULL;
@ -710,7 +733,7 @@ history_cb (void *cls,
JSON_COMPACT); JSON_COMPACT);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Result %u was `%s'\n", "Result %u was `%s'\n",
(unsigned int) hs->results_obtained, (unsigned int) hs->results_obtained++,
acc); acc);
if (NULL != acc) if (NULL != acc)
free (acc); free (acc);
@ -758,7 +781,6 @@ history_run (void *cls,
TALER_LOG_DEBUG ("row id (from trait) is %llu\n", TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
(unsigned long long) row_id); (unsigned long long) row_id);
} }
auth = &AUTHS[hs->account_no - 1]; auth = &AUTHS[hs->account_no - 1];
@ -776,6 +798,81 @@ history_run (void *cls,
} }
/**
* Run the command.
*
* @param cls closure.
* @param cmd the command to execute.
* @param is the interpreter state.
*/
static void
history_range_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct HistoryState *hs = cls;
const struct GNUNET_TIME_Absolute *start_date;
const struct GNUNET_TIME_Absolute *end_date;
struct TALER_BANK_AuthenticationData *auth;
if (NULL != hs->start_row_reference)
{
const struct TALER_TESTING_Command *history_cmd;
history_cmd = TALER_TESTING_interpreter_lookup_command
(is, hs->start_row_reference);
if (NULL == history_cmd)
TALER_TESTING_FAIL (is);
if (GNUNET_OK != TALER_TESTING_get_trait_absolute_time
(history_cmd, 0, &start_date))
TALER_TESTING_FAIL (is);
}
else
{
GNUNET_assert (UINT64_MAX != hs->start_date.abs_value_us);
start_date = &hs->start_date;
}
if (NULL != hs->end_row_reference)
{
const struct TALER_TESTING_Command *history_cmd;
history_cmd = TALER_TESTING_interpreter_lookup_command
(is, hs->end_row_reference);
if (NULL == history_cmd)
TALER_TESTING_FAIL (is);
if (GNUNET_OK != TALER_TESTING_get_trait_absolute_time
(history_cmd, 0, &end_date))
TALER_TESTING_FAIL (is);
}
else
{
GNUNET_assert (UINT64_MAX != hs->end_date.abs_value_us);
end_date = &hs->end_date;
}
auth = &AUTHS[hs->account_no - 1];
hs->hh = TALER_BANK_history_range (is->ctx,
hs->bank_url,
auth,
hs->account_no,
hs->direction,
hs->ascending,
*start_date,
*end_date,
&history_cb,
is);
GNUNET_assert (NULL != hs->hh);
}
/** /**
* Free the state from a "history" CMD, and possibly cancel * Free the state from a "history" CMD, and possibly cancel
* a pending operation thereof. * a pending operation thereof.
@ -848,4 +945,112 @@ TALER_TESTING_cmd_bank_history
return cmd; return cmd;
} }
/**
* Make a "history-range" CMD, picking dates from traits.
*
* @param label command label.
* @param bank_url base URL of the bank offering the "history"
* operation.
* @param account_no bank account number to ask the history for.
* @param direction which direction this operation is interested.
* @param ascending if GNUNET_YES, the bank will return the rows
* in ascending (= chronological) order.
* @param start_row_reference reference to a command that can
* offer a absolute time to use as the 'start' argument
* for "/history-range".
* @param end_row_reference reference to a command that can
* offer a absolute time to use as the 'end' argument
* for "/history-range".
* @param num_result how many rows we want in the result.
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_history_range
(const char *label,
const char *bank_url,
uint64_t account_no,
enum TALER_BANK_Direction direction,
unsigned int ascending,
const char *start_row_reference,
const char *end_row_reference,
long long num_results)
{
struct HistoryState *hs;
hs = GNUNET_new (struct HistoryState);
hs->bank_url = bank_url;
hs->account_no = account_no;
hs->direction = direction;
hs->start_row_reference = start_row_reference;
hs->end_row_reference = end_row_reference;
hs->num_results = num_results;
hs->ascending = ascending;
hs->start_date = GNUNET_TIME_UNIT_FOREVER_ABS;
hs->end_date = GNUNET_TIME_UNIT_FOREVER_ABS;
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = hs,
.run = &history_range_run,
.cleanup = &history_cleanup,
.traits = &history_traits
};
return cmd;
}
/**
* Make a "history-range" CMD, picking dates from the arguments.
*
* @param label command label.
* @param bank_url base URL of the bank offering the "history"
* operation.
* @param account_no bank account number to ask the history for.
* @param direction which direction this operation is interested.
* @param ascending if GNUNET_YES, the bank will return the rows
* in ascending (= chronological) order.
* @param start_date value for the 'start' argument
* of "/history-range".
* @param end_date value for the 'end' argument
* of "/history-range".
* @param num_result how many rows we want in the result.
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_bank_history_range_with_dates
(const char *label,
const char *bank_url,
uint64_t account_no,
enum TALER_BANK_Direction direction,
unsigned int ascending,
struct GNUNET_TIME_Absolute start_date,
struct GNUNET_TIME_Absolute end_date,
long long num_results)
{
struct HistoryState *hs;
hs = GNUNET_new (struct HistoryState);
hs->bank_url = bank_url;
hs->account_no = account_no;
hs->direction = direction;
hs->num_results = num_results;
hs->ascending = ascending;
hs->start_date = start_date;
hs->end_date = start_date;
struct TALER_TESTING_Command cmd = {
.label = label,
.cls = hs,
.run = &history_range_run,
.cleanup = &history_cleanup,
.traits = &history_traits
};
return cmd;
}
/* end of testing_api_cmd_history.c */ /* end of testing_api_cmd_history.c */

View File

@ -101,6 +101,7 @@ struct TALER_BANK_AdminAddIncomingHandle;
* 0 if the bank's reply is bogus (fails to follow the protocol) * 0 if the bank's reply is bogus (fails to follow the protocol)
* @param ec detailed error code * @param ec detailed error code
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param timestamp time when the transaction was made.
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON * @param json detailed response from the HTTPD, or NULL if reply was not in JSON
*/ */
typedef void typedef void
@ -108,6 +109,7 @@ typedef void
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec, enum TALER_ErrorCode ec,
uint64_t serial_id, uint64_t serial_id,
struct GNUNET_TIME_Absolute timestamp,
const json_t *json); const json_t *json);
@ -281,6 +283,41 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,
void *hres_cb_cls); void *hres_cb_cls);
/**
* Request the wire transfer history of a bank account,
* using time stamps to narrow the results.
*
* @param ctx curl context for the event loop
* @param bank_base_url URL of the bank (used to execute this
* request)
* @param auth authentication data to use
* @param account_number which account number should we query
* @param direction what kinds of wire transfers should be
* returned
* @param ascending if GNUNET_YES, history elements will
* be returned in chronological order.
* @param start_date threshold for oldest result.
* @param end_date threshold for youngest result.
* @param hres_cb the callback to call with the transaction
* history
* @param hres_cb_cls closure for the above callback
* @return NULL if the inputs are invalid (i.e. zero value for
* @e num_results). In this case, the callback is not
* called.
*/
struct TALER_BANK_HistoryHandle *
TALER_BANK_history_range (struct GNUNET_CURL_Context *ctx,
const char *bank_base_url,
const struct TALER_BANK_AuthenticationData *auth,
uint64_t account_number,
enum TALER_BANK_Direction direction,
unsigned int ascending,
struct GNUNET_TIME_Absolute start_date,
struct GNUNET_TIME_Absolute end_date,
TALER_BANK_HistoryResultCallback hres_cb,
void *hres_cb_cls);
/** /**
* Cancel an history request. This function cannot be used on a request * Cancel an history request. This function cannot be used on a request
* handle if the last response (anything with a status code other than * handle if the last response (anything with a status code other than

View File

@ -654,8 +654,9 @@ struct TALER_TESTING_SetupContext
* @return #GNUNET_OK if no errors occurred. * @return #GNUNET_OK if no errors occurred.
*/ */
int int
TALER_TESTING_setup_with_exchange_cfg (void *cls, TALER_TESTING_setup_with_exchange_cfg
const struct GNUNET_CONFIGURATION_Handle *cfg); (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg);
/** /**
@ -681,22 +682,23 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
/** /**
* Initialize scheduler loop and curl context for the test case * Initialize scheduler loop and curl context for the test case
* including starting and stopping the auditor and exchange using the * including starting and stopping the auditor and exchange using
* given configuration file. * the given configuration file.
* *
* @param cls must be a `struct TALER_TESTING_SetupContext *` * @param cls must be a `struct TALER_TESTING_SetupContext *`
* @param cfg configuration to use. * @param cfg configuration to use.
* @return #GNUNET_OK if no errors occurred. * @return #GNUNET_OK if no errors occurred.
*/ */
int int
TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls, TALER_TESTING_setup_with_auditor_and_exchange_cfg
const struct GNUNET_CONFIGURATION_Handle *cfg); (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg);
/** /**
* Initialize scheduler loop and curl context for the test case * Initialize scheduler loop and curl context for the test case
* including starting and stopping the auditor and exchange using the * including starting and stopping the auditor and exchange using
* given configuration file. * the given configuration file.
* *
* @param main_cb main method. * @param main_cb main method.
* @param main_cb_cls main method closure. * @param main_cb_cls main method closure.
@ -709,12 +711,10 @@ TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls,
* @return #GNUNET_OK if no errors occurred. * @return #GNUNET_OK if no errors occurred.
*/ */
int int
TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb, TALER_TESTING_setup_with_auditor_and_exchange
void *main_cb_cls, (TALER_TESTING_Main main_cb,
const char *config_file); void *main_cb_cls,
const char *config_file);
/* ************** Specific interpreter commands ************ */ /* ************** Specific interpreter commands ************ */
@ -872,14 +872,15 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance
/** /**
* Modify a fakebank transfer command to enable retries when the * Modify a fakebank transfer command to enable retries when the
* reserve is not yet full or we get other transient errors from the * reserve is not yet full or we get other transient errors from
* fakebank. * the fakebank.
* *
* @param cmd a fakebank transfer command * @param cmd a fakebank transfer command
* @return the command with retries enabled * @return the command with retries enabled
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_retry (struct TALER_TESTING_Command cmd); TALER_TESTING_cmd_fakebank_transfer_retry
(struct TALER_TESTING_Command cmd);
/** /**
@ -1020,7 +1021,8 @@ TALER_TESTING_cmd_withdraw_denomination
* @return the command with retries enabled * @return the command with retries enabled
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd); TALER_TESTING_cmd_withdraw_with_retry
(struct TALER_TESTING_Command cmd);
/** /**
@ -1098,7 +1100,8 @@ TALER_TESTING_cmd_deposit
* @return the command with retries enabled * @return the command with retries enabled
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd); TALER_TESTING_cmd_deposit_with_retry
(struct TALER_TESTING_Command cmd);
/** /**
@ -1148,7 +1151,8 @@ TALER_TESTING_cmd_refresh_melt_double
* @return modified command. * @return modified command.
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd); TALER_TESTING_cmd_refresh_melt_with_retry
(struct TALER_TESTING_Command cmd);
/** /**
@ -2407,4 +2411,32 @@ TALER_TESTING_get_trait_cmd
struct TALER_TESTING_Command **_cmd); struct TALER_TESTING_Command **_cmd);
/**
* Obtain a absolute time from @a cmd.
*
* @param cmd command to extract trait from
* @param index which time stamp to pick if
* @a cmd has multiple on offer.
* @param time[out] set to the wanted WTID.
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_absolute_time
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
const struct GNUNET_TIME_Absolute **time);
/**
* Offer a absolute time.
*
* @param index associate the object with this index
* @param time which object should be returned
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_absolute_time
(unsigned int index,
const struct GNUNET_TIME_Absolute *time);
#endif #endif

View File

@ -107,7 +107,8 @@ libtalertesting_la_SOURCES = \
testing_api_trait_key_peer.c \ testing_api_trait_key_peer.c \
testing_api_trait_wtid.c \ testing_api_trait_wtid.c \
testing_api_trait_amount.c \ testing_api_trait_amount.c \
testing_api_trait_cmd.c testing_api_trait_cmd.c \
testing_api_trait_time.c
libtalertesting_la_LIBADD = \ libtalertesting_la_LIBADD = \
libtalerexchange.la \ libtalerexchange.la \
$(top_builddir)/src/wire/libtalerwire.la \ $(top_builddir)/src/wire/libtalerwire.la \

View File

@ -101,6 +101,11 @@ struct FakebankTransferState
*/ */
uint64_t serial_id; uint64_t serial_id;
/**
* Timestamp of the transaction (as returned from the bank).
*/
struct GNUNET_TIME_Absolute timestamp;
/** /**
* Exchange URL. This value is fed to the bank when requesting * Exchange URL. This value is fed to the bank when requesting
* the wire transfer; note: the bank needs it because a merchant * the wire transfer; note: the bank needs it because a merchant
@ -182,6 +187,7 @@ do_retry (void *cls)
* bogus (fails to follow the protocol) * bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success * @param ec taler-specific error code, #TALER_EC_NONE on success
* @param serial_id unique ID of the wire transfer * @param serial_id unique ID of the wire transfer
* @param timestamp time stamp of the transaction made.
* @param full_response full response from the exchange (for * @param full_response full response from the exchange (for
* logging, in case of errors) * logging, in case of errors)
*/ */
@ -190,13 +196,13 @@ add_incoming_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec, enum TALER_ErrorCode ec,
uint64_t serial_id, uint64_t serial_id,
struct GNUNET_TIME_Absolute timestamp,
const json_t *full_response) const json_t *full_response)
{ {
struct FakebankTransferState *fts = cls; struct FakebankTransferState *fts = cls;
struct TALER_TESTING_Interpreter *is = fts->is; struct TALER_TESTING_Interpreter *is = fts->is;
fts->aih = NULL; fts->aih = NULL;
fts->serial_id = serial_id;
if (MHD_HTTP_OK != http_status) if (MHD_HTTP_OK != http_status)
{ {
if (GNUNET_YES == fts->do_retry) if (GNUNET_YES == fts->do_retry)
@ -205,18 +211,20 @@ add_incoming_cb (void *cls,
(TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) || (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
(MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) ) (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log
"Retrying fakebank transfer failed with %u/%d\n", (GNUNET_ERROR_TYPE_INFO,
http_status, "Retrying fakebank transfer failed with %u/%d\n",
(int) ec); http_status,
(int) ec);
/* on DB conflicts, do not use backoff */ /* on DB conflicts, do not use backoff */
if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
fts->backoff = GNUNET_TIME_UNIT_ZERO; fts->backoff = GNUNET_TIME_UNIT_ZERO;
else else
fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff); fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
fts->retry_task = GNUNET_SCHEDULER_add_delayed (fts->backoff, fts->retry_task = GNUNET_SCHEDULER_add_delayed
&do_retry, (fts->backoff,
fts); &do_retry,
fts);
return; return;
} }
} }
@ -228,6 +236,9 @@ add_incoming_cb (void *cls,
TALER_TESTING_interpreter_fail (is); TALER_TESTING_interpreter_fail (is);
return; return;
} }
fts->serial_id = serial_id;
fts->timestamp = timestamp;
TALER_TESTING_interpreter_next (is); TALER_TESTING_interpreter_next (is);
} }
@ -422,7 +433,7 @@ fakebank_transfer_traits (void *cls,
unsigned int index) unsigned int index)
{ {
struct FakebankTransferState *fts = cls; struct FakebankTransferState *fts = cls;
#define MANDATORY 6 #define MANDATORY 7
struct TALER_TESTING_Trait traits[MANDATORY + 1] = { struct TALER_TESTING_Trait traits[MANDATORY + 1] = {
TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT
(&fts->debit_account_no), (&fts->debit_account_no),
@ -431,6 +442,7 @@ fakebank_transfer_traits (void *cls,
TALER_TESTING_make_trait_url (0, fts->exchange_url), TALER_TESTING_make_trait_url (0, fts->exchange_url),
TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id), TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id),
TALER_TESTING_make_trait_amount_obj (0, &fts->amount), TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp)
}; };
/** /**

View File

@ -0,0 +1,76 @@
/*
This file is part of TALER
Copyright (C) 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
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_trait_time.c
* @brief traits to offer time stamps.
* @author Marcello Stanisci
*/
#include "platform.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "taler_testing_lib.h"
#define TALER_TESTING_TRAIT_TIME_ABS "time-abs"
/**
* Obtain a absolute time from @a cmd.
*
* @param cmd command to extract trait from
* @param index which time stamp to pick if
* @a cmd has multiple on offer.
* @param time[out] set to the wanted WTID.
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_absolute_time
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
const struct GNUNET_TIME_Absolute **time)
{
return cmd->traits (cmd->cls,
(const void **) time,
TALER_TESTING_TRAIT_TIME_ABS,
index);
}
/**
* Offer a absolute time.
*
* @param index associate the object with this index
* @param time which object should be returned
* @return the trait.
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_absolute_time
(unsigned int index,
const struct GNUNET_TIME_Absolute *time)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_TIME_ABS,
.ptr = (const void *) time
};
return ret;
}
/* end of testing_api_trait_time.c */

View File

@ -619,6 +619,7 @@ taler_bank_prepare_wire_transfer (void *cls,
* 0 if the bank's reply is bogus (fails to follow the protocol) * 0 if the bank's reply is bogus (fails to follow the protocol)
* @param ec error code from the bank * @param ec error code from the bank
* @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error
* @param timestamp time when the transfer was settled by the bank.
* @param json detailed response from the HTTPD, or NULL if reply was not JSON * @param json detailed response from the HTTPD, or NULL if reply was not JSON
*/ */
static void static void
@ -626,6 +627,7 @@ execute_cb (void *cls,
unsigned int http_status, unsigned int http_status,
enum TALER_ErrorCode ec, enum TALER_ErrorCode ec,
uint64_t serial_id, uint64_t serial_id,
struct GNUNET_TIME_Absolute timestamp,
const json_t *json) const json_t *json)
{ {
struct TALER_WIRE_ExecuteHandle *eh = cls; struct TALER_WIRE_ExecuteHandle *eh = cls;