summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcello Stanisci <stanisci.m@gmail.com>2018-02-22 14:51:12 +0100
committerMarcello Stanisci <stanisci.m@gmail.com>2018-02-26 14:12:46 +0100
commitb593d416d6e788b2053c2f5ebb634e0bb39fe560 (patch)
treecf08a83fb1922c32d4a0e4ce161ae3ff20023a69 /src
parent8d5cc9f550da58610ad220d72f21d930c47ad0a8 (diff)
downloadexchange-b593d416d6e788b2053c2f5ebb634e0bb39fe560.tar.gz
exchange-b593d416d6e788b2053c2f5ebb634e0bb39fe560.tar.bz2
exchange-b593d416d6e788b2053c2f5ebb634e0bb39fe560.zip
Bank-lib tests, using the new (libraries-based) style.
Diffstat (limited to 'src')
-rw-r--r--src/bank-lib/Makefile.am43
-rw-r--r--src/bank-lib/bank.conf6
-rw-r--r--src/bank-lib/test_bank_api_new.c185
-rw-r--r--src/bank-lib/test_bank_api_with_fakebank_new.c223
-rw-r--r--src/bank-lib/testing_api_cmd_history.c735
-rw-r--r--src/bank-lib/testing_api_cmd_reject.c164
-rw-r--r--src/bank-lib/testing_api_helpers.c205
-rw-r--r--src/exchange-lib/testing_api_cmd_bank_check.c108
-rw-r--r--src/exchange-lib/testing_api_cmd_fakebank_transfer.c19
-rw-r--r--src/exchange-lib/testing_api_cmd_track.c2
-rw-r--r--src/exchange-lib/testing_api_helpers.c5
-rw-r--r--src/exchange-lib/testing_api_loop.c49
-rw-r--r--src/exchange-lib/testing_api_trait_amount.c2
-rw-r--r--src/exchange-lib/testing_api_trait_number.c49
-rw-r--r--src/exchange-lib/testing_api_trait_string.c50
-rw-r--r--src/include/Makefile.am3
-rw-r--r--src/include/taler_testing_bank_lib.h108
-rw-r--r--src/include/taler_testing_lib.h108
18 files changed, 2005 insertions, 59 deletions
diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am
index 967d95ed3..bd1c7e8b1 100644
--- a/src/bank-lib/Makefile.am
+++ b/src/bank-lib/Makefile.am
@@ -21,7 +21,8 @@ taler_bank_transfer_LDADD = \
lib_LTLIBRARIES = \
libtalerbank.la \
- libtalerfakebank.la
+ libtalerfakebank.la \
+ libtalerbanktesting.la
libtalerbank_la_LDFLAGS = \
-version-info 1:0:0 \
@@ -41,7 +42,6 @@ libtalerbank_la_LIBADD = \
-ljansson \
$(XLIB)
-
libtalerfakebank_la_LDFLAGS = \
-version-info 0:0:0 \
-no-undefined
@@ -57,6 +57,22 @@ libtalerfakebank_la_LIBADD = \
-lmicrohttpd \
$(XLIB)
+libtalerbanktesting_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+
+libtalerbanktesting_la_SOURCES = \
+ testing_api_cmd_history.c \
+ testing_api_cmd_reject.c \
+ testing_api_helpers.c
+
+libtalerbanktesting_la_LIBADD = \
+ $(top_builddir)/src/json/libtalerjson.la \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ -lmicrohttpd \
+ $(XLIB)
if HAVE_LIBCURL
libtalerbank_la_LIBADD += -lcurl
@@ -68,7 +84,9 @@ endif
check_PROGRAMS = \
test_bank_api \
- test_bank_api_with_fakebank
+ test_bank_api_new \
+ test_bank_api_with_fakebank \
+ test_bank_api_with_fakebank_new
TESTS = \
$(check_PROGRAMS)
@@ -84,6 +102,15 @@ test_bank_api_LDADD = \
-lgnunetutil \
-ljansson
+test_bank_api_new_SOURCES = \
+ test_bank_api_new.c
+
+test_bank_api_new_LDADD = \
+ $(top_builddir)/src/exchange-lib/libtalertesting.la \
+ libtalerbanktesting.la \
+ -ltalerexchange \
+ -lgnunetutil \
+ libtalerbank.la
test_bank_api_with_fakebank_SOURCES = \
test_bank_interpreter.c test_bank_interpreter.h \
@@ -96,5 +123,15 @@ test_bank_api_with_fakebank_LDADD = \
-lgnunetutil \
-ljansson
+test_bank_api_with_fakebank_new_SOURCES = \
+ test_bank_api_with_fakebank_new.c
+
+test_bank_api_with_fakebank_new_LDADD = \
+ $(top_builddir)/src/exchange-lib/libtalertesting.la \
+ libtalerbanktesting.la \
+ -ltalerexchange \
+ -lgnunetutil \
+ libtalerbank.la
+
EXTRA_DIST = \
bank.conf
diff --git a/src/bank-lib/bank.conf b/src/bank-lib/bank.conf
index 0610606cc..f6e4e7fe0 100644
--- a/src/bank-lib/bank.conf
+++ b/src/bank-lib/bank.conf
@@ -1,2 +1,8 @@
[taler]
currency = KUDOS
+
+[bank]
+http_port = 8081
+
+[exchange-wire-test]
+bank_url = http://localhost:8081/
diff --git a/src/bank-lib/test_bank_api_new.c b/src/bank-lib/test_bank_api_new.c
new file mode 100644
index 000000000..a43aa876f
--- /dev/null
+++ b/src/bank-lib/test_bank_api_new.c
@@ -0,0 +1,185 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016, 2017 GNUnet e.V.
+
+ 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 bank/test_bank_api_new.c
+ * @brief testcase to test bank's HTTP API
+ * interface against the "real" bank
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_bank_service.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include <microhttpd.h>
+#include "taler_exchange_service.h"
+#include "test_bank_interpreter.h"
+#include "taler_testing_lib.h"
+#include "taler_testing_bank_lib.h"
+
+#define CONFIG_FILE "bank.conf"
+
+/**
+ * Bank process.
+ */
+struct GNUNET_OS_Process *bankd;
+
+/**
+ * Bank URL.
+ */
+char *bank_url;
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+
+ extern struct TALER_BANK_AuthenticationData AUTHS[];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Bank serves at `%s'\n",
+ bank_url);
+
+ struct TALER_TESTING_Command commands[] = {
+
+ /**
+ * NOTE: this command uses internally the _fakebank_ version
+ * of the add-incoming command. However, this does seem to
+ * work fine against the Python bank too! Some renaming is
+ * required..
+ */
+ TALER_TESTING_cmd_bank_history ("history-0",
+ bank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_BOTH,
+ NULL,
+ 5),
+
+ /* WARNING: old API has expected http response code among
+ * the parameters, although it was always set as '200 OK' */
+ TALER_TESTING_cmd_fakebank_transfer_with_subject
+ ("deposit-1",
+ "KUDOS:5.01",
+ bank_url,
+ BANK_ACCOUNT_NUMBER,
+ EXCHANGE_ACCOUNT_NUMBER,
+ AUTHS[BANK_ACCOUNT_NUMBER -1].details.basic.username,
+ AUTHS[BANK_ACCOUNT_NUMBER -1].details.basic.password,
+ "subject 1",
+ "http://exchange.com/"),
+
+ TALER_TESTING_cmd_fakebank_transfer_with_subject
+ ("deposit-2",
+ "KUDOS:5.01",
+ bank_url,
+ BANK_ACCOUNT_NUMBER,
+ EXCHANGE_ACCOUNT_NUMBER,
+ AUTHS[BANK_ACCOUNT_NUMBER -1].details.basic.username,
+ AUTHS[BANK_ACCOUNT_NUMBER -1].details.basic.password,
+ "subject 2",
+ "http://exchange.com/"),
+
+ TALER_TESTING_cmd_bank_history ("history-1c",
+ bank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_CREDIT,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_bank_history ("history-1d",
+ bank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_DEBIT,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_bank_history ("history-1dr",
+ bank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_DEBIT,
+ NULL,
+ -5),
+
+ TALER_TESTING_cmd_bank_history ("history-2fwd",
+ bank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_DEBIT,
+ "deposit-1",
+ 5),
+
+ TALER_TESTING_cmd_bank_reject ("reject-1",
+ bank_url,
+ "deposit-1"),
+ /**
+ * End the suite. Fixme: better to have a label for this
+ * too, as it shows a "(null)" token on logs.
+ */
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is, commands);
+}
+
+
+/* Pacifies "make check" */
+int
+main(int argc,
+ char * const *argv)
+{
+ unsigned int ret;
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test-bank-api-new", "DEBUG", NULL);
+
+ if (NULL ==
+ (bank_url = TALER_TESTING_prepare_bank (CONFIG_FILE)))
+ return 77;
+
+ if (NULL == (bankd =
+ TALER_TESTING_run_bank (CONFIG_FILE)))
+ return 1;
+
+ ret = TALER_TESTING_setup (&run,
+ NULL,
+ CONFIG_FILE,
+ NULL); // means no exchange.
+
+ GNUNET_OS_process_kill (bankd, SIGKILL);
+ GNUNET_OS_process_wait (bankd);
+ GNUNET_OS_process_destroy (bankd);
+ GNUNET_free (bank_url);
+
+ if (GNUNET_OK == ret)
+ return 0;
+
+ return 1;
+}
+
+/* end of test_bank_api_new.c */
diff --git a/src/bank-lib/test_bank_api_with_fakebank_new.c b/src/bank-lib/test_bank_api_with_fakebank_new.c
new file mode 100644
index 000000000..a36251c5e
--- /dev/null
+++ b/src/bank-lib/test_bank_api_with_fakebank_new.c
@@ -0,0 +1,223 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016, 2017 GNUnet e.V.
+
+ 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 bank/test_bank_api_with_fakebank.c
+ * @brief testcase to test bank's HTTP API
+ * interface against the fakebank
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_bank_service.h"
+#include "taler_exchange_service.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include <microhttpd.h>
+#include "test_bank_interpreter.h"
+#include "taler_testing_lib.h"
+#include "taler_testing_bank_lib.h"
+
+
+#define CONFIG_FILE "bank.conf"
+
+
+/**
+ * Fakebank URL.
+ */
+char *fakebank_url;
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Fakebank serves at `%s'\n",
+ fakebank_url);
+ extern struct TALER_BANK_AuthenticationData AUTHS[];
+
+ struct TALER_TESTING_Command commands[] = {
+
+ /**
+ * NOTE: this command uses internally the _fakebank_ version
+ * of the add-incoming command. However, this does seem to
+ * work fine against the Python bank too! Some renaming is
+ * required..
+ */
+ TALER_TESTING_cmd_bank_history ("history-0",
+ fakebank_url,
+ BANK_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_BOTH,
+ NULL,
+ 1),
+
+
+ /* WARNING: old API has expected http response code among
+ * the parameters, although it was always set as '200 OK' */
+ TALER_TESTING_cmd_fakebank_transfer_with_subject
+ ("debit-1",
+ "KUDOS:5.01",
+ fakebank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ BANK_ACCOUNT_NUMBER,
+ AUTHS[EXCHANGE_ACCOUNT_NUMBER -1].details.basic.username,
+ AUTHS[EXCHANGE_ACCOUNT_NUMBER -1].details.basic.password,
+ "subject 1",
+ "http://exchange.com/"),
+
+ TALER_TESTING_cmd_bank_history ("history-1c",
+ fakebank_url,
+ BANK_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_CREDIT,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_bank_history ("history-1d",
+ fakebank_url,
+ BANK_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_DEBIT,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_fakebank_transfer_with_subject
+ ("debit-2",
+ "KUDOS:3.21",
+ fakebank_url,
+ EXCHANGE_ACCOUNT_NUMBER, // debit account.
+ USER_ACCOUNT_NUMBER,
+ AUTHS[EXCHANGE_ACCOUNT_NUMBER -1].details.basic.username,
+ AUTHS[EXCHANGE_ACCOUNT_NUMBER -1].details.basic.password,
+ "subject 2",
+ "http://exchange.org/"),
+
+ TALER_TESTING_cmd_fakebank_transfer_with_subject
+ ("credit-2",
+ "KUDOS:3.22",
+ fakebank_url,
+ USER_ACCOUNT_NUMBER, // debit account.
+ EXCHANGE_ACCOUNT_NUMBER,
+ AUTHS[USER_ACCOUNT_NUMBER -1].details.basic.username,
+ AUTHS[USER_ACCOUNT_NUMBER -1].details.basic.password,
+ "credit 2",
+ "http://exchange.org/"),
+
+ TALER_TESTING_cmd_bank_history ("history-2b",
+ fakebank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_BOTH,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_bank_history ("history-2bi",
+ fakebank_url,
+ EXCHANGE_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_BOTH,
+ "debit-1",
+ 5),
+
+ TALER_TESTING_cmd_check_bank_transfer_with_ref ("expect-2d",
+ "credit-2"),
+
+ TALER_TESTING_cmd_check_bank_transfer_with_ref ("expect-2c",
+ "debit-2"),
+
+ TALER_TESTING_cmd_check_bank_transfer_with_ref ("expect-1",
+ "debit-1"),
+
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty"),
+
+ TALER_TESTING_cmd_fakebank_transfer_with_subject
+ ("credit-for-reject-1",
+ "KUDOS:5.01",
+ fakebank_url,
+ BANK_ACCOUNT_NUMBER,
+ EXCHANGE_ACCOUNT_NUMBER,
+ AUTHS[BANK_ACCOUNT_NUMBER -1].details.basic.username,
+ AUTHS[BANK_ACCOUNT_NUMBER -1].details.basic.password,
+ "subject 3",
+ "http://exchange.net/"),
+
+ TALER_TESTING_cmd_bank_reject ("reject-1",
+ fakebank_url,
+ "credit-for-reject-1"),
+
+ TALER_TESTING_cmd_bank_history ("history-r1",
+ fakebank_url,
+ BANK_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_BOTH,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_bank_history ("history-r1c",
+ fakebank_url,
+ BANK_ACCOUNT_NUMBER,
+ TALER_BANK_DIRECTION_BOTH |
+ TALER_BANK_DIRECTION_CANCEL,
+ NULL,
+ 5),
+
+ TALER_TESTING_cmd_check_bank_transfer_with_ref
+ ("expect-credit-reject-1",
+ "credit-for-reject-1"),
+
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-2"),
+
+ /**
+ * End the suite. Fixme: better to have a label for this
+ * too, as it shows a "(null)" token on logs.
+ */
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ fakebank_url);
+}
+
+int
+main (int argc,
+ char * const *argv)
+{
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test-merchant-api-with-fakebank-new",
+ "DEBUG",
+ NULL);
+ if (NULL ==
+ (fakebank_url = TALER_TESTING_prepare_fakebank (CONFIG_FILE)))
+ return 77;
+
+ return (GNUNET_OK == TALER_TESTING_setup (&run,
+ NULL,
+ CONFIG_FILE,
+ NULL)) ? 0 : 1;
+}
+
+
+/* end of test_bank_api_with_fakebank_new.c */
diff --git a/src/bank-lib/testing_api_cmd_history.c b/src/bank-lib/testing_api_cmd_history.c
new file mode 100644
index 000000000..311c910d0
--- /dev/null
+++ b/src/bank-lib/testing_api_cmd_history.c
@@ -0,0 +1,735 @@
+/*
+ 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 bank-lib/testing_api_cmd_history.c
+ * @brief command to check the /history API from the bank.
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_testing_lib.h"
+#include "taler_testing_bank_lib.h"
+#include "taler_fakebank_lib.h"
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+
+
+struct HistoryState
+{
+ const char *bank_url;
+
+ uint64_t account_no;
+
+ enum TALER_BANK_Direction direction;
+
+ const char *start_row_reference;
+
+ unsigned int num_results;
+
+ struct TALER_BANK_HistoryHandle *hh;
+
+ uint64_t results_obtained;
+
+ int failed;
+};
+
+/**
+ * Item in the transaction history, as reconstructed from the
+ * command history.
+ */
+struct History
+{
+
+ /**
+ * Wire details.
+ */
+ struct TALER_BANK_TransferDetails details;
+
+ /**
+ * Serial ID of the wire transfer.
+ */
+ uint64_t row_id;
+
+ /**
+ * Direction of the transfer.
+ */
+ enum TALER_BANK_Direction direction;
+
+};
+
+extern struct TALER_BANK_AuthenticationData AUTHS[];
+
+/**
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param selector more detailed information about which object
+ * to return in case there were multiple generated
+ * by the command
+ * @return #GNUNET_OK on success
+ */
+static int
+history_traits (void *cls,
+ void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ /* Must define this function because some callbacks
+ * look for certain traits on _all_ the commands. */
+ return GNUNET_SYSERR;
+}
+
+/**
+ * Test if the /admin/add/incoming transaction at offset @a off
+ * has been /rejected.
+ *
+ * @param is interpreter state (where we are right now)
+ * @param off offset of the command to test for rejection
+ * @return #GNUNET_YES if the command at @a off was cancelled
+ */
+static int
+test_cancelled (struct TALER_TESTING_Interpreter *is,
+ unsigned int off)
+{
+ const char *rejected_reference;
+
+ for (unsigned int i=0;i<is->ip;i++)
+ {
+ const struct TALER_TESTING_Command *c = &is->commands[i];
+
+
+ #warning "Errors reported here are NOT fatal"
+ /* We use the exposure of a reference to a reject
+ * command as a signal to understand if the current
+ * command was cancelled; so errors about "reject traits"
+ * not found are NOT fatal here */
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_rejected
+ (c, 0, &rejected_reference))
+ continue;
+ if (0 == strcmp (rejected_reference,
+ TALER_TESTING_interpreter_get_current_label
+ (is)))
+ return GNUNET_YES;
+ }
+ return GNUNET_NO;
+}
+
+/**
+ * Free history @a h of length @a h_len.
+ *
+ * @param h history array to free
+ * @param h_len number of entries in @a h
+ */
+static void
+free_history (struct History *h,
+ uint64_t h_len)
+{
+ for (uint64_t off = 0;off<h_len;off++)
+ {
+ GNUNET_free (h[off].details.wire_transfer_subject);
+ json_decref (h[off].details.account_details);
+ }
+ GNUNET_free_non_null (h);
+}
+
+/**
+ * Log which history we expected.
+ *
+ * @param h what we expected
+ * @param h_len number of entries in @a h
+ * @param off position of the missmatch
+ */
+static void
+print_expected (struct History *h,
+ uint64_t h_len,
+ unsigned int off)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Transaction history missmatch at position %u/%llu\n",
+ off,
+ (unsigned long long) h_len);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history:\n");
+ for (uint64_t i=0;i<h_len;i++)
+ {
+ char *acc;
+
+ acc = json_dumps (h[i].details.account_details,
+ JSON_COMPACT);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "H(%llu): %s%s (serial: %llu, subject: %s, to: %s)\n",
+ (unsigned long long) i,
+ (TALER_BANK_DIRECTION_CREDIT == h[i].direction) ? "+" : "-",
+ TALER_amount2s (&h[i].details.amount),
+ (unsigned long long) h[i].row_id,
+ h[i].details.wire_transfer_subject,
+ acc);
+ if (NULL != acc)
+ free (acc);
+ }
+}
+
+/**
+ * Build history of transactions matching the current
+ * command in @a is.
+ *
+ * @param is interpreter state
+ * @param[out] rh history array to initialize
+ * @return number of entries in @a rh
+ */
+static uint64_t
+build_history (struct TALER_TESTING_Interpreter *is,
+ struct History **rh)
+{
+ struct HistoryState *hs = is->commands[is->ip].cls;
+ uint64_t total;
+ struct History *h;
+ const struct TALER_TESTING_Command *add_incoming_cmd;
+ int inc;
+ unsigned int start;
+ unsigned int end;
+ int ok;
+ const uint64_t *row_id_start = NULL;
+
+ if (NULL != hs->start_row_reference)
+ {
+ 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
+ (is, hs->start_row_reference);
+ GNUNET_assert (NULL != add_incoming_cmd);
+ GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_uint64
+ (add_incoming_cmd, 0, &row_id_start));
+ }
+
+ GNUNET_assert (0 != hs->num_results);
+ if (0 == is->ip)
+ {
+ *rh = NULL;
+ return 0;
+ }
+ if (hs->num_results > 0)
+ {
+ inc = 1;
+ start = 0;
+ end = is->ip - 1;
+ }
+ else
+ {
+ inc = -1;
+ start = is->ip - 1;
+ end = 0;
+ }
+
+ total = 0;
+ ok = GNUNET_NO;
+
+ if (NULL == row_id_start)
+ ok = GNUNET_YES;
+
+ for (unsigned int off = start;off != end + inc; off += inc)
+ {
+ const struct TALER_TESTING_Command *pos = &is->commands[off];
+ int cancelled;
+ const uint64_t *row_id;
+
+ /**
+ * Skip non-add_incoming commands, choose upon "do they
+ * offer row_id trait?".
+ */
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_uint64
+ (pos, 0, &row_id))
+ continue;
+
+ if (NULL != row_id_start)
+ {
+ if (*row_id_start == *row_id)
+ {
+ /* Doesn't count, start is excluded from output. */
+ total = 0;
+ ok = GNUNET_YES;
+ continue;
+ }
+ }
+ if (GNUNET_NO == ok)
+ continue; /* skip until we find the marker */
+ if (total >= hs->num_results * inc)
+ break; /* hit limit specified by command */
+
+ cancelled = test_cancelled (is, off);
+
+ if ( (GNUNET_YES == cancelled) &&
+ (0 == (hs->direction & TALER_BANK_DIRECTION_CANCEL)) )
+ {
+ TALER_LOG_INFO ("Ignoring canceled wire"
+ " transfer from history\n");
+ continue;
+ }
+
+ const uint64_t *credit_account_no;
+ const uint64_t *debit_account_no;
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
+ (pos, &credit_account_no));
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
+ (pos, &debit_account_no));
+
+ TALER_LOG_INFO ("Potential history element:"
+ " %llu->%llu; my account: %llu\n",
+ *debit_account_no,
+ *credit_account_no,
+ hs->account_no);
+
+ if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
+ (hs->account_no == *credit_account_no)) ||
+ ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
+ (hs->account_no == *debit_account_no)) )
+ {
+ TALER_LOG_INFO ("+1 my history\n");
+ total++; /* found matching record */
+ }
+ }
+ GNUNET_assert (GNUNET_YES == ok);
+ if (0 == total)
+ {
+ *rh = NULL;
+ return 0;
+ }
+ GNUNET_assert (total < UINT_MAX);
+ h = GNUNET_new_array ((unsigned int) total,
+ struct History);
+ total = 0;
+ ok = GNUNET_NO;
+ if (NULL == row_id_start)
+ ok = GNUNET_YES;
+ for (unsigned int off = start;off != end + inc; off += inc)
+ {
+ const struct TALER_TESTING_Command *pos = &is->commands[off];
+ int cancelled;
+ const uint64_t *row_id;
+
+ if (GNUNET_OK != TALER_TESTING_GET_TRAIT_ROW_ID
+ (pos, &row_id))
+ continue;
+
+ if (NULL != row_id_start)
+ {
+
+ if (*row_id_start == *row_id)
+ {
+ /* Doesn't count, start is excluded from output. */
+ total = 0;
+ ok = GNUNET_YES;
+ continue;
+ }
+ }
+ if (GNUNET_NO == ok)
+ {
+ TALER_LOG_INFO ("Skip on `%s'\n",
+ pos->label);
+ continue; /* skip until we find the marker */
+ }
+
+ if (total >= hs->num_results * inc)
+ {
+ TALER_LOG_INFO ("hit limit specified by command\n");
+ break;
+ }
+ const uint64_t *credit_account_no;
+ const uint64_t *debit_account_no;
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
+ (pos, &credit_account_no));
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
+ (pos, &debit_account_no));
+
+ TALER_LOG_INFO ("Potential history bit:"
+ " %llu->%llu; my account: %llu\n",
+ *debit_account_no,
+ *credit_account_no,
+ hs->account_no);
+
+ if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
+ (hs->account_no == *credit_account_no)) &&
+ ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
+ (hs->account_no == *debit_account_no)) )
+ {
+ GNUNET_break (0);
+ continue;
+ }
+
+ cancelled = test_cancelled (is, off);
+ if ( (GNUNET_YES == cancelled) &&
+ (0 == (hs->direction & TALER_BANK_DIRECTION_CANCEL)) )
+ {
+ TALER_LOG_WARNING ("`%s' was cancelled\n",
+ TALER_TESTING_interpreter_get_current_label
+ (is));
+ continue;
+ }
+
+ if ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
+ (hs->account_no == *credit_account_no))
+ {
+ h[total].direction = TALER_BANK_DIRECTION_CREDIT;
+ if (GNUNET_YES == cancelled)
+ h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
+ h[total].details.account_details
+ = json_pack ("{s:s, s:s, s:I}",
+ "type",
+ "test",
+ "bank_url",
+ hs->bank_url,
+ "account_number",
+ (json_int_t) *debit_account_no);
+ GNUNET_assert (NULL != h[total].details.account_details);
+ }
+ if ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
+ (hs->account_no == *debit_account_no))
+ {
+ h[total].direction = TALER_BANK_DIRECTION_DEBIT;
+ if (GNUNET_YES == cancelled)
+ h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
+ h[total].details.account_details
+ = json_pack ("{s:s, s:s, s:I}",
+ "type",
+ "test",
+ "bank_url",
+ hs->bank_url,
+ "account_number",
+ (json_int_t) *credit_account_no);
+ GNUNET_assert (NULL != h[total].details.account_details);
+ }
+ if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
+ (hs->account_no == *credit_account_no)) ||
+ ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
+ (hs->account_no == *debit_account_no)) )
+ {
+ const struct TALER_Amount *amount;
+ const char *subject;
+ const char *exchange_url;
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_get_trait_amount_obj
+ (pos, 0, &amount));
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_get_trait_transfer_subject
+ (pos, 0, &subject));
+
+ GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_url
+ (pos, 0, &exchange_url));
+
+ h[total].details.amount = *amount;
+
+ h[total].row_id = *row_id;
+ GNUNET_asprintf (&h[total].details.wire_transfer_subject,
+ "%s %s",
+ subject,
+ exchange_url);
+ TALER_LOG_INFO ("+1-bit of my history\n");
+ total++;
+ }
+ }
+ *rh = h;
+ return total;
+}
+
+
+/**
+ * Compute how many results we expect to be returned for
+ * the history command at @a is.
+ *
+ * @param is the interpreter state to inspect
+ * @return number of results expected
+ */
+static uint64_t
+compute_result_count (struct TALER_TESTING_Interpreter *is)
+{
+ uint64_t total;
+ struct History *h;
+
+ total = build_history (is, &h);
+ free_history (h, total);
+ return total;
+}
+
+/**
+ * Check that @a dir and @a details are the transaction
+ * results we expect at offset @a off in the history of
+ * the current command executed by @a is
+ *
+ * @param is the interpreter state we are in
+ * @param off the offset of the result
+ * @param dir the direction of the transaction
+ * @param details the transaction details to check
+ * @return #GNUNET_OK if the transaction is what we expect
+ */
+static int
+check_result (struct TALER_TESTING_Interpreter *is,
+ unsigned int off,
+ enum TALER_BANK_Direction dir,
+ const struct TALER_BANK_TransferDetails *details)
+{
+ uint64_t total;
+ struct History *h;
+
+ total = build_history (is, &h);
+ if (off >= total)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Test says history has at most %u"
+ " results, but got result #%u to check\n",
+ (unsigned int) total,
+ off);
+ print_expected (h, total, off);
+ return GNUNET_SYSERR;
+ }
+ if (h[off].direction != dir)
+ {
+ GNUNET_break (0);
+ print_expected (h, total, off);
+ free_history (h,
+ total);
+ return GNUNET_SYSERR;
+ }
+
+ if ( (0 != strcmp (h[off].details.wire_transfer_subject,
+ details->wire_transfer_subject)) ||
+ (0 != TALER_amount_cmp (&h[off].details.amount,
+ &details->amount)) ||
+ (1 != json_equal (h[off].details.account_details,
+ details->account_details)) )
+ {
+ GNUNET_break (0);
+ print_expected (h, total, off);
+ free_history (h,
+ total);
+ return GNUNET_SYSERR;
+ }
+ free_history (h,
+ total);
+ return GNUNET_OK;
+}
+
+/**
+ * Callbacks of this type are used to serve the result of asking
+ * the bank for the transaction history.
+ *
+ * @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 dir direction of the transfer
+ * @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
+ */
+static void
+history_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ enum TALER_BANK_Direction dir,
+ uint64_t row_id,
+ const struct TALER_BANK_TransferDetails *details,
+ const json_t *json)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct HistoryState *hs = is->commands[is->ip].cls;
+
+ if (MHD_HTTP_OK != http_status)
+ {
+ hs->hh = NULL;
+ if ( (hs->results_obtained != compute_result_count (is)) ||
+ (GNUNET_YES == hs->failed) )
+ {
+ uint64_t total;
+ struct History *h;
+
+ GNUNET_break (0);
+ total = build_history (is, &h);
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history of length %llu, got %llu;"
+ " HTTP status code: %u, failed: %d\n",
+ (unsigned long long) total,
+ (unsigned long long) hs->results_obtained,
+ http_status,
+ hs->failed);
+ print_expected (h, total, UINT_MAX);
+ free_history (h, total);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+ if (GNUNET_OK != check_result (is,
+ hs->results_obtained,
+ dir,
+ details))
+ {
+ GNUNET_break (0);
+
+ {
+ char *acc;
+
+ 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;
+ return;
+ }
+ hs->results_obtained++;
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure, typically a #struct WireState.
+ * @param cmd the command to execute, a /wire one.
+ * @param is the interpreter state.
+ */
+void
+history_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct HistoryState *hs = cls;
+ uint64_t row_id = UINT64_MAX;
+ const uint64_t *row_id_ptr = &row_id;
+ struct TALER_BANK_AuthenticationData *auth;
+
+ /* Get row_id from trait. */
+ 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_uint64
+ (history_cmd, 0, &row_id_ptr))
+ TALER_TESTING_FAIL (is);
+ row_id = *row_id_ptr;
+
+ TALER_LOG_DEBUG ("row id (from trait) is %llu\n", row_id);
+
+ }
+
+ auth = &AUTHS[hs->account_no - 1];
+ hs->hh = TALER_BANK_history (is->ctx,
+ hs->bank_url,
+ auth,
+ hs->account_no,
+ hs->direction,
+ row_id,
+ hs->num_results,
+ &history_cb,
+ is);
+ GNUNET_assert (NULL != hs->hh);
+}
+
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure, typically a #struct WireState.
+ * @param cmd the command which is being cleaned up.
+ */
+void
+history_cleanup
+ (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct HistoryState *hs = cls;
+
+ if (NULL != hs->hh)
+ {
+ TALER_LOG_WARNING ("/history did not complete\n");
+ TALER_BANK_history_cancel (hs->hh);
+ }
+
+ GNUNET_free (hs);
+}
+
+
+/**
+ * Test /history API from the bank.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_history
+ (const char *label,
+ const char *bank_url,
+ uint64_t account_no,
+ enum TALER_BANK_Direction direction,
+ const char *start_row_reference,
+ unsigned int num_results)
+{
+ struct HistoryState *hs;
+ struct TALER_TESTING_Command cmd;
+
+ 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->num_results = num_results;
+
+ cmd.label = label;
+ cmd.cls = hs;
+ cmd.run = &history_run;
+ cmd.cleanup = &history_cleanup;
+ cmd.traits = &history_traits;
+
+ return cmd;
+}
+
+/* end of testing_api_cmd_history.c */
diff --git a/src/bank-lib/testing_api_cmd_reject.c b/src/bank-lib/testing_api_cmd_reject.c
new file mode 100644
index 000000000..638699544
--- /dev/null
+++ b/src/bank-lib/testing_api_cmd_reject.c
@@ -0,0 +1,164 @@
+/*
+ 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 bank-lib/testing_api_cmd_reject.c
+ * @brief command to check the /reject API from the bank.
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+
+struct RejectState
+{
+ struct TALER_BANK_RejectHandle *rh;
+
+ const char *deposit_reference;
+
+ const char *bank_url;
+};
+
+/**
+ * Callbacks of this type are used to serve the result
+ * of asking the bank to reject an incoming wire transfer.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT
+ * (204) for successful status request; #MHD_HTTP_NOT_FOUND
+ * if the rowid is unknown; 0 if the bank's reply is bogus
+ * (fails to follow the protocol),
+ * @param ec detailed error code
+ */
+static void
+reject_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct RejectState *rs = is->commands[is->ip].cls;
+
+ rs->rh = NULL;
+ if (MHD_HTTP_NO_CONTENT != http_status)
+ {
+ GNUNET_break (0);
+ fprintf (stderr,
+ "Unexpected response code %u:\n",
+ http_status);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure, typically a #struct WireState.
+ * @param cmd the command which is being cleaned up.
+ */
+void
+reject_cleanup
+ (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RejectState *rs = cls;
+
+ if (NULL != rs->rh)
+ {
+ TALER_LOG_WARNING ("/reject did not complete\n");
+ TALER_BANK_reject_cancel (rs->rh);
+ }
+
+ GNUNET_free (rs);
+}
+
+/**
+ * Run the command.
+ *
+ * @param cls closure, typically a #struct WireState.
+ * @param cmd the command to execute, a /wire one.
+ * @param is the interpreter state.
+ */
+void
+reject_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RejectState *rs = cls;
+ const struct TALER_TESTING_Command *deposit_cmd;
+ const uint64_t *credit_account;
+ const uint64_t *row_id;
+ extern struct TALER_BANK_AuthenticationData *AUTHS;
+
+ deposit_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, rs->deposit_reference);
+
+ if (NULL != deposit_cmd)
+ TALER_TESTING_FAIL (is);
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
+ (deposit_cmd, &credit_account));
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_ROW_ID
+ (deposit_cmd, &row_id));
+
+ rs->rh = TALER_BANK_reject (is->ctx,
+ rs->bank_url,
+ &AUTHS[*credit_account -1],
+ *credit_account,
+ *row_id,
+ &reject_cb,
+ is);
+ GNUNET_assert (NULL != rs->rh);
+}
+
+
+/**
+ * FIXME.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_reject (const char *label,
+ const char *bank_url,
+ const char *deposit_reference)
+{
+ struct RejectState *rs;
+ struct TALER_TESTING_Command cmd;
+
+ rs = GNUNET_new (struct RejectState);
+ rs->bank_url = bank_url;
+ rs->deposit_reference = deposit_reference;
+
+ cmd.cls = rs;
+ cmd.run = &reject_run;
+ cmd.cleanup = &reject_cleanup;
+
+ return cmd;
+
+}
+
+/* end of testing_api_cmd_reject.c */
diff --git a/src/bank-lib/testing_api_helpers.c b/src/bank-lib/testing_api_helpers.c
new file mode 100644
index 000000000..8446f9581
--- /dev/null
+++ b/src/bank-lib/testing_api_helpers.c
@@ -0,0 +1,205 @@
+/*
+ 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 bank-lib/testing_api_helpers.c
+ * @brief convenience functions for bank-lib tests.
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_testing_bank_lib.h"
+
+/* Keeps each bank account credential at bank account number - 1 */
+struct TALER_BANK_AuthenticationData AUTHS[] = {
+
+ /* Bank credentials */
+ {.method = TALER_BANK_AUTH_BASIC,
+ .details.basic.username = BANK_USERNAME,
+ .details.basic.password = BANK_PASSWORD},
+
+ /* Exchange credentials */
+ {.method = TALER_BANK_AUTH_BASIC,
+ .details.basic.username = EXCHANGE_USERNAME,
+ .details.basic.password = EXCHANGE_PASSWORD },
+
+ /* User credentials */
+ {.method = TALER_BANK_AUTH_BASIC,
+ .details.basic.username = USER_USERNAME,
+ .details.basic.password = USER_PASSWORD }
+};
+
+/**
+ * Start the (Python) bank process. Assume the port
+ * is available and the database is clean. Use the "prepare
+ * bank" function to do such tasks.
+ *
+ * @param config_filename configuration filename.
+ *
+ * @return the process, or NULL if the process could not
+ * be started.
+ */
+struct GNUNET_OS_Process *
+TALER_TESTING_run_bank (const char *config_filename)
+{
+
+ struct GNUNET_OS_Process *bank_proc;
+ unsigned int iter;
+
+ bank_proc = GNUNET_OS_start_process
+ (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-bank-manage",
+ "taler-bank-manage",
+ "-c", config_filename,
+ "--with-db=postgres:///talercheck",
+ "serve-http", NULL);
+ if (NULL == bank_proc)
+ BANK_FAIL ();
+
+ /* give child time to start and bind against the socket */
+ fprintf (stderr,
+ "Waiting for `taler-bank-manage' to be ready");
+ iter = 0;
+ do
+ {
+ if (10 == iter)
+ {
+ fprintf (
+ stderr,
+ "Failed to launch `taler-bank-manage' (or `wget')\n");
+ GNUNET_OS_process_kill (bank_proc,
+ SIGTERM);
+ GNUNET_OS_process_wait (bank_proc);
+ GNUNET_OS_process_destroy (bank_proc);
+ BANK_FAIL ();
+ }
+ fprintf (stderr, ".");
+ sleep (1);
+ iter++;
+ }
+ /*FIXME: no hardcode port*/
+ while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/" \
+ " -o /dev/null -O /dev/null"));
+ fprintf (stderr, "\n");
+
+ return bank_proc;
+
+}
+
+/**
+ * Prepare the bank execution. Check if the port is available
+ * (and reset database?).
+ *
+ * @param config_filename configuration filename.
+ *
+ * @return the base url, or NULL upon errors. Must be freed
+ * by the caller.
+ */
+char *
+TALER_TESTING_prepare_bank (const char *config_filename)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ unsigned long long port;
+ struct GNUNET_OS_Process *dbreset_proc;
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
+ char *base_url;
+
+ cfg = GNUNET_CONFIGURATION_create ();
+
+ if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, config_filename))
+ BANK_FAIL ();
+
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number
+ (cfg, "bank",
+ "HTTP_PORT", &port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "bank",
+ "HTTP_PORT");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ BANK_FAIL ();
+ }
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ if (GNUNET_OK != GNUNET_NETWORK_test_port_free
+ (IPPROTO_TCP, (uint16_t) port))
+ {
+ fprintf (stderr,
+ "Required port %llu not available, skipping.\n",
+ port);
+ BANK_FAIL ();
+ }
+
+ /* DB preparation */
+ if (NULL ==
+ (dbreset_proc = GNUNET_OS_start_process (
+ GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-bank-manage",
+ "taler-bank-manage",
+ "-c", "bank.conf",
+ "--with-db=postgres:///talercheck", /*FIXME: no hardcoded*/
+ "django",
+ "flush",
+ "--no-input", NULL)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to flush the bank db.\n");
+ BANK_FAIL ();
+ }
+
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_process_wait_status (dbreset_proc,
+ &type,
+ &code))
+ {
+ GNUNET_OS_process_destroy (dbreset_proc);
+ BANK_FAIL ();
+ }
+ if ( (type == GNUNET_OS_PROCESS_EXITED) &&
+ (0 != code) )
+ {
+ fprintf (stderr,
+ "Failed to setup database\n");
+ BANK_FAIL ();
+ }
+ if ( (type != GNUNET_OS_PROCESS_EXITED) ||
+ (0 != code) )
+ {
+ fprintf (stderr,
+ "Unexpected error running"
+ " `taler-bank-manage django flush..'!\n");
+ BANK_FAIL ();
+ }
+
+ GNUNET_OS_process_destroy (dbreset_proc);
+
+ GNUNET_asprintf (&base_url,
+ "http://localhost:%llu/",
+ port);
+ return base_url;
+}
+
+
+/* end of testing_api_helpers.c */
diff --git a/src/exchange-lib/testing_api_cmd_bank_check.c b/src/exchange-lib/testing_api_cmd_bank_check.c
index 8c4ee2c44..9af156f92 100644
--- a/src/exchange-lib/testing_api_cmd_bank_check.c
+++ b/src/exchange-lib/testing_api_cmd_bank_check.c
@@ -47,12 +47,12 @@ struct BankCheckState
/**
* Expected account number that gave money
*/
- unsigned int debit_account;
+ uint64_t debit_account;
/**
* Expected account number that received money
*/
- unsigned int credit_account;
+ uint64_t credit_account;
/**
* Wire transfer subject (set by fakebank-lib).
@@ -69,6 +69,11 @@ struct BankCheckState
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * FIXME.
+ */
+ const char *deposit_reference;
};
/**
@@ -84,26 +89,72 @@ check_bank_transfer_run (void *cls,
struct TALER_TESTING_Interpreter *is)
{
struct BankCheckState *bcs = cls;
+
struct TALER_Amount amount;
+ const uint64_t *debit_account;
+ const uint64_t *credit_account;
+ const char *exchange_base_url;
- if (GNUNET_OK !=
- TALER_string_to_amount (bcs->amount,
- &amount))
+ if (NULL == bcs->deposit_reference)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u\n",
- bcs->amount,
- is->ip);
- TALER_TESTING_interpreter_fail (is);
- return;
+ debit_account = &bcs->debit_account;
+ credit_account = &bcs->credit_account;
+ exchange_base_url = bcs->exchange_base_url;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (bcs->amount,
+ &amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u\n",
+ bcs->amount,
+ is->ip);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+
+ if (NULL != bcs->deposit_reference)
+ {
+ const struct TALER_TESTING_Command *deposit_cmd;
+ const struct TALER_Amount *amount_ptr;
+
+ TALER_LOG_INFO ("`%s' uses reference (%s)\n",
+ TALER_TESTING_interpreter_get_current_label
+ (is),
+ bcs->deposit_reference);
+ deposit_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, bcs->deposit_reference);
+
+ if (NULL == deposit_cmd)
+ TALER_TESTING_FAIL (is);
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_get_trait_amount_obj
+ (deposit_cmd, 0, &amount_ptr));
+ amount = *amount_ptr;
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT
+ (deposit_cmd, &debit_account));
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT
+ (deposit_cmd, &credit_account));
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_get_trait_url
+ (deposit_cmd, 0, &exchange_base_url)); // check 0 works!
+
}
+
if (GNUNET_OK !=
TALER_FAKEBANK_check (is->fakebank,
&amount,
- bcs->debit_account,
- bcs->credit_account,
- bcs->exchange_base_url,
+ *debit_account,
+ *credit_account,
+ exchange_base_url,
&bcs->subject))
{
GNUNET_break (0);
@@ -189,8 +240,8 @@ TALER_TESTING_cmd_check_bank_transfer
(const char *label,
const char *exchange_base_url,
const char *amount,
- unsigned int debit_account,
- unsigned int credit_account)
+ uint64_t debit_account,
+ uint64_t credit_account)
{
struct BankCheckState *bcs;
struct TALER_TESTING_Command cmd;
@@ -205,7 +256,6 @@ TALER_TESTING_cmd_check_bank_transfer
cmd.cls = bcs;
cmd.run = &check_bank_transfer_run;
cmd.cleanup = &check_bank_transfer_cleanup;
- // traits?
cmd.traits = &check_bank_transfer_traits;
return cmd;
@@ -265,3 +315,27 @@ TALER_TESTING_cmd_check_bank_empty (const char *label)
return cmd;
}
+
+
+/**
+ * FIXME.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_bank_transfer_with_ref
+ (const char *label,
+ const char *deposit_reference)
+{
+
+ struct BankCheckState *bcs;
+ struct TALER_TESTING_Command cmd;
+
+ bcs = GNUNET_new (struct BankCheckState);
+ bcs->deposit_reference = deposit_reference;
+ cmd.label = label;
+ cmd.cls = bcs;
+ cmd.run = &check_bank_transfer_run;
+ cmd.cleanup = &check_bank_transfer_cleanup;
+ cmd.traits = &check_bank_transfer_traits;
+
+ return cmd;
+}
diff --git a/src/exchange-lib/testing_api_cmd_fakebank_transfer.c b/src/exchange-lib/testing_api_cmd_fakebank_transfer.c
index 7da4bf09c..a8bad860a 100644
--- a/src/exchange-lib/testing_api_cmd_fakebank_transfer.c
+++ b/src/exchange-lib/testing_api_cmd_fakebank_transfer.c
@@ -31,6 +31,7 @@
#include "taler_fakebank_lib.h"
#include "taler_signatures.h"
#include "taler_testing_lib.h"
+#include "taler_testing_bank_lib.h"
/**
*
@@ -348,17 +349,19 @@ fakebank_transfer_traits (void *cls,
{
struct FakebankTransferState *fts = cls;
struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_reserve_priv (0,
- &fts->reserve_priv),
+ TALER_TESTING_make_trait_reserve_priv
+ (0, &fts->reserve_priv),
+ TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT
+ (&fts->debit_account_no),
+ TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT
+ (&fts->credit_account_no),
+ TALER_TESTING_make_trait_url (0, fts->exchange_url),
+ TALER_TESTING_make_trait_transfer_subject (0, fts->subject),
+ TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id),
+ TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
TALER_TESTING_trait_end ()
};
- if (NULL != fts->subject)
- {
- GNUNET_break (0);
- /* we do NOT create a reserve private key */
- return GNUNET_SYSERR;
- }
return TALER_TESTING_get_trait (traits,
ret,
trait,
diff --git a/src/exchange-lib/testing_api_cmd_track.c b/src/exchange-lib/testing_api_cmd_track.c
index 40894872b..8c289ed5d 100644
--- a/src/exchange-lib/testing_api_cmd_track.c
+++ b/src/exchange-lib/testing_api_cmd_track.c
@@ -198,7 +198,7 @@ deposit_wtid_cb
return;
}
- char *transfer_subject;
+ const char *transfer_subject;
if (GNUNET_OK != TALER_TESTING_get_trait_transfer_subject
(bank_transfer_cmd, 0, &transfer_subject))
diff --git a/src/exchange-lib/testing_api_helpers.c b/src/exchange-lib/testing_api_helpers.c
index b6e1e9897..690c222c9 100644
--- a/src/exchange-lib/testing_api_helpers.c
+++ b/src/exchange-lib/testing_api_helpers.c
@@ -431,9 +431,8 @@ TALER_TESTING_prepare_fakebank (const char *config_filename)
char *fakebank_url;
cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- config_filename))
+ if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg,
+ config_filename))
return NULL;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
diff --git a/src/exchange-lib/testing_api_loop.c b/src/exchange-lib/testing_api_loop.c
index 2bbf46ac7..78ae3611d 100644
--- a/src/exchange-lib/testing_api_loop.c
+++ b/src/exchange-lib/testing_api_loop.c
@@ -504,6 +504,22 @@ cert_cb (void *cls,
main_ctx->is);
}
+/**
+ * Initialize scheduler loop and curl context for the testcase,
+ * and responsible to run the "run" method.
+ *
+ * @param cls closure, typically the "run" method, the
+ * interpreter state and a closure for "run".
+ */
+static void
+main_wrapper_exchange_agnostic (void *cls)
+{
+ struct MainContext *main_ctx = cls;
+
+ main_ctx->main_cb (main_ctx->main_cb_cls,
+ main_ctx->is);
+}
+
/**
* Initialize scheduler loop and curl context for the testcase,
@@ -513,7 +529,7 @@ cert_cb (void *cls,
* interpreter state and a closure for "run".
*/
static void
-main_wrapper (void *cls)
+main_wrapper_exchange_connect (void *cls)
{
struct MainContext *main_ctx = cls;
struct TALER_TESTING_Interpreter *is = main_ctx->is;
@@ -542,11 +558,6 @@ main_wrapper (void *cls)
"http://localhost:%llu/",
exchange_port);
- is->ctx = GNUNET_CURL_init
- (&GNUNET_CURL_gnunet_scheduler_reschedule, &is->rc);
- GNUNET_assert (NULL != is->ctx);
- is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx);
-
GNUNET_assert ( NULL !=
(is->exchange = TALER_EXCHANGE_connect (is->ctx,
exchange_url,
@@ -568,7 +579,8 @@ main_wrapper (void *cls)
* @param exchanged exchange process handle: will be put in the
* state as some commands - e.g. revoke - need to send
* signal to it, for example to let it know to reload the
- * key state..
+ * key state.. if NULL, the interpreter will run without
+ * trying to connect to the exchange first.
*
* @return FIXME: not sure what 'is.result' is at this stage.
*/
@@ -585,10 +597,7 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
/* needed to init the curl ctx */
.is = &is,
/* needed to read values like exchange port
- * number and construct the exchange url. The
- * port number _could_ have been passed here, but
- * we prefer to stay "general" as other values might
- * need to be passed around in the future. */
+ * number to construct the exchange url.*/
.config_filename = config_filename
};
struct GNUNET_SIGNAL_Context *shc_chld;
@@ -602,16 +611,26 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
GNUNET_assert (NULL != sigpipe);
shc_chld = GNUNET_SIGNAL_handler_install
(GNUNET_SIGCHLD, &sighandler_child_death);
+
+ is.ctx = GNUNET_CURL_init
+ (&GNUNET_CURL_gnunet_scheduler_reschedule, &is.rc);
+ GNUNET_assert (NULL != is.ctx);
+ is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
+
/* Blocking */
- GNUNET_SCHEDULER_run (&main_wrapper,
- &main_ctx);
+
+ if (NULL != exchanged)
+ GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
+ &main_ctx);
+ else
+ GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
+ &main_ctx);
+
GNUNET_SIGNAL_handler_uninstall (shc_chld);
GNUNET_DISK_pipe_close (sigpipe);
sigpipe = NULL;
- /*FIXME: ?? */
return is.result;
}
-
/* end of testing_api_loop.c */
diff --git a/src/exchange-lib/testing_api_trait_amount.c b/src/exchange-lib/testing_api_trait_amount.c
index a9c5b3bc2..f21ec8704 100644
--- a/src/exchange-lib/testing_api_trait_amount.c
+++ b/src/exchange-lib/testing_api_trait_amount.c
@@ -45,7 +45,7 @@ int
TALER_TESTING_get_trait_amount_obj (
const struct TALER_TESTING_Command *cmd,
unsigned int index,
- struct TALER_Amount **amount)
+ const struct TALER_Amount **amount)
{
return cmd->traits (cmd->cls,
(void **) amount,
diff --git a/src/exchange-lib/testing_api_trait_number.c b/src/exchange-lib/testing_api_trait_number.c
index 8f011dcae..4db887927 100644
--- a/src/exchange-lib/testing_api_trait_number.c
+++ b/src/exchange-lib/testing_api_trait_number.c
@@ -29,7 +29,8 @@
#include "taler_signatures.h"
#include "taler_testing_lib.h"
-#define TALER_TESTING_TRAIT_NUMBER "number"
+#define TALER_TESTING_TRAIT_UINT "uint"
+#define TALER_TESTING_TRAIT_UINT64 "uint-64"
/**
* Obtain a "number" value from @a cmd.
@@ -48,7 +49,7 @@ TALER_TESTING_get_trait_uint
{
return cmd->traits (cmd->cls,
(void **) n,
- TALER_TESTING_TRAIT_NUMBER,
+ TALER_TESTING_TRAIT_UINT,
index);
}
@@ -65,10 +66,52 @@ TALER_TESTING_make_trait_uint
{
struct TALER_TESTING_Trait ret = {
.index = index,
- .trait_name = TALER_TESTING_TRAIT_NUMBER,
+ .trait_name = TALER_TESTING_TRAIT_UINT,
.ptr = (const void *) n
};
return ret;
}
+/**
+ * Obtain a "number" value from @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param selector which coin to pick if @a cmd has multiple on
+ * offer
+ * @param n[out] set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_uint64
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const uint64_t **n)
+{
+ return cmd->traits (cmd->cls,
+ (void **) n,
+ TALER_TESTING_TRAIT_UINT64,
+ index);
+}
+
+/**
+ * @param selector associate the object with this "tag"
+ * @param n which object should be returned
+ *
+ * @return the trait, to be put in the traits array of the command
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_uint64
+ (unsigned int index,
+ const uint64_t *n)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_UINT64,
+ .ptr = (const void *) n
+ };
+ return ret;
+}
+
+
+
/* end of testing_api_trait_number.c */
diff --git a/src/exchange-lib/testing_api_trait_string.c b/src/exchange-lib/testing_api_trait_string.c
index 0675d5a88..1b1b42219 100644
--- a/src/exchange-lib/testing_api_trait_string.c
+++ b/src/exchange-lib/testing_api_trait_string.c
@@ -36,6 +36,7 @@
#define TALER_TESTING_TRAIT_AMOUNT "amount"
#define TALER_TESTING_TRAIT_URL "url"
#define TALER_TESTING_TRAIT_ORDER_ID "order-id"
+#define TALER_TESTING_TRAIT_REJECTED "rejected"
/**
* Obtain contract terms from @a cmd.
@@ -135,7 +136,7 @@ int
TALER_TESTING_get_trait_transfer_subject
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
- char **transfer_subject)
+ const char **transfer_subject)
{
return cmd->traits (cmd->cls,
(void **) transfer_subject,
@@ -154,7 +155,7 @@ TALER_TESTING_get_trait_transfer_subject
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_transfer_subject
(unsigned int index,
- char *transfer_subject)
+ const char *transfer_subject)
{
struct TALER_TESTING_Trait ret = {
.index = index,
@@ -293,5 +294,50 @@ TALER_TESTING_make_trait_order_id
return ret;
}
+/**
+ * Obtain the reference from a bank transfer which has
+ * been rejected.
+ *
+ * @param cmd command to extract trait from
+ * @param index which reference is to be picked, in case
+ * multiple are offered.
+ * @param rejected_reference[out] where to write the order id.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_rejected
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const char **rejected_reference)
+{
+ return cmd->traits (cmd->cls,
+ (void **) rejected_reference,
+ TALER_TESTING_TRAIT_REJECTED,
+ index);
+}
+
+/**
+ * Offer reference to a bank transfer which has been
+ * rejected.
+ *
+ * @param index which reference is to be picked, in case
+ * multiple are offered.
+ * @param rejected_reference the url to offer
+ * @return the trait, to be put in the traits array of the command
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_rejected
+ (unsigned int index,
+ const char *rejected)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_REJECTED,
+ .ptr = (const void *) rejected
+ };
+ return ret;
+}
+
+
/* end of testing_api_trait_string.c */
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 6583ad524..2916a812c 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -28,7 +28,8 @@ talerinclude_HEADERS = \
taler_pq_lib.h \
taler_signatures.h \
taler_wire_lib.h \
- taler_wire_plugin.h
+ taler_wire_plugin.h \
+ taler_testing_bank_lib.h
endif
diff --git a/src/include/taler_testing_bank_lib.h b/src/include/taler_testing_bank_lib.h
new file mode 100644
index 000000000..87187a733
--- /dev/null
+++ b/src/include/taler_testing_bank_lib.h
@@ -0,0 +1,108 @@
+/*
+ This file is part of TALER
+ (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 include/taler_testing_bank_lib.h
+ * @brief API for writing an interpreter to test Taler components
+ * @author Marcello Stanisci
+ */
+#ifndef TALER_TESTING_BANK_LIB_H
+#define TALER_TESTING_BANK_LIB_H
+
+#include "taler_util.h"
+#include <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_testing_lib.h"
+
+
+/* ******** Credentials to log in at the bank ******* */
+
+#define BANK_ACCOUNT_NUMBER 1
+#define BANK_USERNAME "Bank"
+#define BANK_PASSWORD "x"
+#define EXCHANGE_ACCOUNT_NUMBER 2
+#define EXCHANGE_USERNAME "Exchange"
+#define EXCHANGE_PASSWORD "x"
+#define USER_ACCOUNT_NUMBER 3
+#define USER_USERNAME "user3"
+#define USER_PASSWORD "pass3"
+
+
+/* ********************* Helper functions ********************* */
+
+#define BANK_FAIL() \
+ do {GNUNET_break (0); return NULL; } while (0)
+
+/**
+ * Start the (Python) bank process. Assume the port
+ * is available and the database is clean. Use the "prepare
+ * bank" function to do such tasks.
+ *
+ * @param config_filename configuration filename.
+ *
+ * @return the process, or NULL if the process could not
+ * be started.
+ */
+struct GNUNET_OS_Process *
+TALER_TESTING_run_bank (const char *config_filename);
+
+/**
+ * Prepare the bank execution. Check if the port is available
+ * (and reset database?).
+ *
+ * @param config_filename configuration filename.
+ *
+ * @return the base url, or NULL upon errors. Must be freed
+ * by the caller.
+ */
+char *
+TALER_TESTING_prepare_bank (const char *config_filename);
+
+
+/* ******************* Generic interpreter logic ************ */
+
+/* ************** Specific interpreter commands ************ */
+
+/**
+ * Test /history API from the bank.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_history
+ (const char *label,
+ const char *bank_url,
+ uint64_t account_no,
+ enum TALER_BANK_Direction direction,
+ const char *start_row_reference,
+ unsigned int num_results);
+
+/**
+ * FIXME.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_reject (const char *label,
+ const char *bank_url,
+ const char *deposit_reference);
+
+/* *** Generic trait logic for implementing traits ********* */
+
+/* ****** Specific traits supported by this component ******* */
+
+#endif
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index b4350e0c3..d06105dd1 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -27,6 +27,7 @@
#define TALER_TESTING_LIB_H
#include "taler_util.h"
+#include "taler_exchange_service.h"
#include <gnunet/gnunet_json_lib.h>
#include "taler_json_lib.h"
#include <microhttpd.h>
@@ -35,6 +36,37 @@
/* ********************* Helper functions ********************* */
/**
+ * Print failing line number and trigger shutdown. Useful
+ * quite any time after the command "run" method has been called.
+ */
+#define TALER_TESTING_FAIL(is) \
+ do \
+ {\
+ GNUNET_break (0); \
+ TALER_TESTING_interpreter_fail (is); \
+ return; \
+ } while (0)
+
+
+#define TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT(cmd,out) \
+ TALER_TESTING_get_trait_uint64 (cmd, 0, out)
+
+#define TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT(data) \
+ TALER_TESTING_make_trait_uint64 (0, data)
+
+#define TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT(cmd,out) \
+ TALER_TESTING_get_trait_uint64 (cmd, 1, out)
+
+#define TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT(data) \
+ TALER_TESTING_make_trait_uint64 (1, data)
+
+#define TALER_TESTING_GET_TRAIT_ROW_ID(cmd,out) \
+ TALER_TESTING_get_trait_uint64 (cmd, 3, out)
+
+#define TALER_TESTING_MAKE_TRAIT_ROW_ID(data) \
+ TALER_TESTING_make_trait_uint64 (3, data)
+
+/**
* Allocate and return a piece of wire-details. Mostly, it adds
* the bank_url to the JSON.
*
@@ -747,8 +779,16 @@ TALER_TESTING_cmd_check_bank_transfer
(const char *label,
const char *exchange_base_url,
const char *amount,
- unsigned int debit_account,
- unsigned int credit_account);
+ uint64_t debit_account,
+ uint64_t credit_account);
+
+/**
+ * FIXME.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_bank_transfer_with_ref
+ (const char *label,
+ const char *deposit_reference);
/**
* Check bank's balance is zero.
@@ -1017,6 +1057,33 @@ TALER_TESTING_make_trait_denom_sig
(unsigned int index,
const struct TALER_DenominationSignature *sig);
+
+/**
+ * @param selector associate the object with this "tag"
+ * @param i which object should be returned
+ *
+ * @return the trait, to be put in the traits array of the command
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_uint64
+ (unsigned int index,
+ const uint64_t *i);
+
+/**
+ * Obtain a "number" value from @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param selector which coin to pick if @a cmd has multiple on
+ * offer
+ * @param n[out] set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_uint64
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const uint64_t **n);
+
/**
* @param selector associate the object with this "tag"
* @param i which object should be returned
@@ -1225,7 +1292,7 @@ int
TALER_TESTING_get_trait_transfer_subject
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
- char **transfer_subject);
+ const char **transfer_subject);
/**
@@ -1239,7 +1306,7 @@ TALER_TESTING_get_trait_transfer_subject
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_transfer_subject
(unsigned int index,
- char *transfer_subject);
+ const char *transfer_subject);
/**
@@ -1369,11 +1436,42 @@ int
TALER_TESTING_get_trait_amount_obj (
const struct TALER_TESTING_Command *cmd,
unsigned int index,
- struct TALER_Amount **amount);
+ const struct TALER_Amount **amount);
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_amount_obj (
unsigned int index,
const struct TALER_Amount *amount);
+
+/**
+ * Offer reference to a bank transfer which has been
+ * rejected.
+ *
+ * @param index which reference is to be picked, in case
+ * multiple are offered.
+ * @param rejected_reference the url to offer
+ * @return the trait, to be put in the traits array of the command
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_rejected
+ (unsigned int index,
+ const char *rejected);
+
+/**
+ * Obtain the reference from a bank transfer which has
+ * been rejected.
+ *
+ * @param cmd command to extract trait from
+ * @param index which reference is to be picked, in case
+ * multiple are offered.
+ * @param rejected_reference[out] where to write the order id.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_rejected
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const char **rejected_reference);
+
#endif