diff options
| author | Marcello Stanisci <stanisci.m@gmail.com> | 2018-02-22 14:51:12 +0100 | 
|---|---|---|
| committer | Marcello Stanisci <stanisci.m@gmail.com> | 2018-02-26 14:12:46 +0100 | 
| commit | b593d416d6e788b2053c2f5ebb634e0bb39fe560 (patch) | |
| tree | cf08a83fb1922c32d4a0e4ce161ae3ff20023a69 /src | |
| parent | 8d5cc9f550da58610ad220d72f21d930c47ad0a8 (diff) | |
Bank-lib tests, using the new (libraries-based) style.
Diffstat (limited to 'src')
| -rw-r--r-- | src/bank-lib/Makefile.am | 43 | ||||
| -rw-r--r-- | src/bank-lib/bank.conf | 6 | ||||
| -rw-r--r-- | src/bank-lib/test_bank_api_new.c | 185 | ||||
| -rw-r--r-- | src/bank-lib/test_bank_api_with_fakebank_new.c | 223 | ||||
| -rw-r--r-- | src/bank-lib/testing_api_cmd_history.c | 735 | ||||
| -rw-r--r-- | src/bank-lib/testing_api_cmd_reject.c | 164 | ||||
| -rw-r--r-- | src/bank-lib/testing_api_helpers.c | 205 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_cmd_bank_check.c | 108 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_cmd_fakebank_transfer.c | 19 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_cmd_track.c | 2 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_helpers.c | 5 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_loop.c | 49 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_trait_amount.c | 2 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_trait_number.c | 49 | ||||
| -rw-r--r-- | src/exchange-lib/testing_api_trait_string.c | 50 | ||||
| -rw-r--r-- | src/include/Makefile.am | 3 | ||||
| -rw-r--r-- | src/include/taler_testing_bank_lib.h | 108 | ||||
| -rw-r--r-- | src/include/taler_testing_lib.h | 108 | 
18 files changed, 2005 insertions, 59 deletions
| diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index 967d95ed..bd1c7e8b 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 0610606c..f6e4e7fe 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 00000000..a43aa876 --- /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 00000000..a36251c5 --- /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 00000000..311c910d --- /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 00000000..63869954 --- /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 00000000..8446f958 --- /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 8c4ee2c4..9af156f9 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 7da4bf09..a8bad860 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 40894872..8c289ed5 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 b6e1e989..690c222c 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 2bbf46ac..78ae3611 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 a9c5b3bc..f21ec870 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 8f011dca..4db88792 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 0675d5a8..1b1b4221 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 6583ad52..2916a812 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 00000000..87187a73 --- /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 b4350e0c..d06105dd 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 | 
