summaryrefslogtreecommitdiff
path: root/src/testing/testing_api_cmd_bank_history_debit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/testing_api_cmd_bank_history_debit.c')
-rw-r--r--src/testing/testing_api_cmd_bank_history_debit.c530
1 files changed, 316 insertions, 214 deletions
diff --git a/src/testing/testing_api_cmd_bank_history_debit.c b/src/testing/testing_api_cmd_bank_history_debit.c
index cb3f68097..1cb7320fa 100644
--- a/src/testing/testing_api_cmd_bank_history_debit.c
+++ b/src/testing/testing_api_cmd_bank_history_debit.c
@@ -92,6 +92,11 @@ struct HistoryState
struct TALER_BANK_DebitHistoryHandle *hh;
/**
+ * Our interpreter.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
* Expected number of results (= rows).
*/
uint64_t results_obtained;
@@ -147,38 +152,155 @@ print_expected (struct History *h,
/**
+ * Closure for command_cb().
+ */
+struct IteratorContext
+{
+ /**
+ * Array of history items to return.
+ */
+ struct History *h;
+
+ /**
+ * Set to the row ID from where on we should actually process history items,
+ * or NULL if we should process all of them.
+ */
+ const uint64_t *row_id_start;
+
+ /**
+ * History state we are working on.
+ */
+ struct HistoryState *hs;
+
+ /**
+ * Current length of the @e h array.
+ */
+ unsigned int total;
+
+ /**
+ * Current write position in @e h array.
+ */
+ unsigned int pos;
+
+ /**
+ * Ok equals True whenever a starting row_id was provided AND was found
+ * among the CMDs, OR no starting row was given in the first place.
+ */
+ bool ok;
+
+};
+
+
+/**
+ * Helper function of build_history() that expands
+ * the history for each relevant command encountered.
+ *
+ * @param[in,out] cls our `struct IteratorContext`
+ * @param cmd a command to process
+ */
+static void
+command_cb (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct IteratorContext *ic = cls;
+ struct HistoryState *hs = ic->hs;
+
+ const uint64_t *row_id;
+ const char *debit_account;
+ const char *credit_account;
+ const struct TALER_Amount *amount;
+ const struct TALER_WireTransferIdentifierRawP *wtid;
+ const char *exchange_base_url;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking if command %s is relevant for debit history\n",
+ cmd->label);
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_bank_row (cmd,
+ &row_id)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_debit_payto_uri (cmd,
+ &debit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_credit_payto_uri (cmd,
+ &credit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount (cmd,
+ &amount)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_wtid (cmd,
+ &wtid)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_exchange_url (cmd,
+ &exchange_base_url)) )
+ return; /* not an event we care about */
+ /* Seek "/history/outgoing" starting row. */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Command %s is relevant for debit history!\n",
+ cmd->label);
+ if ( (NULL != ic->row_id_start) &&
+ (*(ic->row_id_start) == *row_id) &&
+ (! ic->ok) )
+ {
+ /* Until here, nothing counted. */
+ ic->ok = true;
+ return;
+ }
+ /* when 'start' was _not_ given, then ok == GNUNET_YES */
+ if (! ic->ok)
+ return; /* skip until we find the marker */
+ if (ic->total >= GNUNET_MAX (hs->num_results,
+ -hs->num_results) )
+ {
+ TALER_LOG_DEBUG ("Hit history limit\n");
+ return;
+ }
+ TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
+ debit_account,
+ credit_account,
+ hs->account_url);
+ /* found matching record, make sure we have room */
+ if (ic->pos == ic->total)
+ GNUNET_array_grow (ic->h,
+ ic->total,
+ ic->pos * 2);
+ ic->h[ic->pos].c_url = GNUNET_strdup (credit_account);
+ ic->h[ic->pos].d_url = GNUNET_strdup (debit_account);
+ ic->h[ic->pos].details.credit_account_uri = ic->h[ic->pos].c_url;
+ ic->h[ic->pos].details.amount = *amount;
+ ic->h[ic->pos].row_id = *row_id;
+ ic->h[ic->pos].details.wtid = *wtid;
+ ic->h[ic->pos].details.exchange_base_url = exchange_base_url;
+ ic->pos++;
+}
+
+
+/**
* This function constructs the list of history elements that
* interest the account number of the caller. It has two main
* loops: the first to figure out how many history elements have
* to be allocated, and the second to actually populate every
* element.
*
- * @param is interpreter state (supposedly having the
- * current CMD pointing at a "history" CMD).
+ * @param hs history state command context
* @param[out] rh history array to initialize.
* @return number of entries in @a rh.
*/
static unsigned int
-build_history (struct TALER_TESTING_Interpreter *is,
+build_history (struct HistoryState *hs,
struct History **rh)
{
- struct HistoryState *hs = is->commands[is->ip].cls;
- unsigned int total;
- unsigned int pos;
- struct History *h;
- const struct TALER_TESTING_Command *add_incoming_cmd;
- int inc;
- int start;
- int end;
- /* #GNUNET_YES whenever either no 'start' value was given for the history
- * query, or the given value is found in the list of all the CMDs. */
- int ok;
- const uint64_t *row_id_start = NULL;
+ struct TALER_TESTING_Interpreter *is = hs->is;
+ struct IteratorContext ic = {
+ .hs = hs
+ };
if (NULL != hs->start_row_reference)
{
- TALER_LOG_INFO
- ("`%s': start row given via reference `%s'\n",
+ const struct TALER_TESTING_Command *add_incoming_cmd;
+
+ TALER_LOG_INFO (
+ "`%s': start row given via reference `%s'\n",
TALER_TESTING_interpreter_get_current_label (is),
hs->start_row_reference);
add_incoming_cmd = TALER_TESTING_interpreter_lookup_command (
@@ -187,124 +309,91 @@ build_history (struct TALER_TESTING_Interpreter *is,
GNUNET_assert (NULL != add_incoming_cmd);
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_row (add_incoming_cmd,
- &row_id_start));
+ &ic.row_id_start));
}
+ ic.ok = false;
+ if (NULL == ic.row_id_start)
+ ic.ok = true;
+ GNUNET_array_grow (ic.h,
+ ic.total,
+ 4);
GNUNET_assert (0 != hs->num_results);
- if (0 == is->ip)
- {
- TALER_LOG_DEBUG ("Checking history at first CMD..\n");
- *rh = NULL;
- return 0;
- }
+ TALER_TESTING_iterate (is,
+ hs->num_results > 0,
+ &command_cb,
+ &ic);
+ GNUNET_assert (ic.ok);
+ GNUNET_array_grow (ic.h,
+ ic.total,
+ ic.pos);
+ if (0 == ic.pos)
+ TALER_LOG_DEBUG ("Empty credit history computed\n");
+ *rh = ic.h;
+ return ic.pos;
+}
- /* AKA 'delta' */
- if (hs->num_results > 0)
- {
- inc = 1; /* _inc_rement: go forwards */
- start = 0;
- end = is->ip;
- }
+
+/**
+ * Normalize IBAN-based payto URI in @a in.
+ *
+ * @param in input payto://-URI to normalize
+ * @return normalized IBAN for the test
+ */
+static char *
+normalize (const char *in)
+{
+ char *npt;
+ const char *q = strchr (in,
+ '?');
+ const char *mptr;
+ const char *bic;
+ const char *iban;
+
+ if (NULL == q)
+ npt = GNUNET_strdup (in);
else
+ npt = GNUNET_strndup (in,
+ q - in);
+ if (0 != strncasecmp (npt,
+ "payto://",
+ strlen ("payto://")))
{
- inc = -1; /* decrement: we go backwards */
- start = is->ip - 1;
- end = -1; /* range is exclusive, do look at 0! */
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Invalid payto: %s\n",
+ npt);
+ GNUNET_free (npt);
+ return NULL;
}
-
- ok = GNUNET_NO;
- if (NULL == row_id_start)
- ok = GNUNET_YES;
- h = NULL;
- total = 0;
- GNUNET_array_grow (h,
- total,
- 4);
- pos = 0;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checking commands %u to %u for debit history\n",
- start,
- end);
- for (int off = start; off != end; off += inc)
+ mptr = npt + strlen ("payto://");
+ bic = strchr (mptr, '/');
+ if (NULL == bic)
{
- const struct TALER_TESTING_Command *cmd = &is->commands[off];
- const uint64_t *row_id;
- const char **debit_account;
- const char **credit_account;
- const struct TALER_Amount *amount;
- const struct TALER_WireTransferIdentifierRawP *wtid;
- const char **exchange_base_url;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checking if command %s is relevant for debit history\n",
- cmd->label);
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_bank_row (cmd,
- &row_id)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_debit_payto_uri (cmd,
- &debit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_credit_payto_uri (cmd,
- &credit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_amount (cmd,
- &amount)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_wtid (cmd,
- &wtid)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_exchange_url (cmd,
- &exchange_base_url)) )
- continue; /* not an event we care about */
- /* Seek "/history/outgoing" starting row. */
+ GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Command %s is relevant for debit history!\n",
- cmd->label);
- if ( (NULL != row_id_start) &&
- (*row_id_start == *row_id) &&
- (GNUNET_NO == ok) )
- {
- /* Until here, nothing counted. */
- ok = GNUNET_YES;
- continue;
- }
- /* when 'start' was _not_ given, then ok == GNUNET_YES */
- if (GNUNET_NO == ok)
- continue; /* skip until we find the marker */
- if (total >= GNUNET_MAX (hs->num_results,
- -hs->num_results) )
- {
- TALER_LOG_DEBUG ("Hit history limit\n");
- break;
- }
- TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
- *debit_account,
- *credit_account,
- hs->account_url);
- /* found matching record, make sure we have room */
- if (pos == total)
- GNUNET_array_grow (h,
- total,
- pos * 2);
- h[pos].c_url = GNUNET_strdup (*credit_account);
- h[pos].d_url = GNUNET_strdup (*debit_account);
- h[pos].details.credit_account_uri = h[pos].c_url;
- h[pos].details.debit_account_uri = h[pos].d_url;
- h[pos].details.amount = *amount;
- h[pos].row_id = *row_id;
- h[pos].details.wtid = *wtid;
- h[pos].details.exchange_base_url = *exchange_base_url;
- pos++;
+ "Invalid payto: %s\n",
+ npt);
+ GNUNET_free (npt);
+ return NULL;
}
- GNUNET_assert (GNUNET_YES == ok);
- GNUNET_array_grow (h,
- total,
- pos);
- if (0 == pos)
- TALER_LOG_DEBUG ("Empty debit history computed\n");
- *rh = h;
- return total;
+ bic++;
+ iban = strchr (bic, '/');
+ if (NULL != iban)
+ {
+ /* need to remove bic */
+ char *n;
+
+ iban++;
+ GNUNET_asprintf (&n,
+ "payto://%.*s/%s",
+ (int) ((bic - mptr) - 1),
+ mptr,
+ iban);
+ GNUNET_free (npt);
+ npt = n;
+ }
+ return npt;
}
@@ -325,6 +414,9 @@ check_result (struct History *h,
unsigned int off,
const struct TALER_BANK_DebitDetails *details)
{
+ char *u1;
+ char *u2;
+
if (off >= total)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -337,14 +429,33 @@ check_result (struct History *h,
off);
return GNUNET_SYSERR;
}
+ u1 = normalize (h[off].details.credit_account_uri);
+ if (NULL == u1)
+ return GNUNET_SYSERR;
+ u2 = normalize (details->credit_account_uri);
+ if (NULL == u2)
+ {
+ GNUNET_free (u1);
+ return GNUNET_SYSERR;
+ }
if ( (0 != GNUNET_memcmp (&h[off].details.wtid,
&details->wtid)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
- (0 != strcasecmp (h[off].details.credit_account_uri,
- details->credit_account_uri)) )
+ (0 != strcasecmp (u1,
+ u2)) )
{
GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "expected debit_account_uri: %s with %s for %s\n",
+ u1,
+ TALER_amount2s (&h[off].details.amount),
+ TALER_B2S (&h[off].details.wtid));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "actual debit_account_uri: %s with %s for %s\n",
+ u2,
+ TALER_amount2s (&details->amount),
+ TALER_B2S (&details->wtid));
print_expected (h,
total,
off);
@@ -362,99 +473,86 @@ check_result (struct History *h,
* finally check it against what the bank returned.
*
* @param cls closure.
- * @param http_status HTTP response code, #MHD_HTTP_OK (200)
- * for successful status request 0 if the bank's reply is
- * bogus (fails to follow the protocol),
- * #MHD_HTTP_NO_CONTENT if there are no more results; on
- * success the last callback is always of this status
- * (even if `abs(num_results)` were already returned).
- * @param ec taler status code.
- * @param row_id monotonically increasing counter corresponding to
- * the transaction.
- * @param details details about the wire transfer.
- * @param json detailed response from the HTTPD, or NULL if
- * reply was not in JSON.
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
+ * @param dhr http response details
*/
-static enum GNUNET_GenericReturnValue
+static void
history_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t row_id,
- const struct TALER_BANK_DebitDetails *details,
- const json_t *json)
+ const struct TALER_BANK_DebitHistoryResponse *dhr)
{
- struct TALER_TESTING_Interpreter *is = cls;
- struct HistoryState *hs = is->commands[is->ip].cls;
+ struct HistoryState *hs = cls;
+ struct TALER_TESTING_Interpreter *is = hs->is;
- (void) row_id;
- if (NULL == details)
+ hs->hh = NULL;
+ switch (dhr->http_status)
{
- hs->hh = NULL;
- if ( (MHD_HTTP_NOT_FOUND == http_status) &&
- (0 == hs->total) )
+ case 0:
+ GNUNET_break (0);
+ goto error;
+ case MHD_HTTP_OK:
+ for (unsigned int i = 0; i<dhr->details.ok.details_length; i++)
+ {
+ const struct TALER_BANK_DebitDetails *dd =
+ &dhr->details.ok.details[i];
+
+ /* check current element */
+ if (GNUNET_OK !=
+ check_result (hs->h,
+ hs->total,
+ hs->results_obtained,
+ dd))
+ {
+ GNUNET_break (0);
+ json_dumpf (dhr->response,
+ stderr,
+ JSON_COMPACT);
+ hs->failed = true;
+ hs->hh = NULL;
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ hs->results_obtained++;
+ }
+ TALER_TESTING_interpreter_next (is);
+ return;
+ case MHD_HTTP_NO_CONTENT:
+ if (0 == hs->total)
{
/* not found is OK for empty history */
TALER_TESTING_interpreter_next (is);
- return GNUNET_OK;
+ return;
}
- if ( (hs->results_obtained != hs->total) ||
- (GNUNET_YES == hs->failed) ||
- (MHD_HTTP_NO_CONTENT != http_status) )
+ GNUNET_break (0);
+ goto error;
+ case MHD_HTTP_NOT_FOUND:
+ if (0 == hs->total)
{
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history of length %u, got %llu;"
- " HTTP status code: %u/%d, failed: %d\n",
- hs->total,
- (unsigned long long) hs->results_obtained,
- http_status,
- (int) ec,
- hs->failed);
- print_expected (hs->h,
- hs->total,
- UINT_MAX);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
+ /* not found is OK for empty history */
+ TALER_TESTING_interpreter_next (is);
+ return;
}
- TALER_TESTING_interpreter_next (is);
- return GNUNET_OK;
- }
- if (MHD_HTTP_OK != http_status)
- {
- hs->hh = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unwanted response code from /history/outgoing: %u\n",
- http_status);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
-
- /* check current element */
- if (GNUNET_OK !=
- check_result (hs->h,
- hs->total,
- hs->results_obtained,
- details))
- {
- char *acc;
-
GNUNET_break (0);
- acc = json_dumps (json,
- JSON_COMPACT);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Result %u was `%s'\n",
- (unsigned int) hs->results_obtained++,
- acc);
- if (NULL != acc)
- free (acc);
- hs->failed = GNUNET_YES;
+ goto error;
+ default:
hs->hh = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unwanted response code from /history/incoming: %u\n",
+ dhr->http_status);
TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
+ return;
}
- hs->results_obtained++;
- return GNUNET_OK;
+error:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history of length %u, got %llu;"
+ " HTTP status code: %u/%d, failed: %d\n",
+ hs->total,
+ (unsigned long long) hs->results_obtained,
+ dhr->http_status,
+ (int) dhr->ec,
+ hs->failed ? 1 : 0);
+ print_expected (hs->h,
+ hs->total,
+ UINT_MAX);
+ TALER_TESTING_interpreter_fail (is);
}
@@ -475,6 +573,7 @@ history_run (void *cls,
const uint64_t *row_ptr;
(void) cmd;
+ hs->is = is;
/* Get row_id from trait. */
if (NULL != hs->start_row_reference)
{
@@ -495,14 +594,16 @@ history_run (void *cls,
TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
(unsigned long long) row_id);
}
- hs->total = build_history (is, &hs->h);
- hs->hh = TALER_BANK_debit_history (is->ctx,
- &hs->auth,
- row_id,
- hs->num_results,
- GNUNET_TIME_UNIT_ZERO,
- &history_cb,
- is);
+ hs->total = build_history (hs,
+ &hs->h);
+ hs->hh = TALER_BANK_debit_history (
+ TALER_TESTING_interpreter_get_context (is),
+ &hs->auth,
+ row_id,
+ hs->num_results,
+ GNUNET_TIME_UNIT_ZERO,
+ &history_cb,
+ hs);
GNUNET_assert (NULL != hs->hh);
}
@@ -523,7 +624,8 @@ history_cleanup (void *cls,
(void) cmd;
if (NULL != hs->hh)
{
- TALER_LOG_WARNING ("/history/outgoing did not complete\n");
+ TALER_TESTING_command_incomplete (hs->is,
+ cmd->label);
TALER_BANK_debit_history_cancel (hs->hh);
}
for (unsigned int off = 0; off<hs->total; off++)