commit 72a629a8be1ed2adc7402285e0f19f8f06816a26
parent dbf85bbc0d23b044aa47be67ceae4e6ecd709298
Author: Florian Dold <florian.dold@gmail.com>
Date: Sun, 19 Jan 2020 15:23:19 +0100
move testing logic and integration tests into separate directory
Diffstat:
177 files changed, 19874 insertions(+), 19900 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -47,16 +47,16 @@ src/lib/test_taler_exchange_httpd_home/.local/share/taler/exchange/wirefees/
src/lib/test_taler_exchange_httpd_home/.local/share/taler/auditor/
src/lib/test_taler_exchange_httpd_home/.local/share/taler/auditors/
-src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/live-keys/
-src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/
-src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditor/
-src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditors/
-src/lib/test_exchange_api_home/.local/share/taler/exchange/live-keys/
-src/lib/test_exchange_api_home/.local/share/taler/exchange/wirefees/
-src/lib/test_exchange_api_home/.local/share/taler/auditor/
-src/lib/test_exchange_api_home/.local/share/taler/auditors/
+src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/live-keys/
+src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/
+src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditor/
+src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/auditors/
+src/testing/test_exchange_api_home/.local/share/taler/exchange/live-keys/
+src/testing/test_exchange_api_home/.local/share/taler/exchange/wirefees/
+src/testing/test_exchange_api_home/.local/share/taler/auditor/
+src/testing/test_exchange_api_home/.local/share/taler/auditors/
src/lib/auditor.in
-src/lib/test_exchange_api_twisted
+src/testing/test_exchange_api_twisted
src/exchange/taler-exchange-aggregator
src/exchange/test_taler_exchange_aggregator-postgres
src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/live-keys/
diff --git a/configure.ac b/configure.ac
@@ -487,6 +487,7 @@ AC_CONFIG_FILES([Makefile
src/exchangedb/Makefile
src/exchange-tools/Makefile
src/lib/Makefile
+ src/testing/Makefile
src/benchmark/Makefile
src/include/Makefile
src/json/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
@@ -25,4 +25,5 @@ SUBDIRS = \
auditordb \
auditor \
lib \
+ testing \
benchmark
diff --git a/src/benchmark/Makefile.am b/src/benchmark/Makefile.am
@@ -20,7 +20,7 @@ taler_exchange_benchmark_LDADD = \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/lib/libtalerexchange.la \
- $(top_builddir)/src/lib/libtalertesting.la \
+ $(top_builddir)/src/testing/libtalertesting.la \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
-lgnunetjson \
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
@@ -1,20 +1,21 @@
# This Makefile.am is in the public domain
+
AM_CPPFLAGS = \
- -I$(top_srcdir)/src/include \
- $(LIBGCRYPT_CFLAGS) \
- $(POSTGRESQL_CPPFLAGS)
+ -I$(top_srcdir)/src/include \
+ $(LIBGCRYPT_CFLAGS) \
+ $(POSTGRESQL_CPPFLAGS)
if USE_COVERAGE
AM_CFLAGS = --coverage -O0
XLIB = -lgcov
endif
+
# Libraries
lib_LTLIBRARIES = \
libtalerauditor.la \
- libtalerexchange.la \
- libtalertesting.la
+ libtalerexchange.la
libtalerexchange_la_LDFLAGS = \
-version-info 4:0:0 \
@@ -62,294 +63,3 @@ libtalerauditor_la_LIBADD = \
-ljansson \
$(LIBGNURLCURL_LIBS) \
$(XLIB)
-
-libtalertesting_la_LDFLAGS = \
- -version-info 0:0:0 \
- -no-undefined
-libtalertesting_la_SOURCES = \
- exchange_api_curl_defaults.c \
- testing_api_cmd_auditor_deposit_confirmation.c \
- testing_api_cmd_auditor_exchanges.c \
- testing_api_cmd_auditor_exec_auditor.c \
- testing_api_cmd_auditor_exec_auditor_dbinit.c \
- testing_api_cmd_auditor_exec_wire_auditor.c \
- testing_api_cmd_bank_admin_add_incoming.c \
- testing_api_cmd_bank_check.c \
- testing_api_cmd_bank_admin_check.c \
- testing_api_cmd_bank_check_empty.c \
- testing_api_cmd_bank_history_credit.c \
- testing_api_cmd_bank_history_debit.c \
- testing_api_cmd_bank_transfer.c \
- testing_api_cmd_batch.c \
- testing_api_cmd_check_keys.c \
- testing_api_cmd_deposit.c \
- testing_api_cmd_exec_aggregator.c \
- testing_api_cmd_exec_wirewatch.c \
- testing_api_cmd_exec_keyup.c \
- testing_api_cmd_exec_auditor-sign.c \
- testing_api_cmd_recoup.c \
- testing_api_cmd_refund.c \
- testing_api_cmd_refresh.c \
- testing_api_cmd_serialize_keys.c \
- testing_api_cmd_signal.c \
- testing_api_cmd_sleep.c \
- testing_api_cmd_status.c \
- testing_api_cmd_track.c \
- testing_api_cmd_wait.c \
- testing_api_cmd_wire.c \
- testing_api_cmd_withdraw.c \
- testing_api_cmd_insert_deposit.c \
- testing_api_helpers_auditor.c \
- testing_api_helpers_bank.c \
- testing_api_helpers_exchange.c \
- testing_api_loop.c \
- testing_api_traits.c \
- testing_api_trait_amount.c \
- testing_api_trait_blinding_key.c \
- testing_api_trait_cmd.c \
- testing_api_trait_coin_priv.c \
- testing_api_trait_contract.c \
- testing_api_trait_denom_pub.c \
- testing_api_trait_denom_sig.c \
- testing_api_trait_exchange_pub.c \
- testing_api_trait_exchange_sig.c \
- testing_api_trait_fresh_coin.c \
- testing_api_trait_json.c \
- testing_api_trait_merchant_key.c \
- testing_api_trait_number.c \
- testing_api_trait_process.c \
- testing_api_trait_reserve_pub.c \
- testing_api_trait_reserve_priv.c \
- testing_api_trait_string.c \
- testing_api_trait_time.c \
- testing_api_trait_wtid.c
-libtalertesting_la_LIBADD = \
- libtalerexchange.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- -lgnunetcurl \
- -lgnunetjson \
- -lgnunetutil \
- -ljansson \
- $(XLIB)
-
-# Testcases
-
-AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
-
-check_PROGRAMS = \
- test_auditor_api \
- test_auditor_api_version \
- test_bank_api_with_fakebank \
- test_bank_api_with_pybank \
- test_exchange_api \
- test_exchange_api_keys_cherry_picking \
- test_exchange_api_revocation \
- test_exchange_api_overlapping_keys_bug \
- test_taler_exchange_aggregator-postgres \
- test_taler_exchange_wirewatch-postgres
-if HAVE_TWISTER
- check_PROGRAMS += \
- test_exchange_api_twisted \
- test_bank_api_with_fakebank_twisted \
- test_bank_api_with_pybank_twisted
-endif
-
-TESTS = \
- $(check_PROGRAMS)
-
-test_auditor_api_SOURCES = \
- test_auditor_api.c
-test_auditor_api_LDADD = \
- libtalerauditor.la \
- libtalertesting.la \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_auditor_api_version_SOURCES = \
- test_auditor_api_version.c
-test_auditor_api_version_LDADD = \
- libtalerauditor.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_bank_api_with_fakebank_SOURCES = \
- test_bank_api.c
-test_bank_api_with_fakebank_LDADD = \
- $(top_builddir)/src/lib/libtalertesting.la \
- -ltalerexchange \
- -lgnunetutil \
- $(top_builddir)/src/bank-lib/libtalerbank.la
-
-test_bank_api_with_pybank_SOURCES = \
- test_bank_api.c
-test_bank_api_with_pybank_LDADD = \
- libtalertesting.la \
- libtalerexchange.la \
- -lgnunetutil \
- $(top_builddir)/src/bank-lib/libtalerbank.la
-
-test_exchange_api_SOURCES = \
- test_exchange_api.c
-test_exchange_api_LDADD = \
- libtalertesting.la \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_exchange_api_revocation_SOURCES = \
- test_exchange_api_revocation.c
-test_exchange_api_revocation_LDADD = \
- libtalertesting.la \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_exchange_api_keys_cherry_picking_SOURCES = \
- test_exchange_api_keys_cherry_picking.c
-test_exchange_api_keys_cherry_picking_LDADD = \
- libtalertesting.la \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_exchange_api_overlapping_keys_bug_SOURCES = \
- test_exchange_api_overlapping_keys_bug.c
-test_exchange_api_overlapping_keys_bug_LDADD = \
- libtalertesting.la \
- libtalerexchange.la \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_taler_exchange_aggregator_postgres_SOURCES = \
- test_taler_exchange_aggregator.c
-test_taler_exchange_aggregator_postgres_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/lib/libtalertesting.la \
- -lmicrohttpd \
- -lgnunetutil \
- -lgnunetjson \
- -ljansson \
- -lpthread
-
-test_taler_exchange_wirewatch_postgres_SOURCES = \
- test_taler_exchange_wirewatch.c
-test_taler_exchange_wirewatch_postgres_LDADD = \
- $(LIBGCRYPT_LIBS) \
- $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- $(top_builddir)/src/lib/libtalertesting.la \
- -lmicrohttpd \
- -lgnunetutil \
- -lgnunetjson \
- -lgnunetpq \
- -ljansson \
- -lpthread
-
-test_exchange_api_twisted_SOURCES = \
- test_exchange_api_twisted.c
-test_exchange_api_twisted_LDADD = \
- $(LIBGCRYPT_LIBS) \
- libtalertesting.la \
- libtalerexchange.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -ltalertwistertesting \
- -lgnunetjson \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_bank_api_with_fakebank_twisted_SOURCES = \
- test_bank_api_twisted.c
-test_bank_api_with_fakebank_twisted_LDADD = \
- $(top_builddir)/src/lib/libtalertesting.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/lib/libtalerexchange.la \
- $(top_builddir)/src/json/libtalerjson.la \
- -ltalertwistertesting \
- -lgnunetjson \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-test_bank_api_with_pybank_twisted_SOURCES = \
- test_bank_api_twisted.c
-test_bank_api_with_pybank_twisted_LDADD = \
- $(top_builddir)/src/lib/libtalertesting.la \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/lib/libtalerexchange.la \
- $(top_builddir)/src/json/libtalerjson.la \
- -ltalertwistertesting \
- -lgnunetjson \
- -lgnunetcurl \
- -lgnunetutil \
- -ljansson
-
-
-# Distribution
-
-EXTRA_DIST = \
- test_bank_api.conf \
- test_bank_api_bank_twisted.conf \
- test_auditor_api.conf \
- test_auditor_api_expire_reserve_now.conf \
- test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
- test_exchange_api_home/.config/taler/account-2.json \
- test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json \
- test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \
- test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \
- test_exchange_api_home/.config/taler/test.json \
- test_exchange_api_home/.config/taler/sepa.json \
- test_exchange_api.conf \
- test_exchange_api_twisted.conf \
- test_exchange_api_keys_cherry_picking.conf \
- test_exchange_api_keys_cherry_picking_extended.conf \
- test_exchange_api_keys_cherry_picking_extended_2.conf \
- test_exchange_api_expire_reserve_now.conf \
- test-taler-exchange-aggregator-postgres.conf \
- test-taler-exchange-wirewatch-postgres.conf
diff --git a/src/lib/test_auditor_api.c b/src/lib/test_auditor_api.c
@@ -1,710 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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 lib/test_auditor_api.c
- * @brief testcase to test auditor's HTTP API interface
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_auditor_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_auditor_api.conf"
-
-#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
- "test_auditor_api_expire_reserve_now.conf"
-
-/**
- * Exchange configuration data.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Execute the taler-exchange-wirewatch command with
- * our configuration file.
- *
- * @param label label to use for the command.
- */
-#define CMD_EXEC_WIREWATCH(label) \
- TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
-
-/**
- * Execute the taler-exchange-aggregator command with
- * our configuration file.
- *
- * @param label label to use for the command.
- */
-#define CMD_EXEC_AGGREGATOR(label) \
- TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE)
-
-/**
- * Run wire transfer of funds from some user's account to the
- * exchange.
- *
- * @param label label to use for the command.
- * @param amount amount to transfer, i.e. "EUR:1"
- */
-#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
- TALER_TESTING_cmd_admin_add_incoming (label, amount, \
- &bc.exchange_auth, \
- bc.user42_payto)
-
-/**
- * Run the taler-auditor.
- *
- * @param label label to use for the command.
- */
-#define CMD_RUN_AUDITOR(label) \
- TALER_TESTING_cmd_exec_auditor (label, CONFIG_FILE)
-
-/**
- * Run the taler-wire-auditor.
- *
- * @param label label to use for the command.
- */
-#define CMD_RUN_WIRE_AUDITOR(label) \
- TALER_TESTING_cmd_exec_wire_auditor (label, CONFIG_FILE)
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- /**
- * Test withdraw.
- */
- struct TALER_TESTING_Command withdraw[] = {
- /**
- * Move money to the exchange's bank account.
- */
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check-create-reserve-1",
- "EUR:5.01", bc.user42_payto, bc.exchange_payto,
- "create-reserve-1"),
- /**
- * Make a reserve exist, according to the previous transfer.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-1"),
- /**
- * Withdraw EUR:5.
- */
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
- "create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command spend[] = {
- /**
- * Spend the coin.
- */
- TALER_TESTING_cmd_deposit ("deposit-simple",
- "withdraw-coin-1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command refresh[] = {
- /* Fill reserve with EUR:5, 1ct is for fees. NOTE: the old
- * test-suite gave a account number of _424_ to the user at
- * this step; to type less, here the _42_ number is reused.
- * Does this change the tests semantics? *///
- CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check-refresh-create-reserve-1",
- "EUR:5.01", bc.user42_payto, bc.exchange_payto,
- "refresh-create-reserve-1"),
- /**
- * Make previous command effective.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-2"),
- /**
- * Withdraw EUR:5.
- */
- TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
- "refresh-create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in
- * full) Merchant receives EUR:0.99 due to 1 ct deposit fee.
- */
- TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
- "refresh-withdraw-coin-1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:1\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x
- * EUR:0.13) */
- TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1",
- "refresh-withdraw-coin-1",
- MHD_HTTP_OK,
- NULL),
- /**
- * Complete (successful) melt operation, and withdraw the coins
- */
- TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1",
- "refresh-melt-1",
- MHD_HTTP_OK),
- /**
- * Try to spend a refreshed EUR:0.1 coin
- */
- TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b",
- "refresh-reveal-1",
- 3,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command track[] = {
- /**
- * Run transfers. Note that _actual_ aggregation will NOT
- * happen here, as each deposit operation is run with a
- * fresh merchant public key! NOTE: this comment comes
- * "verbatim" from the old test-suite, and IMO does not explain
- * a lot!*///
- CMD_EXEC_AGGREGATOR ("run-aggregator"),
-
- /**
- * Check all the transfers took place.
- */
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-499c", ec.exchange_url,
- "EUR:4.98", bc.exchange_payto, bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-99c1", ec.exchange_url,
- "EUR:0.98", bc.exchange_payto, bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check_bank_transfer-99c", ec.exchange_url,
- "EUR:0.08", bc.exchange_payto, bc.user43_payto),
-
- /* The following transactions got originated within
- * the "massive deposit confirms" batch. */
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-1",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-2",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-3",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-4",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-5",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-6",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-7",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-8",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-9",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_transfer
- ("check-massive-transfer-10",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto, bc.user43_payto),
- TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
- TALER_TESTING_cmd_end ()
- };
-
- /**
- * This block checks whether a wire deadline
- * very far in the future does NOT get aggregated now.
- */
- struct TALER_TESTING_Command unaggregation[] = {
- TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"),
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated",
- "EUR:5.01"),
- CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"),
- /* "consume" reserve creation transfer. */
- TALER_TESTING_cmd_check_bank_admin_transfer (
- "check_bank_transfer-unaggregated",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "create-reserve-unaggregated"),
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
- "create-reserve-unaggregated",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("deposit-unaggregated",
- "withdraw-coin-unaggregated",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_YEARS,
- 3000),
- "EUR:5",
- MHD_HTTP_OK),
- CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
- TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-b"),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command refund[] = {
- /**
- * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config.
- */
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1",
- "EUR:5.01"),
- /**
- * Run wire-watch to trigger the reserve creation.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-3"),
- /**
- * Withdraw a 5 EUR coin, at fee of 1 ct
- */
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
- "create-reserve-r1",
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Spend 5 EUR of the 5 EUR coin (in full). Merchant would
- * receive EUR:4.99 due to 1 ct deposit fee.
- */
- TALER_TESTING_cmd_deposit ("deposit-refund-1",
- "withdraw-coin-r1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_MINUTES,
- "EUR:5",
- MHD_HTTP_OK),
-
- TALER_TESTING_cmd_refund ("refund-ok",
- MHD_HTTP_OK,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-1"),
- /**
- * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone
- * due to refund) (merchant would receive EUR:4.98 due to
- * 1 ct deposit fee) */
- TALER_TESTING_cmd_deposit ("deposit-refund-2",
- "withdraw-coin-r1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"more\",\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:4.99",
- MHD_HTTP_OK),
- /**
- * Run transfers. This will do the transfer as refund deadline was
- * 0.
- */
- CMD_EXEC_AGGREGATOR ("run-aggregator-3"),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command recoup[] = {
- /**
- * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
- * config.
- */
- CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1",
- "EUR:5.01"),
- /**
- * Run wire-watch to trigger the reserve creation.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-4"),
- /**
- * Withdraw a 5 EUR coin, at fee of 1 ct
- */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
- "recoup-create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_revoke ("revoke-1",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-1",
- CONFIG_FILE),
- TALER_TESTING_cmd_recoup ("recoup-1",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-1",
- "EUR:5",
- NULL),
- /**
- * Re-withdraw from this reserve
- */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
- "recoup-create-reserve-1",
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * These commands should close the reserve because the aggregator
- * is given a config file that ovverrides the reserve expiration
- * time (making it now-ish)
- */CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
- "EUR:5.01"),
- TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
- TALER_TESTING_cmd_exec_aggregator ("close-reserves",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
- /**
- * Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
- * config, then withdraw two coin, partially spend one, and
- * then have the rest paid back. Check deposit of other coin
- * fails. (Do not use EUR:5 here as the EUR:5 coin was
- * revoked and we did not bother to create a new one...)
- */CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2",
- "EUR:2.02"),
- /**
- * Make previous command effective.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-5"),
- /**
- * Withdraw a 1 EUR coin, at fee of 1 ct
- */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
- "recoup-create-reserve-2",
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * Withdraw a 1 EUR coin, at fee of 1 ct
- */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
- "recoup-create-reserve-2",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
- "recoup-withdraw-coin-2a",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_revoke ("revoke-2",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-2a",
- CONFIG_FILE),
- TALER_TESTING_cmd_recoup ("recoup-2",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-2a",
- "EUR:0.5",
- NULL),
- TALER_TESTING_cmd_end ()
- };
-
-
- struct TALER_TESTING_Command massive_deposit_confirms[] = {
-
- /**
- * Move money to the exchange's bank account.
- */
- CMD_TRANSFER_TO_EXCHANGE ("massive-reserve",
- "EUR:10.10"),
- TALER_TESTING_cmd_check_bank_admin_transfer
- ("check-massive-transfer",
- "EUR:10.10",
- bc.user42_payto, bc.exchange_payto,
- "massive-reserve"),
- CMD_EXEC_WIREWATCH ("massive-wirewatch"),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10",
- "massive-reserve",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-1",
- "massive-withdraw-1",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-2",
- "massive-withdraw-2",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-3",
- "massive-withdraw-3",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-4",
- "massive-withdraw-4",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-5",
- "massive-withdraw-5",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-6",
- "massive-withdraw-6",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-7",
- "massive-withdraw-7",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-8",
- "massive-withdraw-8",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-9",
- "massive-withdraw-9",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("massive-deposit-10",
- "massive-withdraw-10",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation",
- is->auditor,
- "massive-deposit-10",
- 0,
- "EUR:0.99",
- MHD_HTTP_OK),
- CMD_RUN_AUDITOR ("massive-auditor"),
-
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command commands[] = {
- CMD_RUN_AUDITOR ("virgin-auditor"),
- CMD_RUN_WIRE_AUDITOR ("virgin-wire-auditor"),
- TALER_TESTING_cmd_exchanges_with_url ("check-exchange",
- MHD_HTTP_OK,
- "http://localhost:8081/"),
- TALER_TESTING_cmd_batch ("massive-deposit-confirms",
- massive_deposit_confirms),
- TALER_TESTING_cmd_batch ("withdraw",
- withdraw),
- TALER_TESTING_cmd_batch ("spend",
- spend),
- TALER_TESTING_cmd_batch ("refresh",
- refresh),
- TALER_TESTING_cmd_batch ("track",
- track),
- TALER_TESTING_cmd_batch ("unaggregation",
- unaggregation),
- TALER_TESTING_cmd_batch ("refund",
- refund),
- TALER_TESTING_cmd_batch ("recoup",
- recoup),
- CMD_RUN_AUDITOR ("normal-auditor"),
- CMD_RUN_WIRE_AUDITOR ("normal-wire-auditor"),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_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-auditor-api",
- "INFO",
- NULL);
- /* Check fakebank port is available and get configuration data. */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &ec))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_auditor_setup (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_auditor_api.c */
diff --git a/src/lib/test_auditor_api_version.c b/src/lib/test_auditor_api_version.c
@@ -1,163 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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 lib/test_auditor_api_version.c
- * @brief testcase to test auditor's HTTP API interface to fetch /version
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_auditor_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_auditor_api.conf"
-
-static struct TALER_AUDITOR_Handle *ah;
-
-static struct GNUNET_CURL_Context *ctx;
-
-static struct GNUNET_CURL_RescheduleContext *rc;
-
-static int global_ret;
-
-static struct GNUNET_SCHEDULER_Task *tt;
-
-static void
-do_shutdown (void *cls)
-{
- (void) cls;
-
- if (NULL != tt)
- {
- GNUNET_SCHEDULER_cancel (tt);
- tt = NULL;
- }
- TALER_AUDITOR_disconnect (ah);
- GNUNET_CURL_fini (ctx);
- GNUNET_CURL_gnunet_rc_destroy (rc);
-}
-
-
-static void
-do_timeout (void *cls)
-{
- (void) cls;
- tt = NULL;
- global_ret = 3;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Function called with information about the auditor.
- *
- * @param cls closure
- * @param vi basic information about the auditor
- * @param compat protocol compatibility information
- */
-static void
-version_cb (void *cls,
- const struct TALER_AUDITOR_VersionInformation *vi,
- enum TALER_AUDITOR_VersionCompatibility compat)
-{
- if ( (NULL != vi) &&
- (TALER_AUDITOR_VC_MATCH == compat) )
- global_ret = 0;
- else
- global_ret = 2;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls)
-{
- const char *auditor_url = "http://localhost:8083/";
-
- (void) cls;
- ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
- &rc);
- rc = GNUNET_CURL_gnunet_rc_create (ctx);
- ah = TALER_AUDITOR_connect (ctx,
- auditor_url,
- &version_cb,
- NULL);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
- NULL);
- tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
- &do_timeout,
- NULL);
-}
-
-
-int
-main (int argc,
- char *const *argv)
-{
- struct GNUNET_OS_Process *proc;
-
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-auditor-api-version",
- "INFO",
- NULL);
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-httpd",
- "taler-auditor-httpd",
- "-c", CONFIG_FILE,
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-httpd`,"
- " is your PATH correct?\n");
- return 77;
- }
- GNUNET_SCHEDULER_run (&run,
- NULL);
- GNUNET_OS_process_kill (proc, SIGTERM);
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
- return global_ret;
-}
-
-
-/* end of test_auditor_api_version.c */
diff --git a/src/lib/test_bank_api.c b/src/lib/test_bank_api.c
@@ -1,186 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2016-2020 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/test_bank_api.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 "taler_testing_lib.h"
-
-#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank.conf"
-#define CONFIG_FILE_PYBANK "test_bank_api_pybank.conf"
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Handle to the Py-bank daemon.
- */
-static struct GNUNET_OS_Process *bankd;
-
-/**
- * Flag indicating whether the test is running against the
- * Fakebank. Set up at runtime.
- */
-static int with_fakebank;
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_WireTransferIdentifierRawP wtid;
-
- memset (&wtid, 42, sizeof (wtid));
-
- {
- struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_bank_credits ("history-0",
- &bc.exchange_auth,
- NULL,
- 1),
- TALER_TESTING_cmd_admin_add_incoming ("credit-1",
- "KUDOS:5.01",
- &bc.exchange_auth,
- bc.user42_payto),
- TALER_TESTING_cmd_bank_credits ("history-1c",
- &bc.exchange_auth,
- NULL,
- 5),
- TALER_TESTING_cmd_bank_debits ("history-1d",
- &bc.exchange_auth,
- NULL,
- 5),
- TALER_TESTING_cmd_admin_add_incoming ("credit-2",
- "KUDOS:3.21",
- &bc.exchange_auth,
- bc.user42_payto),
- TALER_TESTING_cmd_transfer ("debit-1",
- "KUDOS:3.22",
- &bc.exchange_auth,
- bc.exchange_payto,
- bc.user42_payto,
- &wtid,
- "http://exchange.example.com/"),
- TALER_TESTING_cmd_bank_debits ("history-2b",
- &bc.exchange_auth,
- NULL,
- 5),
- TALER_TESTING_cmd_end ()
- };
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Bank serves at `%s'\n",
- bc.exchange_auth.wire_gateway_url);
- if (GNUNET_YES == with_fakebank)
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
- else
- TALER_TESTING_run (is,
- commands);
- }
-}
-
-
-int
-main (int argc,
- char *const *argv)
-{
- int rv;
- const char *cfgfilename;
-
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-bank-api",
- "DEBUG",
- NULL);
- with_fakebank = TALER_TESTING_has_in_name (argv[0],
- "_with_fakebank");
- if (GNUNET_YES == with_fakebank)
- {
- TALER_LOG_DEBUG ("Running against the Fakebank.\n");
- cfgfilename = CONFIG_FILE_FAKEBANK;
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE_FAKEBANK,
- "account-2",
- &bc))
- {
- GNUNET_break (0);
- return 77;
- }
- }
- else
- {
- TALER_LOG_DEBUG ("Running against the Pybank.\n");
- cfgfilename = CONFIG_FILE_PYBANK;
- if (GNUNET_OK !=
- TALER_TESTING_prepare_bank (CONFIG_FILE_PYBANK,
- "account-2",
- &bc))
- {
- GNUNET_break (0);
- return 77;
- }
-
- if (NULL == (bankd = TALER_TESTING_run_bank (CONFIG_FILE_PYBANK,
- bc.exchange_auth.
- wire_gateway_url)))
- {
- GNUNET_break (0);
- return 77;
- }
- }
-
- rv = (GNUNET_OK == TALER_TESTING_setup (&run,
- NULL,
- cfgfilename,
- NULL,
- GNUNET_NO)) ? 0 : 1;
- if (GNUNET_NO == with_fakebank)
- {
-
- GNUNET_OS_process_kill (bankd,
- SIGKILL);
- GNUNET_OS_process_wait (bankd);
- GNUNET_OS_process_destroy (bankd);
- }
- return rv;
-}
-
-
-/* end of test_bank_api.c */
diff --git a/src/lib/test_bank_api_twisted.c b/src/lib/test_bank_api_twisted.c
@@ -1,221 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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 lib/test_bank_api_with_fakebank_twisted.c
- * @author Marcello Stanisci
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-#include <taler/taler_twister_testing_lib.h>
-#include <taler/taler_twister_service.h>
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank_twisted.conf"
-
-/**
- * Separate config file for running with the pybank.
- */
-#define CONFIG_FILE_PYBANK "test_bank_api_pybank_twisted.conf"
-
-/**
- * True when the test runs against Fakebank.
- */
-static int with_fakebank;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * (real) Twister URL. Used at startup time to check if it runs.
- */
-static char *twister_url;
-
-/**
- * Twister process.
- */
-static struct GNUNET_OS_Process *twisterd;
-
-/**
- * Python bank process handle.
- */
-static struct GNUNET_OS_Process *bankd;
-
-
-/**
- * Main function that will tell
- * the interpreter what commands to run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
-
- struct TALER_TESTING_Command commands[] = {
- /**
- * Can't use the "wait service" CMD here because the
- * fakebank runs inside the same process of the test.
- */
- TALER_TESTING_cmd_wait_service ("wait-service",
- twister_url),
- TALER_TESTING_cmd_bank_credits ("history-0",
- &bc.exchange_auth,
- NULL,
- 5),
- TALER_TESTING_cmd_end ()
- };
-
- if (GNUNET_YES == with_fakebank)
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
- else
- TALER_TESTING_run (is,
- commands);
-}
-
-
-/**
- * Kill, wait, and destroy convenience function.
- *
- * @param process process to purge.
- */
-static void
-purge_process (struct GNUNET_OS_Process *process)
-{
- GNUNET_OS_process_kill (process, SIGINT);
- GNUNET_OS_process_wait (process);
- GNUNET_OS_process_destroy (process);
-}
-
-
-int
-main (int argc,
- char *const *argv)
-{
- unsigned int ret;
- const char *cfgfilename;
-
- /* These environment variables get in the way... */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test-bank-api-with-(fake)bank-twisted",
- "DEBUG",
- NULL);
-
- with_fakebank = TALER_TESTING_has_in_name (argv[0],
- "_with_fakebank");
-
- if (with_fakebank)
- cfgfilename = CONFIG_FILE_FAKEBANK;
- else
- cfgfilename = CONFIG_FILE_PYBANK;
-
- if (NULL == (twister_url = TALER_TESTING_prepare_twister
- (cfgfilename)))
- {
- GNUNET_break (0);
- return 77;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "twister_url is %s\n",
- twister_url);
- if (NULL == (twisterd = TALER_TESTING_run_twister (cfgfilename)))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
-
- if (GNUNET_YES == with_fakebank)
- {
- TALER_LOG_DEBUG ("Running against the Fakebank.\n");
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (cfgfilename,
- "account-2",
- &bc))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
- }
- else
- {
- TALER_LOG_DEBUG ("Running against the Pybank.\n");
- if (GNUNET_OK !=
- TALER_TESTING_prepare_bank (cfgfilename,
- "account-2",
- &bc))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
-
- if (NULL == (bankd = TALER_TESTING_run_bank (cfgfilename,
- bc.exchange_auth.
- wire_gateway_url)))
- {
- GNUNET_break (0);
- GNUNET_free (twister_url);
- return 77;
- }
- }
-
- ret = TALER_TESTING_setup (&run,
- NULL,
- cfgfilename,
- NULL,
- GNUNET_NO);
- purge_process (twisterd);
-
- if (GNUNET_NO == with_fakebank)
- {
- GNUNET_OS_process_kill (bankd,
- SIGKILL);
- GNUNET_OS_process_wait (bankd);
- GNUNET_OS_process_destroy (bankd);
- }
-
- GNUNET_free (twister_url);
- if (GNUNET_OK == ret)
- return 0;
-
- return 1;
-}
-
-
-/* end of test_bank_api_twisted.c */
diff --git a/src/lib/test_exchange_api.c b/src/lib/test_exchange_api.c
@@ -1,832 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014--2020 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 lib/test_exchange_api.c
- * @brief testcase to test exchange's HTTP API interface
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_exchange_api.conf"
-
-#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
- "test_exchange_api_expire_reserve_now.conf"
-
-
-/**
- * Exchange configuration data.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-
-/**
- * Execute the taler-exchange-wirewatch command with
- * our configuration file.
- *
- * @param label label to use for the command.
- */
-#define CMD_EXEC_WIREWATCH(label) \
- TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
-
-/**
- * Execute the taler-exchange-aggregator command with
- * our configuration file.
- *
- * @param label label to use for the command.
- */
-#define CMD_EXEC_AGGREGATOR(label) \
- TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE)
-
-/**
- * Run wire transfer of funds from some user's account to the
- * exchange.
- *
- * @param label label to use for the command.
- * @param amount amount to transfer, i.e. "EUR:1"
- */
-#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
- TALER_TESTING_cmd_admin_add_incoming (label, amount, \
- &bc.exchange_auth, \
- bc.user42_payto)
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- * @param is interpreter we use to run commands
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- /**
- * Checks made against /wire response.
- */
- struct TALER_TESTING_Command wire[] = {
- /**
- * Check if 'x-taler-bank' wire method is offered
- * by the exchange.
- */
- TALER_TESTING_cmd_wire ("wire-taler-bank-1",
- "x-taler-bank",
- NULL,
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- /**
- * Test withdrawal plus spending.
- */
- struct TALER_TESTING_Command withdraw[] = {
- /**
- * Move money to the exchange's bank account.
- */
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "create-reserve-1"),
- /**
- * Make a reserve exist, according to the previous
- * transfer.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-1"),
- /**
- * Withdraw EUR:5.
- */
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
- "create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Check the reserve is depleted.
- */
- TALER_TESTING_cmd_status ("status-1",
- "create-reserve-1",
- "EUR:0",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command spend[] = {
- /**
- * Spend the coin.
- */
- TALER_TESTING_cmd_deposit ("deposit-simple",
- "withdraw-coin-1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Try to overdraw.
- */
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
- "create-reserve-1",
- "EUR:5",
- MHD_HTTP_CONFLICT),
- /**
- * Try to double spend using different wire details.
- */
- TALER_TESTING_cmd_deposit ("deposit-double-1",
- "withdraw-coin-1",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:5",
- MHD_HTTP_CONFLICT),
- /* Try to double spend using a different transaction id.
- * The test needs the contract terms to differ. This
- * is currently the case because of the "timestamp" field,
- * which is set automatically by #TALER_TESTING_cmd_deposit().
- * This could theoretically fail if at some point a deposit
- * command executs in less than 1 ms. *///
- TALER_TESTING_cmd_deposit ("deposit-double-1",
- "withdraw-coin-1",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:5",
- MHD_HTTP_CONFLICT),
- /**
- * Try to double spend with different proposal.
- */
- TALER_TESTING_cmd_deposit ("deposit-double-2",
- "withdraw-coin-1",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:5",
- MHD_HTTP_CONFLICT),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command refresh[] = {
- /* Fill reserve with EUR:5, 1ct is for fees. */
- CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("ck-refresh-create-reserve-1",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "refresh-create-reserve-1"),
- /**
- * Make previous command effective.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-2"),
- /**
- * Withdraw EUR:5.
- */
- TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
- "refresh-create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin
- * (in full) (merchant would receive EUR:0.99 due to 1 ct
- * deposit fee) *///
- TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
- "refresh-withdraw-coin-1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * Melt the rest of the coin's value
- * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
- TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1",
- "refresh-withdraw-coin-1",
- MHD_HTTP_OK,
- NULL),
- /**
- * Complete (successful) melt operation, and
- * withdraw the coins
- */
- TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1",
- "refresh-melt-1",
- MHD_HTTP_OK),
- /**
- * Do it again to check idempotency
- */
- TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1-idempotency",
- "refresh-melt-1",
- MHD_HTTP_OK),
- /**
- * Test that /refresh/link works
- */
- TALER_TESTING_cmd_refresh_link ("refresh-link-1",
- "refresh-reveal-1",
- MHD_HTTP_OK),
- /**
- * Try to spend a refreshed EUR:1 coin
- */
- TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1a",
- "refresh-reveal-1-idempotency",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * Try to spend a refreshed EUR:0.1 coin
- */
- TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b",
- "refresh-reveal-1",
- 3,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.1",
- MHD_HTTP_OK),
- /* Test running a failing melt operation (same operation
- * again must fail) */
- TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing",
- "refresh-withdraw-coin-1",
- MHD_HTTP_CONFLICT,
- NULL),
- /* Test running a failing melt operation (on a coin that
- was itself revealed and subsequently deposited) */
- TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing-2",
- "refresh-reveal-1",
- MHD_HTTP_CONFLICT,
- NULL),
-
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command track[] = {
- /* Try resolving a deposit's WTID, as we never triggered
- * execution of transactions, the answer should be that
- * the exchange knows about the deposit, but has no WTID yet.
- *///
- TALER_TESTING_cmd_track_transaction ("deposit-wtid-found",
- "deposit-simple",
- 0,
- MHD_HTTP_ACCEPTED,
- NULL),
- /* Try resolving a deposit's WTID for a failed deposit.
- * As the deposit failed, the answer should be that the
- * exchange does NOT know about the deposit.
- *///
- TALER_TESTING_cmd_track_transaction ("deposit-wtid-failing",
- "deposit-double-2",
- 0,
- MHD_HTTP_NOT_FOUND,
- NULL),
- /* Try resolving an undefined (all zeros) WTID; this
- * should fail as obviously the exchange didn't use that
- * WTID value for any transaction.
- *///
- TALER_TESTING_cmd_track_transfer_empty ("wire-deposit-failing",
- NULL,
- 0,
- MHD_HTTP_NOT_FOUND),
- /* Run transfers. Note that _actual_ aggregation will NOT
- * happen here, as each deposit operation is run with a
- * fresh merchant public key, so the aggregator will treat
- * them as "different" merchants and do the wire transfers
- * individually. *///
- CMD_EXEC_AGGREGATOR ("run-aggregator"),
- /**
- * Check all the transfers took place.
- */
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c",
- ec.exchange_url,
- "EUR:4.98",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c2",
- ec.exchange_url,
- "EUR:0.98",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c",
- ec.exchange_url,
- "EUR:0.08",
- bc.exchange_payto,
- bc.user43_payto),
- TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
- TALER_TESTING_cmd_track_transaction ("deposit-wtid-ok",
- "deposit-simple",
- 0,
- MHD_HTTP_OK,
- "check_bank_transfer-499c"),
- TALER_TESTING_cmd_track_transfer ("wire-deposit-success-bank",
- "check_bank_transfer-99c1",
- 0,
- MHD_HTTP_OK,
- "EUR:0.98",
- "EUR:0.01"),
- TALER_TESTING_cmd_track_transfer ("wire-deposits-success-wtid",
- "deposit-wtid-ok",
- 0,
- MHD_HTTP_OK,
- "EUR:4.98",
- "EUR:0.01"),
- TALER_TESTING_cmd_end ()
- };
-
-
- /**
- * This block checks whether a wire deadline
- * very far in the future does NOT get aggregated now.
- */
- struct TALER_TESTING_Command unaggregation[] = {
- TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"),
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated",
- "EUR:5.01"),
- /* "consume" reserve creation transfer. */
- TALER_TESTING_cmd_check_bank_admin_transfer (
- "check-create-reserve-unaggregated",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "create-reserve-unaggregated"),
- CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"),
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
- "create-reserve-unaggregated",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("deposit-unaggregated",
- "withdraw-coin-unaggregated",
- 0,
- bc.user43_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
- GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_YEARS,
- 3000),
- "EUR:5",
- MHD_HTTP_OK),
- CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
-
- TALER_TESTING_cmd_check_bank_empty
- ("far-future-aggregation-b"),
-
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command refund[] = {
- /**
- * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
- * config.
- */
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-r1",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "create-reserve-r1"),
- /**
- * Run wire-watch to trigger the reserve creation.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-3"),
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
- "create-reserve-r1",
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Spend 5 EUR of the 5 EUR coin (in full) (merchant would
- * receive EUR:4.99 due to 1 ct deposit fee)
- */
- TALER_TESTING_cmd_deposit ("deposit-refund-1",
- "withdraw-coin-r1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_MINUTES,
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Run transfers. Should do nothing as refund deadline blocks it
- */
- CMD_EXEC_AGGREGATOR ("run-aggregator-refund"),
- /* Check that aggregator didn't do anything, as expected.
- * Note, this operation takes two commands: one to "flush"
- * the preliminary transfer (used to withdraw) from the
- * fakebank and the second to actually check there are not
- * other transfers around. *///
- TALER_TESTING_cmd_check_bank_empty ("check_bank_transfer-pre-refund"),
- TALER_TESTING_cmd_refund ("refund-ok",
- MHD_HTTP_OK,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-1"),
- TALER_TESTING_cmd_refund ("refund-ok-double",
- MHD_HTTP_OK,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-1"),
- /* Previous /refund(s) had id == 0. */
- TALER_TESTING_cmd_refund_with_id ("refund-conflicting",
- MHD_HTTP_CONFLICT,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-1",
- 1),
- /**
- * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone
- * due to refund) (merchant would receive EUR:4.98 due to
- * 1 ct deposit fee) */
- TALER_TESTING_cmd_deposit ("deposit-refund-2",
- "withdraw-coin-r1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:4.99",
- MHD_HTTP_OK),
- /**
- * Run transfers. This will do the transfer as refund deadline
- * was 0
- */
- CMD_EXEC_AGGREGATOR ("run-aggregator-3"),
- /**
- * Check that deposit did run.
- */
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-pre-refund",
- ec.exchange_url,
- "EUR:4.97",
- bc.exchange_payto,
- bc.user42_payto),
- /**
- * Run failing refund, as past deadline & aggregation.
- */
- TALER_TESTING_cmd_refund ("refund-fail",
- MHD_HTTP_GONE,
- "EUR:4.99",
- "EUR:0.01",
- "deposit-refund-2"),
- TALER_TESTING_cmd_check_bank_empty ("check-empty-after-refund"),
- /**
- * Test refunded coins are never executed, even past
- * refund deadline
- */
- CMD_TRANSFER_TO_EXCHANGE ("create-reserve-rb",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-rb",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "create-reserve-rb"),
- CMD_EXEC_WIREWATCH ("wirewatch-rb"),
- TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb",
- "create-reserve-rb",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("deposit-refund-1b",
- "withdraw-coin-rb",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:5",
- MHD_HTTP_OK),
- /**
- * Trigger refund (before aggregator had a chance to execute
- * deposit, even though refund deadline was zero).
- */
- TALER_TESTING_cmd_refund ("refund-ok-fast",
- MHD_HTTP_OK,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-1b"),
- /**
- * Run transfers. This will do the transfer as refund deadline
- * was 0, except of course because the refund succeeded, the
- * transfer should no longer be done.
- */CMD_EXEC_AGGREGATOR ("run-aggregator-3b"),
- /* check that aggregator didn't do anything, as expected */
- TALER_TESTING_cmd_check_bank_empty ("check-refund-fast-not-run"),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command recoup[] = {
- /**
- * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
- * config.
- */
- CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("recoup-create-reserve-1",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "recoup-create-reserve-1"),
- /**
- * Run wire-watch to trigger the reserve creation.
- */
- CMD_EXEC_WIREWATCH ("wirewatch-4"),
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
- "recoup-create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- /* Make coin invalid */
- TALER_TESTING_cmd_revoke ("revoke-0-EUR:5",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-1",
- CONFIG_FILE),
- /* Refund coin to bank account */
- TALER_TESTING_cmd_recoup ("recoup-1",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-1",
- "EUR:5",
- NULL),
- /* Check the money is back with the reserve */
- TALER_TESTING_cmd_status ("recoup-reserve-status-1",
- "recoup-create-reserve-1",
- "EUR:5.0",
- MHD_HTTP_OK),
- /* Re-withdraw from this reserve */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
- "recoup-create-reserve-1",
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * This withdrawal will test the logic to create a "recoup"
- * element to insert into the reserve's history.
- */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over",
- "recoup-create-reserve-1",
- "EUR:10",
- MHD_HTTP_CONFLICT),
- TALER_TESTING_cmd_status ("recoup-reserve-status-2",
- "recoup-create-reserve-1",
- "EUR:3.99",
- MHD_HTTP_OK),
-
- /* These commands should close the reserve because
- * the aggregator is given a config file that ovverrides
- * the reserve expiration time (making it now-ish) */
- CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
- "EUR:5.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("check-short-lived-reserve",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "short-lived-reserve"),
- TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
-
- TALER_TESTING_cmd_exec_aggregator ("close-reserves",
- CONFIG_FILE_EXPIRE_RESERVE_NOW),
-
- TALER_TESTING_cmd_status ("short-lived-status",
- "short-lived-reserve",
- "EUR:0",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_withdraw_amount ("expired-withdraw",
- "short-lived-reserve",
- "EUR:1",
- MHD_HTTP_CONFLICT),
- TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse",
- ec.exchange_url,
- "EUR:5",
- bc.exchange_payto,
- bc.user42_payto),
- /* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
- * config, then withdraw two coin, partially spend one, and
- * then have the rest paid back. Check deposit of other coin
- * fails. Do not use EUR:5 here as the EUR:5 coin was
- * revoked and we did not bother to create a new one... *///
- CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2",
- "EUR:2.02"),
- TALER_TESTING_cmd_check_bank_admin_transfer ("ck-recoup-create-reserve-2",
- "EUR:2.02",
- bc.user42_payto,
- bc.exchange_payto,
- "recoup-create-reserve-2"),
- /* Make previous command effective. */
- CMD_EXEC_WIREWATCH ("wirewatch-5"),
- /* Withdraw a 1 EUR coin, at fee of 1 ct */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
- "recoup-create-reserve-2",
- "EUR:1",
- MHD_HTTP_OK),
- /* Withdraw a 1 EUR coin, at fee of 1 ct */
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
- "recoup-create-reserve-2",
- "EUR:1",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
- "recoup-withdraw-coin-2a",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_revoke ("revoke-1-EUR:1",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-2a",
- CONFIG_FILE),
- TALER_TESTING_cmd_recoup ("recoup-2",
- MHD_HTTP_OK,
- "recoup-withdraw-coin-2a",
- "EUR:0.5",
- NULL),
- TALER_TESTING_cmd_recoup ("recoup-2b",
- MHD_HTTP_CONFLICT,
- "recoup-withdraw-coin-2a",
- "EUR:0.5",
- NULL),
- TALER_TESTING_cmd_deposit ("recoup-deposit-revoked",
- "recoup-withdraw-coin-2b",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_NOT_FOUND),
- /* Test deposit fails after recoup, with proof in recoup */
-
- /* Note that, the exchange will never return the coin's transaction
- * history with recoup data, as we get a 404 on the DK! */
- TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup",
- "recoup-withdraw-coin-2a",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.5",
- MHD_HTTP_NOT_FOUND),
- /* Test that revoked coins cannot be withdrawn */
- CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3",
- "EUR:1.01"),
- TALER_TESTING_cmd_check_bank_admin_transfer (
- "check-recoup-create-reserve-3",
- "EUR:1.01",
- bc.user42_payto,
- bc.exchange_payto,
- "recoup-create-reserve-3"),
- CMD_EXEC_WIREWATCH ("wirewatch-6"),
- TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked",
- "recoup-create-reserve-3",
- "EUR:1",
- MHD_HTTP_NOT_FOUND),
- /* check that we are empty before the rejection test */
- TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
-
- TALER_TESTING_cmd_end ()
- };
-
-#define RESERVE_OPEN_CLOSE_CHUNK 4
-#define RESERVE_OPEN_CLOSE_ITERATIONS 3
-
- struct TALER_TESTING_Command reserve_open_close[(RESERVE_OPEN_CLOSE_ITERATIONS
- * RESERVE_OPEN_CLOSE_CHUNK)
- + 1];
- for (unsigned int i = 0;
- i < RESERVE_OPEN_CLOSE_ITERATIONS;
- i++)
- {
- reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 0]
- = CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key",
- "EUR:20");
- reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1]
- = TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch",
- CONFIG_FILE_EXPIRE_RESERVE_NOW);
- reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2]
- = TALER_TESTING_cmd_exec_aggregator ("reserve-open-close-aggregation",
- CONFIG_FILE_EXPIRE_RESERVE_NOW);
- reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 3]
- = TALER_TESTING_cmd_status ("reserve-open-close-status",
- "reserve-open-close-key",
- "EUR:0",
- MHD_HTTP_OK);
- }
- reserve_open_close[RESERVE_OPEN_CLOSE_ITERATIONS * RESERVE_OPEN_CLOSE_CHUNK]
- = TALER_TESTING_cmd_end ();
-
- {
- struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_batch ("wire",
- wire),
- TALER_TESTING_cmd_batch ("withdraw",
- withdraw),
- TALER_TESTING_cmd_batch ("spend",
- spend),
- TALER_TESTING_cmd_batch ("refresh",
- refresh),
- TALER_TESTING_cmd_batch ("track",
- track),
- TALER_TESTING_cmd_batch ("unaggregation",
- unaggregation),
- TALER_TESTING_cmd_batch ("refund",
- refund),
- TALER_TESTING_cmd_batch ("recoup",
- recoup),
- TALER_TESTING_cmd_batch ("reserve-open-close",
- reserve_open_close),
- /* End the suite. */
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_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-exchange-api",
- "INFO",
- NULL);
- /* Check fakebank port is available and get config */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &ec))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_exchange_api.c */
diff --git a/src/lib/test_exchange_api_interpreter_on-off.c b/src/lib/test_exchange_api_interpreter_on-off.c
@@ -1,128 +0,0 @@
-/*
- 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 lib/test_exchange_api_keys_cherry_picking_new.c
- * @brief testcase to test exchange's /keys cherry picking ability
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-/**
- * XXX:
- *
- * This test helps in finding a way to use/modify the "normal"
- * cert_cb to handle reconnections from serialized states as well.
- *
- * 1st step: simply turn the interpreter off and on again.
- * 2nd step: turn the interpreter off and give a serial state
- * to reconnect.
- */
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
-
-/**
- * Exchange base URL; mainly purpose is to make the compiler happy.
- */
-static char *exchange_url;
-
-/**
- * Auditor base URL; mainly purpose is to make the compiler happy.
- */
-static char *auditor_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)
-{
-
- struct TALER_TESTING_Command commands[] = {
-
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run (is,
- commands);
-}
-
-
-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-exchange-api-cherry-picking-new",
- "DEBUG", NULL);
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &auditor_url,
- &exchange_url))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_exchange_api_keys_cherry_picking_new.c */
diff --git a/src/lib/test_exchange_api_keys_cherry_picking.c b/src/lib/test_exchange_api_keys_cherry_picking.c
@@ -1,263 +0,0 @@
-/*
- 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 lib/test_exchange_api_keys_cherry_picking.c
- * @brief testcase to test exchange's /keys cherry picking ability
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
-
-/**
- * Used to increase the number of denomination keys.
- */
-#define CONFIG_FILE_EXTENDED \
- "test_exchange_api_keys_cherry_picking_extended.conf"
-
-/**
- * Used to increase the number of denomination keys.
- */
-#define CONFIG_FILE_EXTENDED_2 \
- "test_exchange_api_keys_cherry_picking_extended_2.conf"
-
-
-#define NDKS_RIGHT_BEFORE_SERIALIZATION 46
-
-/**
- * Add seconds.
- *
- * @param base absolute time to add seconds to.
- * @param relative number of seconds to add.
- * @return a new absolute time, modified according to @e relative.
- */
-#define ADDSECS(base, secs) \
- GNUNET_TIME_absolute_add \
- (base, \
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
- secs))
-
-/**
- * Subtract seconds.
- *
- * @param base absolute time to subtract seconds to.
- * @param secs relative number of _seconds_ to subtract.
- * @return a new absolute time, modified according to @e relative.
- */
-#define SUBSECS(base, secs) \
- GNUNET_TIME_absolute_subtract \
- (base, \
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
- secs))
-#define JAN1971 "1971-01-01"
-#define JAN2030 "2030-01-01"
-
-/**
- * Exchange configuration data.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-
-/**
- * Wrapper around the time parser.
- *
- * @param str human-readable time string.
- * @return the parsed time from @a str.
- */
-static struct GNUNET_TIME_Absolute
-TTH_parse_time (const char *str)
-{
- struct GNUNET_TIME_Absolute ret;
-
- GNUNET_assert
- (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_absolute (str,
- &ret));
- return ret;
-}
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- * @param is[in,out] interpreter state
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command keys_serialization[] = {
- TALER_TESTING_cmd_serialize_keys
- ("serialize-keys"),
- TALER_TESTING_cmd_connect_with_state
- ("reconnect-with-state",
- "serialize-keys"),
- /**
- * Make sure we have the same keys situation as
- * it was before the serialization.
- */
- TALER_TESTING_cmd_check_keys_with_now
- ("check-keys-after-deserialization",
- 4,
- NDKS_RIGHT_BEFORE_SERIALIZATION,
- /**
- * Pretend 5 seconds passed.
- */
- ADDSECS (TTH_parse_time (JAN2030),
- 5)),
- /**
- * Use one of the deserialized keys.
- */
- TALER_TESTING_cmd_wire
- ("verify-/wire-with-serialized-keys",
- "x-taler-bank",
- NULL,
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end (),
- };
-
- struct TALER_TESTING_Command ordinary_cherry_pick[] = {
- /**
- * 1 DK with 80s withdraw duration, lookahead_sign is 60s
- * => expect 1 DK.
- */
- TALER_TESTING_cmd_check_keys ("check-keys-1",
- 1, /* generation */
- 1),
- /**
- * The far-future now will cause "keyup" to start a fresh
- * key set. The new KS will have only one key, because the
- * current lookahead_sign == 60 seconds and the key's withdraw
- * duration is 80 seconds.
- */TALER_TESTING_cmd_exec_keyup_with_now
- ("keyup-1",
- CONFIG_FILE,
- TTH_parse_time (JAN2030)),
- /**
- * Should return 1 new key, + the original one. NOTE: the
- * original DK will never be 'cancelled' as for the current
- * libtalerexchange logic, so it must always be counted.
- */TALER_TESTING_cmd_check_keys_with_now
- ("check-keys-2",
- 2, /* generation */
- 2,
- TTH_parse_time (JAN2030)),
- TALER_TESTING_cmd_exec_keyup_with_now
- ("keyup-3",
- CONFIG_FILE_EXTENDED_2,
- /* Taking care of not using a 'now' that equals the
- * last DK timestamp, otherwise it would get silently
- * overridden. */
- ADDSECS (TTH_parse_time (JAN2030),
- 10)),
-
- /**
- * Expected number of DK:
- *
- * 3500 (the lookahead_sign time frame, in seconds)
- * - 69 (how many seconds are covered by the latest DK)
- * ----
- * 3431
- * / 79 (how many seconds each DK will cover)
- * ----
- * 44 (rounded up)
- * + 2 (old DKs already stored locally: 1 from the
- * very initial setup, and 1 from the 'keyup-1' CMD)
- * ----
- * 46
- */TALER_TESTING_cmd_check_keys_with_now
- ("check-keys-3",
- 3,
- NDKS_RIGHT_BEFORE_SERIALIZATION,
- TTH_parse_time (JAN2030)),
-
- TALER_TESTING_cmd_end ()
- };
- struct TALER_TESTING_Command commands[] = {
-
- TALER_TESTING_cmd_batch ("ordinary-cherry-pick",
- ordinary_cherry_pick),
- TALER_TESTING_cmd_batch ("keys-serialization",
- keys_serialization),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run (is,
- commands);
-}
-
-
-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-exchange-api-cherry-picking",
- "DEBUG",
- NULL);
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &ec))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_exchange_api_keys_cherry_picking.c */
diff --git a/src/lib/test_exchange_api_overlapping_keys_bug.c b/src/lib/test_exchange_api_overlapping_keys_bug.c
@@ -1,130 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018, 2019 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 lib/test_exchange_api_overlapping_keys_bug.c
- * @brief testcase to test exchange's /keys cherry picking ability and
- * other /keys related operations
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
-
-/**
- * Used to increase the number of denomination keys.
- */
-#define CONFIG_FILE_EXTENDED \
- "test_exchange_api_keys_cherry_picking_extended.conf"
-
-/**
- * Used to increase the number of denomination keys.
- */
-#define CONFIG_FILE_EXTENDED_2 \
- "test_exchange_api_keys_cherry_picking_extended_2.conf"
-
-/**
- * Exchange configuration data.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_check_keys ("first-download",
- 1,
- 1),
- /* Causes GET /keys?last_denom_issue=0 */
- TALER_TESTING_cmd_check_keys_with_last_denom ("second-download",
- 3,
- 1,
- GNUNET_TIME_UNIT_ZERO_ABS),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run (is,
- commands);
-}
-
-
-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-exchange-api-overlapping-keys-bug",
- "DEBUG", NULL);
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &ec))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_exchange_api_overlapping_keys_bug.c */
diff --git a/src/lib/test_exchange_api_revocation.c b/src/lib/test_exchange_api_revocation.c
@@ -1,231 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014--2020 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 lib/test_exchange_api_revocation.c
- * @brief testcase to test key revocation handling via the exchange's HTTP API interface
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_exchange_api.conf"
-
-/**
- * Exchange configuration data.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command revocation[] = {
- /**
- * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
- * config.
- */
- TALER_TESTING_cmd_admin_add_incoming ("create-reserve-1",
- "EUR:5.01",
- &bc.exchange_auth,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
- "EUR:5.01",
- bc.user42_payto,
- bc.exchange_payto,
- "create-reserve-1"),
- /**
- * Run wire-watch to trigger the reserve creation.
- */
- TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4",
- CONFIG_FILE),
- /* Withdraw a 5 EUR coin, at fee of 1 ct */
- TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1",
- "create-reserve-1",
- "EUR:5",
- MHD_HTTP_OK),
- /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
- * (merchant would receive EUR:0.99 due to 1 ct deposit fee) *///
- TALER_TESTING_cmd_deposit ("deposit-partial",
- "withdraw-revocation-coin-1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
- /**
- * Melt SOME of the rest of the coin's value
- * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13) */
- TALER_TESTING_cmd_refresh_melt ("refresh-melt-1",
- "withdraw-revocation-coin-1",
- MHD_HTTP_OK,
- NULL),
- /**
- * Complete (successful) melt operation, and withdraw the coins
- */
- TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1",
- "refresh-melt-1",
- MHD_HTTP_OK),
- /* Make refreshed coin invalid */
- TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
- MHD_HTTP_OK,
- "refresh-melt-1",
- CONFIG_FILE),
- /* Refund coin to original coin */
- TALER_TESTING_cmd_recoup ("recoup-1a",
- MHD_HTTP_OK,
- "refresh-reveal-1#0",
- "EUR:1",
- "refresh-melt-1"),
- TALER_TESTING_cmd_recoup ("recoup-1b",
- MHD_HTTP_OK,
- "refresh-reveal-1#1",
- "EUR:1",
- "refresh-melt-1"),
- TALER_TESTING_cmd_recoup ("recoup-1c",
- MHD_HTTP_OK,
- "refresh-reveal-1#2",
- "EUR:1",
- "refresh-melt-1"),
- /* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */
- /* Melt original coin AGAIN, but only create one 0.1 EUR coin;
- This costs EUR:0.03 in refresh and EUR:01 in withdraw fees,
- leaving EUR:3.69. */
- TALER_TESTING_cmd_refresh_melt ("refresh-melt-2",
- "withdraw-revocation-coin-1",
- MHD_HTTP_OK,
- "EUR:0.1",
- NULL),
- /**
- * Complete (successful) melt operation, and withdraw the coins
- */
- TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-2",
- "refresh-melt-2",
- MHD_HTTP_OK),
- /* Revokes refreshed EUR:0.1 coin */
- TALER_TESTING_cmd_revoke ("revoke-3-EUR:0.1",
- MHD_HTTP_OK,
- "refresh-reveal-2",
- CONFIG_FILE),
- /* Revoke also original coin denomination */
- TALER_TESTING_cmd_revoke ("revoke-4-EUR:5",
- MHD_HTTP_OK,
- "withdraw-revocation-coin-1",
- CONFIG_FILE),
- /* Refund coin EUR:0.1 to original coin, creating zombie! */
- TALER_TESTING_cmd_recoup ("recoup-2",
- MHD_HTTP_OK,
- "refresh-reveal-2",
- "EUR:0.1",
- "refresh-melt-2"),
- /* Due to recoup, original coin is now at EUR:3.79 */
- /* Refund original (now zombie) coin to reserve */
- TALER_TESTING_cmd_recoup ("recoup-3",
- MHD_HTTP_OK,
- "withdraw-revocation-coin-1",
- "EUR:3.79",
- NULL),
- /* Check the money is back with the reserve */
- TALER_TESTING_cmd_status ("recoup-reserve-status-1",
- "create-reserve-1",
- "EUR:3.79",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run_with_fakebank (is,
- revocation,
- bc.exchange_auth.wire_gateway_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-exchange-api-revocation",
- "INFO",
- NULL);
- /* Check fakebank port is available and get config */
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "account-2",
- &bc))
- return 77;
- TALER_TESTING_cleanup_files (CONFIG_FILE);
- /* @helpers. Run keyup, create tables, ... Note: it
- * fetches the port number from config in order to see
- * if it's available. */
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &ec))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
- case GNUNET_OK:
- if (GNUNET_OK !=
- /* Set up event loop and reschedule context, plus
- * start/stop the exchange. It calls TALER_TESTING_setup
- * which creates the 'is' object.
- */
- TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE))
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_exchange_api_revocation.c */
diff --git a/src/lib/test_exchange_api_twisted.c b/src/lib/test_exchange_api_twisted.c
@@ -1,332 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2020 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 lib/test_exchange_api_twisted.c
- * @brief testcase to test exchange's HTTP API interface
- * @author Marcello Stanisci
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_signatures.h"
-#include "taler_exchange_service.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-#include <taler/taler_twister_testing_lib.h>
-#include <taler/taler_twister_service.h>
-
-/**
- * Configuration file we use. One (big) configuration is used
- * for the various components for this test.
- */
-#define CONFIG_FILE "test_exchange_api_twisted.conf"
-
-/**
- * (real) Twister URL. Used at startup time to check if it runs.
- */
-static char *twister_url;
-
-/**
- * Exchange configuration data.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Twister process.
- */
-static struct GNUNET_OS_Process *twisterd;
-
-
-/**
- * Execute the taler-exchange-wirewatch command with
- * our configuration file.
- *
- * @param label label to use for the command.
- */
-static struct TALER_TESTING_Command
-CMD_EXEC_WIREWATCH (char *label)
-{
- return TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE);
-}
-
-
-/**
- * Run wire transfer of funds from some user's account to the
- * exchange.
- *
- * @param label label to use for the command.
- * @param amount amount to transfer, i.e. "EUR:1"
- * @param url exchange_url
- */
-static struct TALER_TESTING_Command
-CMD_TRANSFER_TO_EXCHANGE (char *label, char *amount)
-{
- return TALER_TESTING_cmd_admin_add_incoming (label,
- amount,
- &bc.exchange_auth,
- bc.user42_payto);
-}
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- /**
- * This batch aims to trigger the 409 Conflict
- * response from a refresh-reveal operation.
- */
- struct TALER_TESTING_Command refresh_409_conflict[] = {
- CMD_TRANSFER_TO_EXCHANGE
- ("refresh-create-reserve",
- "EUR:5.01"),
- /**
- * Make previous command effective.
- */
- CMD_EXEC_WIREWATCH
- ("wirewatch"),
- /**
- * Withdraw EUR:5.
- */
- TALER_TESTING_cmd_withdraw_amount
- ("refresh-withdraw-coin",
- "refresh-create-reserve",
- "EUR:5",
- MHD_HTTP_OK),
-
- TALER_TESTING_cmd_deposit
- ("refresh-deposit-partial",
- "refresh-withdraw-coin",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\",\
- \"value\":\"EUR:1\"}]}",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- MHD_HTTP_OK),
-
- /**
- * Melt the rest of the coin's value
- * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
- TALER_TESTING_cmd_refresh_melt
- ("refresh-melt",
- "refresh-withdraw-coin",
- MHD_HTTP_OK,
- NULL),
- /* Trigger 409 Conflict. */
- TALER_TESTING_cmd_flip_upload
- ("flip-upload",
- CONFIG_FILE,
- "transfer_privs.0"),
- TALER_TESTING_cmd_refresh_reveal
- ("refresh-(flipped-)reveal",
- "refresh-melt",
- MHD_HTTP_CONFLICT),
-
- TALER_TESTING_cmd_end ()
-
- };
-
-
- /**
- * NOTE: not all CMDs actually need the twister,
- * so it may be better to move those into the "main"
- * lib test suite.
- */struct TALER_TESTING_Command refund[] = {
-
- CMD_TRANSFER_TO_EXCHANGE
- ("create-reserve-r1",
- "EUR:5.01"),
- CMD_EXEC_WIREWATCH
- ("wirewatch-r1"),
- TALER_TESTING_cmd_withdraw_amount
- ("withdraw-coin-r1",
- "create-reserve-r1",
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_deposit
- ("deposit-refund-1",
- "withdraw-coin-r1",
- 0,
- bc.user42_payto,
- "{\"items\":[{\"name\":\"ice cream\","
- "\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_MINUTES,
- "EUR:5",
- MHD_HTTP_OK),
- TALER_TESTING_cmd_refund
- ("refund-currency-missmatch",
- MHD_HTTP_PRECONDITION_FAILED,
- "USD:5",
- "USD:0.01",
- "deposit-refund-1"),
- TALER_TESTING_cmd_refund
- ("refund-fee-above-amount",
- MHD_HTTP_BAD_REQUEST,
- "EUR:5",
- "EUR:10",
- "deposit-refund-1"),
- TALER_TESTING_cmd_flip_upload
- ("flip-upload",
- CONFIG_FILE,
- "merchant_sig"),
- TALER_TESTING_cmd_refund
- ("refund-bad-sig",
- MHD_HTTP_FORBIDDEN,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-1"),
-
- /* This next deposit CMD is only used to provide a
- * good merchant signature to the next (failing) refund
- * operations. */
-
- TALER_TESTING_cmd_deposit
- ("deposit-refund-to-fail",
- "withdraw-coin-r1",
- 0, /* coin index. */
- bc.user42_payto,
- /* This parameter will make any comparison about
- h_contract_terms fail, when /refund will be handled.
- So in other words, this is h_contract missmatch. */
- "{\"items\":[{\"name\":\"ice skate\","
- "\"value\":\"EUR:5\"}]}",
- GNUNET_TIME_UNIT_MINUTES,
- "EUR:5",
- MHD_HTTP_CONFLICT),
- TALER_TESTING_cmd_refund
- ("refund-deposit-not-found",
- MHD_HTTP_NOT_FOUND,
- "EUR:5",
- "EUR:0.01",
- "deposit-refund-to-fail"),
- TALER_TESTING_cmd_refund
- ("refund-insufficient-funds",
- MHD_HTTP_PRECONDITION_FAILED,
- "EUR:50",
- "EUR:0.01",
- "deposit-refund-1"),
- TALER_TESTING_cmd_refund
- ("refund-fee-too-low",
- MHD_HTTP_BAD_REQUEST,
- "EUR:5",
- "EUR:0.000001",
- "deposit-refund-1"),
- TALER_TESTING_cmd_end ()
- };
-
- struct TALER_TESTING_Command commands[] = {
- TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict",
- refresh_409_conflict),
- TALER_TESTING_cmd_batch ("refund",
- refund),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run_with_fakebank (is,
- commands,
- bc.exchange_auth.wire_gateway_url);
-}
-
-
-/**
- * Kill, wait, and destroy convenience function.
- *
- * @param process process to purge.
- */
-static void
-purge_process (struct GNUNET_OS_Process *process)
-{
- GNUNET_OS_process_kill (process, SIGINT);
- GNUNET_OS_process_wait (process);
- GNUNET_OS_process_destroy (process);
-}
-
-
-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-exchange-api-twisted",
- "DEBUG", NULL);
-
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (CONFIG_FILE,
- "account-2",
- &bc))
- return 77;
-
- if (NULL == (twister_url = TALER_TESTING_prepare_twister
- (CONFIG_FILE)))
- return 77;
-
- TALER_TESTING_cleanup_files (CONFIG_FILE);
-
- switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
- &ec))
- {
- case GNUNET_SYSERR:
- GNUNET_break (0);
- return 1;
- case GNUNET_NO:
- return 77;
-
- case GNUNET_OK:
-
- if (NULL == (twisterd = TALER_TESTING_run_twister (CONFIG_FILE)))
- return 77;
-
- ret = TALER_TESTING_setup_with_exchange (&run,
- NULL,
- CONFIG_FILE);
- purge_process (twisterd);
- GNUNET_free (twister_url);
-
- if (GNUNET_OK != ret)
- return 1;
- break;
- default:
- GNUNET_break (0);
- return 1;
- }
- return 0;
-}
-
-
-/* end of test_exchange_api_twisted.c */
diff --git a/src/lib/test_taler_exchange_aggregator.c b/src/lib/test_taler_exchange_aggregator.c
@@ -1,524 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016-2020 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 lib/test_taler_exchange_aggregator.c
- * @brief Tests for taler-exchange-aggregator logic
- * @author Christian Grothoff <christian@grothoff.org>
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_util.h"
-#include <gnunet/gnunet_json_lib.h>
-#include "taler_json_lib.h"
-#include "taler_exchangedb_lib.h"
-#include <microhttpd.h>
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Helper structure to keep exchange configuration values.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Contains plugin and session.
- */
-static struct TALER_TESTING_DatabaseConnection dbc;
-
-/**
- * Return value from main().
- */
-static int result;
-
-/**
- * Name of the configuration file to use.
- */
-static char *config_filename;
-
-#define USER42_ACCOUNT "42"
-
-/**
- * @return GNUNET_NO if database could not be prepared,
- * otherwise GNUNET_OK
- */
-static int
-prepare_database (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- dbc.plugin = TALER_EXCHANGEDB_plugin_load (cfg);
- if (NULL == dbc.plugin)
- {
- GNUNET_break (0);
- result = 77;
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- dbc.plugin->create_tables (dbc.plugin->cls))
- {
- GNUNET_break (0);
- TALER_EXCHANGEDB_plugin_unload (dbc.plugin);
- dbc.plugin = NULL;
- result = 77;
- return GNUNET_NO;
- }
- dbc.session = dbc.plugin->get_session (dbc.plugin->cls);
- GNUNET_assert (NULL != dbc.session);
-
- return GNUNET_OK;
-}
-
-
-/**
- * Collects all the tests.
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command all[] = {
-
- // check no aggregation happens on a empty database
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty-db",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
-
- /* check aggregation happens on the simplest case:
- one deposit into the database. */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-1",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-deposit-1",
- config_filename),
-
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1",
- ec.exchange_url,
- "EUR:0.89",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-1"),
-
- /* check aggregation accumulates well. */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-2a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- "EUR:0.1"),
-
- TALER_TESTING_cmd_insert_deposit ("do-deposit-2b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- "EUR:0.1"),
-
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-2",
- config_filename),
-
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-2",
- ec.exchange_url,
- "EUR:1.79",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-2"),
-
- /* check that different merchants stem different aggregations. */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-3a",
- &dbc,
- "bob",
- "4",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- "EUR:0.1"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-3b",
- &dbc,
- "bob",
- "5",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- "EUR:0.1"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-3c",
- &dbc,
- "alice",
- "4",
- GNUNET_TIME_UNIT_ZERO,
- "EUR:1",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-3",
- config_filename),
-
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3a",
- ec.exchange_url,
- "EUR:0.89",
- bc.exchange_payto,
- "payto://x-taler-bank/localhost/4"),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3b",
- ec.exchange_url,
- "EUR:0.89",
- bc.exchange_payto,
- "payto://x-taler-bank/localhost/4"),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3c",
- ec.exchange_url,
- "EUR:0.89",
- bc.exchange_payto,
- "payto://x-taler-bank/localhost/5"),
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-3"),
-
- /* checking that aggregator waits for the deadline. */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-4a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.2",
- "EUR:0.1"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-4b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.2",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-early",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-4-fast"),
-
- TALER_TESTING_cmd_sleep ("wait (5s)", 5),
-
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-delayed",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-4",
- ec.exchange_url,
- "EUR:0.19",
- bc.exchange_payto,
- bc.user42_payto),
-
- // test picking all deposits at earliest deadline
- TALER_TESTING_cmd_insert_deposit ("do-deposit-5a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 10),
- "EUR:0.2",
- "EUR:0.1"),
-
- TALER_TESTING_cmd_insert_deposit ("do-deposit-5b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.2",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-early",
- config_filename),
-
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-5-early"),
- TALER_TESTING_cmd_sleep ("wait (5s)", 5),
-
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-delayed",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-5",
- ec.exchange_url,
- "EUR:0.19",
- bc.exchange_payto,
- bc.user42_payto),
- /* Test NEVER running 'tiny' unless they make up minimum unit */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-6a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.102",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6a-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-6a-tiny"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-6b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.102",
- "EUR:0.1"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-6c",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.102",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6c-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-6c-tiny"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-6d",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.102",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6d-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-6d-tiny"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-6e",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.112",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6e",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-6",
- ec.exchange_url,
- "EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
-
- /* Test profiteering if wire deadline is short */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-7a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.109",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7a-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-7a-tiny"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-7b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.119",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-profit",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7",
- ec.exchange_url,
- "EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
-
- /* Now check profit was actually taken */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-7c",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.122",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-loss",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7",
- ec.exchange_url,
- "EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
-
- /* Test that aggregation would happen fully if wire deadline is long */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-8a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.109",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8a-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-8a-tiny"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-8b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.109",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8b-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-8b-tiny"),
-
- /* now trigger aggregate with large transaction and short deadline */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-8c",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.122",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-8",
- ec.exchange_url,
- "EUR:0.03",
- bc.exchange_payto,
- bc.user42_payto),
-
- /* Test aggregation with fees and rounding profits. */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-9a",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.104",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9a-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-9a-tiny"),
- TALER_TESTING_cmd_insert_deposit ("do-deposit-9b",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_relative_multiply
- (GNUNET_TIME_UNIT_SECONDS,
- 5),
- "EUR:0.105",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9b-tiny",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty (
- "expect-empty-transactions-after-9b-tiny"),
-
- /* now trigger aggregate with large transaction and short deadline */
- TALER_TESTING_cmd_insert_deposit ("do-deposit-9c",
- &dbc,
- "bob",
- USER42_ACCOUNT,
- GNUNET_TIME_UNIT_ZERO,
- "EUR:0.112",
- "EUR:0.1"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9",
- config_filename),
- /* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-9",
- ec.exchange_url,
- "EUR:0.01",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run_with_fakebank (is,
- all,
- bc.exchange_auth.wire_gateway_url);
-}
-
-
-int
-main (int argc,
- char *const argv[])
-{
- const char *plugin_name;
- char *testname;
-
- if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
- {
- GNUNET_break (0);
- return -1;
- }
- plugin_name++;
- (void) GNUNET_asprintf (&testname,
- "test-taler-exchange-aggregator-%s",
- plugin_name);
- (void) GNUNET_asprintf (&config_filename,
- "%s.conf",
- testname);
-
- GNUNET_log_setup ("test_taler_exchange_aggregator",
- "DEBUG",
- NULL);
-
- /* these might get in the way */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
-
- TALER_TESTING_cleanup_files (config_filename);
-
- if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename,
- &ec))
- {
- TALER_LOG_WARNING ("Could not prepare the exchange.\n");
- return 77;
- }
-
- if (GNUNET_OK != TALER_TESTING_prepare_fakebank (config_filename,
- "account-1",
- &bc))
- {
- TALER_LOG_WARNING ("Could not prepare the fakebank\n");
- return 77;
- }
-
- if (GNUNET_OK != GNUNET_CONFIGURATION_parse_and_run (config_filename,
- &prepare_database,
- NULL))
- {
- TALER_LOG_WARNING ("Could not prepare database for tests.\n");
- return result;
- }
-
- result = TALER_TESTING_setup (&run,
- NULL,
- config_filename,
- NULL, // no exchange process handle.
- GNUNET_NO); // do not try to connect to the exchange
-
- GNUNET_free (config_filename);
- GNUNET_free (testname);
- dbc.plugin->drop_tables (dbc.plugin->cls);
- TALER_EXCHANGEDB_plugin_unload (dbc.plugin);
- return GNUNET_OK == result ? 0 : 1;
-}
-
-
-/* end of test_taler_exchange_aggregator.c */
diff --git a/src/lib/test_taler_exchange_wirewatch.c b/src/lib/test_taler_exchange_wirewatch.c
@@ -1,182 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016, 2017, 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 lib/test_taler_exchange_wirewatch.c
- * @brief Tests for taler-exchange-wirewatch and taler-exchange-aggregator logic;
- * Performs an invalid wire transfer to the exchange, and then checks that
- * wirewatch immediately sends the money back.
- * Then performs a valid wire transfer, waits for the reserve to expire,
- * and then checks that the aggregator sends the money back.
- * @author Christian Grothoff <christian@grothoff.org>
- */
-#include "platform.h"
-#include "taler_util.h"
-#include <gnunet/gnunet_json_lib.h>
-#include <gnunet/gnunet_pq_lib.h>
-#include "taler_json_lib.h"
-#include <microhttpd.h>
-#include "taler_fakebank_lib.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Bank configuration data.
- */
-static struct TALER_TESTING_BankConfiguration bc;
-
-/**
- * Helper structure to keep exchange configuration values.
- */
-static struct TALER_TESTING_ExchangeConfiguration ec;
-
-/**
- * Name of the configuration file to use.
- */
-static char *config_filename;
-
-static struct TALER_TESTING_Command
-transfer_to_exchange (const char *label,
- const char *amount)
-{
- return TALER_TESTING_cmd_admin_add_incoming (label,
- amount,
- &bc.exchange_auth,
- bc.user42_payto);
-}
-
-
-/**
- * Main function that will tell the interpreter what commands to
- * run.
- *
- * @param cls closure
- */
-static void
-run (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command all[] = {
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty",
- config_filename),
- TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty",
- config_filename),
- TALER_TESTING_cmd_check_bank_empty ("expect-transfers-empty-after-dry-run"),
-
- transfer_to_exchange ("run-transfer-good-to-exchange",
- "EUR:5"),
- TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-good-transfer",
- config_filename),
-
- TALER_TESTING_cmd_check_bank_admin_transfer (
- "clear-good-transfer-to-the-exchange",
- "EUR:5",
- bc.user42_payto, // debit
- bc.exchange_payto, // credit
- "run-transfer-good-to-exchange"),
-
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-non-expired-reserve",
- config_filename),
-
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-1"),
- TALER_TESTING_cmd_sleep ("wait (5s)",
- 5),
- TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-expired-reserve",
- config_filename),
- TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1",
- ec.exchange_url,
- "EUR:4.99",
- bc.exchange_payto,
- bc.user42_payto),
- TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-2"),
- TALER_TESTING_cmd_end ()
- };
-
- TALER_TESTING_run_with_fakebank (is,
- all,
- bc.exchange_auth.wire_gateway_url);
-}
-
-
-int
-main (int argc,
- char *const argv[])
-{
- const char *plugin_name;
-
- /* these might get in the way */
- unsetenv ("XDG_DATA_HOME");
- unsetenv ("XDG_CONFIG_HOME");
- GNUNET_log_setup ("test_taler_exchange_wirewatch",
- "DEBUG",
- NULL);
-
- if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
- {
- GNUNET_break (0);
- return -1;
- }
- plugin_name++;
- {
- char *testname;
-
- GNUNET_asprintf (&testname,
- "test-taler-exchange-wirewatch-%s",
- plugin_name);
- GNUNET_asprintf (&config_filename,
- "%s.conf",
- testname);
- GNUNET_free (testname);
- }
- /* check database is working */
- {
- struct GNUNET_PQ_Context *conn;
- struct GNUNET_PQ_ExecuteStatement es[] = {
- GNUNET_PQ_EXECUTE_STATEMENT_END
- };
-
- conn = GNUNET_PQ_connect ("postgres:///talercheck",
- NULL,
- es,
- NULL);
- if (NULL == conn)
- return 77;
- GNUNET_PQ_disconnect (conn);
- }
-
- TALER_TESTING_cleanup_files (config_filename);
- if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename,
- &ec))
- {
- TALER_LOG_INFO ("Could not prepare the exchange\n");
- return 77;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_prepare_fakebank (config_filename,
- "account-1",
- &bc))
- return 77;
-
- return
- (GNUNET_OK == TALER_TESTING_setup_with_exchange (&run,
- NULL,
- config_filename)) ? 0 : 1;
-}
-
-
-/* end of test_taler_exchange_wirewatch.c */
diff --git a/src/lib/testing_api_cmd_auditor_deposit_confirmation.c b/src/lib/testing_api_cmd_auditor_deposit_confirmation.c
@@ -1,444 +0,0 @@
-/*
- 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 lib/testing_api_cmd_auditor_deposit_confirmation.c
- * @brief command for testing /deposit_confirmation.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_auditor_service.h"
-#include "taler_testing_lib.h"
-#include "taler_signatures.h"
-#include "backoff.h"
-
-
-/**
- * State for a "deposit confirmation" CMD.
- */
-struct DepositConfirmationState
-{
-
- /**
- * Reference to any command that is able to provide a deposit.
- */
- const char *deposit_reference;
-
- /**
- * What is the deposited amount without the fee (i.e. the
- * amount we expect in the deposit confirmation)?
- */
- const char *amount_without_fee;
-
- /**
- * Which coin of the @e deposit_reference should we confirm.
- */
- unsigned int coin_index;
-
- /**
- * DepositConfirmation handle while operation is running.
- */
- struct TALER_AUDITOR_DepositConfirmationHandle *dc;
-
- /**
- * Auditor connection.
- */
- struct TALER_AUDITOR_Handle *auditor;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-deposit_confirmation_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #deposit_confirmation_run.
- *
- * @param cls a `struct DepositConfirmationState`
- */
-static void
-do_retry (void *cls)
-{
- struct DepositConfirmationState *dcs = cls;
-
- dcs->retry_task = NULL;
- deposit_confirmation_run (dcs,
- NULL,
- dcs->is);
-}
-
-
-/**
- * Callback to analyze the /deposit-confirmation response, just used
- * to check if the response code is acceptable.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param obj raw response from the auditor.
- */
-static void
-deposit_confirmation_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const json_t *obj)
-{
- struct DepositConfirmationState *dcs = cls;
-
- dcs->dc = NULL;
- if (dcs->expected_response_code != http_status)
- {
- if (GNUNET_YES == dcs->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying deposit confirmation failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- dcs->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- dcs->backoff = EXCHANGE_LIB_BACKOFF (dcs->backoff);
- dcs->retry_task = GNUNET_SCHEDULER_add_delayed (dcs->backoff,
- &do_retry,
- dcs);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- dcs->is->commands[dcs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (obj, stderr, 0);
- TALER_TESTING_interpreter_fail (dcs->is);
- return;
- }
- TALER_TESTING_interpreter_next (dcs->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-deposit_confirmation_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct DepositConfirmationState *dcs = cls;
- const struct TALER_TESTING_Command *deposit_cmd;
- struct GNUNET_HashCode h_wire;
- struct GNUNET_HashCode h_contract_terms;
- struct GNUNET_TIME_Absolute timestamp;
- struct GNUNET_TIME_Absolute refund_deadline;
- struct TALER_Amount amount_without_fee;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- const struct TALER_MerchantPrivateKeyP *merchant_priv;
- struct TALER_MerchantPublicKeyP merchant_pub;
- const struct TALER_ExchangePublicKeyP *exchange_pub;
- const struct TALER_ExchangeSignatureP *exchange_sig;
- const json_t *wire_details;
- const json_t *contract_terms;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- const struct TALER_EXCHANGE_Keys *keys;
- const struct TALER_EXCHANGE_SigningPublicKey *spk;
-
- dcs->is = is;
- GNUNET_assert (NULL != dcs->deposit_reference);
- deposit_cmd
- = TALER_TESTING_interpreter_lookup_command (is,
- dcs->deposit_reference);
- if (NULL == deposit_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_exchange_pub (deposit_cmd,
- dcs->coin_index,
- &exchange_pub));
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_exchange_sig (deposit_cmd,
- dcs->coin_index,
- &exchange_sig));
- keys = TALER_EXCHANGE_get_keys (dcs->is->exchange);
- GNUNET_assert (NULL != keys);
- spk = TALER_EXCHANGE_get_exchange_signing_key_info (keys,
- exchange_pub);
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_contract_terms (deposit_cmd,
- dcs->coin_index,
- &contract_terms));
- /* Very unlikely to fail */
- GNUNET_assert (NULL != contract_terms);
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (contract_terms,
- &h_contract_terms));
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_wire_details (deposit_cmd,
- dcs->coin_index,
- &wire_details));
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (wire_details,
- &h_wire));
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_coin_priv (deposit_cmd,
- dcs->coin_index,
- &coin_priv));
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_merchant_priv (deposit_cmd,
- dcs->coin_index,
- &merchant_priv));
- GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
- &merchant_pub.eddsa_pub);
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (dcs->amount_without_fee,
- &amount_without_fee));
- /* timestamp is mandatory */
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_absolute_time ("timestamp", ×tamp),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (contract_terms,
- spec,
- NULL, NULL))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- /* refund deadline is optional, defaults to zero */
- {
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (contract_terms,
- spec,
- NULL, NULL))
- {
- refund_deadline = timestamp;
- }
- }
- dcs->dc = TALER_AUDITOR_deposit_confirmation
- (dcs->auditor,
- &h_wire,
- &h_contract_terms,
- timestamp,
- refund_deadline,
- &amount_without_fee,
- &coin_pub,
- &merchant_pub,
- exchange_pub,
- exchange_sig,
- &keys->master_pub,
- spk->valid_from,
- spk->valid_until,
- spk->valid_legal,
- &spk->master_sig,
- &deposit_confirmation_cb,
- dcs);
-
- if (NULL == dcs->dc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- return;
-}
-
-
-/**
- * Free the state of a "deposit_confirmation" CMD, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure, a `struct DepositConfirmationState`
- * @param cmd the command which is being cleaned up.
- */
-static void
-deposit_confirmation_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct DepositConfirmationState *dcs = cls;
-
- if (NULL != dcs->dc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- dcs->is->ip,
- cmd->label);
- TALER_AUDITOR_deposit_confirmation_cancel (dcs->dc);
- dcs->dc = NULL;
- }
- if (NULL != dcs->retry_task)
- {
- GNUNET_SCHEDULER_cancel (dcs->retry_task);
- dcs->retry_task = NULL;
- }
- GNUNET_free (dcs);
-}
-
-
-/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- *
- * @return #GNUNET_OK on success
- */
-static int
-deposit_confirmation_traits (void *cls,
- const 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;
-}
-
-
-/**
- * Create a "deposit-confirmation" command.
- *
- * @param label command label.
- * @param auditor auditor connection.
- * @param deposit_reference reference to any operation that can
- * provide a coin.
- * @param coin_index if @a deposit_reference offers an array of
- * coins, this parameter selects which one in that array.
- * This value is currently ignored, as only one-coin
- * deposits are implemented.
- * @param amount_without_fee deposited amount without the fee
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_confirmation (const char *label,
- struct TALER_AUDITOR_Handle *auditor,
- const char *deposit_reference,
- unsigned int coin_index,
- const char *amount_without_fee,
- unsigned int expected_response_code)
-{
- struct DepositConfirmationState *dcs;
-
- dcs = GNUNET_new (struct DepositConfirmationState);
- dcs->auditor = auditor;
- dcs->deposit_reference = deposit_reference;
- dcs->coin_index = coin_index;
- dcs->amount_without_fee = amount_without_fee;
- dcs->expected_response_code = expected_response_code;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = dcs,
- .label = label,
- .run = &deposit_confirmation_run,
- .cleanup = &deposit_confirmation_cleanup,
- .traits = &deposit_confirmation_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a deposit confirmation command to enable retries when we get
- * transient errors from the auditor.
- *
- * @param cmd a deposit confirmation command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_confirmation_with_retry (struct TALER_TESTING_Command
- cmd)
-{
- struct DepositConfirmationState *dcs;
-
- GNUNET_assert (&deposit_confirmation_run == cmd.run);
- dcs = cmd.cls;
- dcs->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/* end of testing_auditor_api_cmd_deposit_confirmation.c */
diff --git a/src/lib/testing_api_cmd_auditor_exchanges.c b/src/lib/testing_api_cmd_auditor_exchanges.c
@@ -1,361 +0,0 @@
-/*
- 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 lib/testing_api_cmd_auditor_exchanges.c
- * @brief command for testing /exchanges of the auditor
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_auditor_service.h"
-#include "taler_testing_lib.h"
-#include "taler_signatures.h"
-#include "backoff.h"
-
-
-/**
- * State for a "deposit confirmation" CMD.
- */
-struct ExchangesState
-{
-
- /**
- * Exchanges handle while operation is running.
- */
- struct TALER_AUDITOR_ListExchangesHandle *leh;
-
- /**
- * Auditor connection.
- */
- struct TALER_AUDITOR_Handle *auditor;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * URL of the exchange expected to be included in the response.
- */
- const char *exchange_url;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-exchanges_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #exchanges_run.
- *
- * @param cls a `struct ExchangesState`
- */
-static void
-do_retry (void *cls)
-{
- struct ExchangesState *es = cls;
-
- es->retry_task = NULL;
- exchanges_run (es,
- NULL,
- es->is);
-}
-
-
-/**
- * Callback to analyze the /exchanges response.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param num_exchanges length of the @a ei array
- * @param ei array with information about the exchanges
- * @param raw_response raw response from the auditor.
- */
-static void
-exchanges_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_exchanges,
- const struct TALER_AUDITOR_ExchangeInfo *ei,
- const json_t *raw_response)
-{
- struct ExchangesState *es = cls;
-
- es->leh = NULL;
- if (es->expected_response_code != http_status)
- {
- if (GNUNET_YES == es->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying list exchanges failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- es->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- es->backoff = EXCHANGE_LIB_BACKOFF (es->backoff);
- es->retry_task = GNUNET_SCHEDULER_add_delayed (es->backoff,
- &do_retry,
- es);
- return;
- }
- }
- GNUNET_log
- (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- es->is->commands[es->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (raw_response, stderr, 0);
- TALER_TESTING_interpreter_fail (es->is);
- return;
- }
- if (NULL != es->exchange_url)
- {
- unsigned int found = GNUNET_NO;
-
- for (unsigned int i = 0;
- i<num_exchanges;
- i++)
- if (0 == strcmp (es->exchange_url,
- ei[i].exchange_url))
- found = GNUNET_YES;
- if (GNUNET_NO == found)
- {
- TALER_LOG_ERROR
- ("Exchange '%s' doesn't exist at this auditor\n",
- es->exchange_url);
- TALER_TESTING_interpreter_fail (es->is);
- return;
- }
-
- TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n",
- es->exchange_url);
- }
- TALER_TESTING_interpreter_next (es->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-exchanges_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct ExchangesState *es = cls;
-
- es->is = is;
- es->leh = TALER_AUDITOR_list_exchanges
- (is->auditor,
- &exchanges_cb,
- es);
-
- if (NULL == es->leh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- return;
-}
-
-
-/**
- * Free the state of a "exchanges" CMD, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure, a `struct ExchangesState`
- * @param cmd the command which is being cleaned up.
- */
-static void
-exchanges_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct ExchangesState *es = cls;
-
- if (NULL != es->leh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- es->is->ip,
- cmd->label);
- TALER_AUDITOR_list_exchanges_cancel (es->leh);
- es->leh = NULL;
- }
- if (NULL != es->retry_task)
- {
- GNUNET_SCHEDULER_cancel (es->retry_task);
- es->retry_task = NULL;
- }
- GNUNET_free (es);
-}
-
-
-/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- * @return #GNUNET_OK on success
- */
-static int
-exchanges_traits (void *cls,
- const 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;
-}
-
-
-/**
- * Create a "list exchanges" command.
- *
- * @param label command label.
- * @param auditor auditor connection.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exchanges (const char *label,
- struct TALER_AUDITOR_Handle *auditor,
- unsigned int expected_response_code)
-{
- struct ExchangesState *es;
-
- es = GNUNET_new (struct ExchangesState);
- es->auditor = auditor;
- es->expected_response_code = expected_response_code;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = es,
- .label = label,
- .run = &exchanges_run,
- .cleanup = &exchanges_cleanup,
- .traits = &exchanges_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Create a "list exchanges" command and check whether
- * a particular exchange belongs to the returned bundle.
- *
- * @param label command label.
- * @param expected_response_code expected HTTP response code.
- * @param exchange_url URL of the exchange supposed to
- * be included in the response.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exchanges_with_url (const char *label,
- unsigned int expected_response_code,
- const char *exchange_url)
-{
- struct ExchangesState *es;
-
- es = GNUNET_new (struct ExchangesState);
- es->expected_response_code = expected_response_code;
- es->exchange_url = exchange_url;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = es,
- .label = label,
- .run = &exchanges_run,
- .cleanup = &exchanges_cleanup,
- .traits = &exchanges_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify an exchanges command to enable retries when we get
- * transient errors from the auditor.
- *
- * @param cmd a deposit confirmation command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exchanges_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct ExchangesState *es;
-
- GNUNET_assert (&exchanges_run == cmd.run);
- es = cmd.cls;
- es->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/* end of testing_auditor_api_cmd_exchanges.c */
diff --git a/src/lib/testing_api_cmd_auditor_exec_auditor.c b/src/lib/testing_api_cmd_auditor_exec_auditor.c
@@ -1,166 +0,0 @@
-/*
- 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 lib/testing_api_cmd_auditor_exec_auditor.c
- * @brief run the taler-auditor command
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "auditor_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "auditor" CMD.
- */
-struct AuditorState
-{
-
- /**
- * Process for the "auditor" command.
- */
- struct GNUNET_OS_Process *auditor_proc;
-
- /**
- * Configuration file used by the command.
- */
- const char *config_filename;
-};
-
-
-/**
- * Run the command; calls the `taler-auditor' program.
- *
- * @param cls closure.
- * @param cmd the commaind being run.
- * @param is interpreter state.
- */
-static void
-auditor_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct AuditorState *ks = cls;
-
- ks->auditor_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor",
- "taler-auditor",
- "-c", ks->config_filename,
- NULL);
- if (NULL == ks->auditor_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "auditor" CMD, and possibly kills its
- * process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-auditor_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct AuditorState *ks = cls;
-
- if (NULL != ks->auditor_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (ks->auditor_proc,
- SIGKILL));
- GNUNET_OS_process_wait (ks->auditor_proc);
- GNUNET_OS_process_destroy (ks->auditor_proc);
- ks->auditor_proc = NULL;
- }
- GNUNET_free (ks);
-}
-
-
-/**
- * Offer "auditor" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-auditor_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct AuditorState *ks = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ks->auditor_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make the "exec-auditor" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_auditor (const char *label,
- const char *config_filename)
-{
- struct AuditorState *ks;
-
- ks = GNUNET_new (struct AuditorState);
- ks->config_filename = config_filename;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ks,
- .label = label,
- .run = &auditor_run,
- .cleanup = &auditor_cleanup,
- .traits = &auditor_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_auditor_api_cmd_exec_auditor.c */
diff --git a/src/lib/testing_api_cmd_auditor_exec_auditor_dbinit.c b/src/lib/testing_api_cmd_auditor_exec_auditor_dbinit.c
@@ -1,167 +0,0 @@
-/*
- 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 lib/testing_api_cmd_auditor_exec_auditor_dbinit.c
- * @brief run the taler-auditor-dbinit "-r" command
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "auditor_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "auditor-dbinit" CMD.
- */
-struct AuditorDbinitState
-{
-
- /**
- * Process for the "auditor-dbinit" command.
- */
- struct GNUNET_OS_Process *auditor_dbinit_proc;
-
- /**
- * Configuration file used by the command.
- */
- const char *config_filename;
-};
-
-
-/**
- * Run the command; calls the `taler-auditor-dbinit' program.
- *
- * @param cls closure.
- * @param cmd the commaind being run.
- * @param is interpreter state.
- */
-static void
-auditor_dbinit_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct AuditorDbinitState *ks = cls;
-
- ks->auditor_dbinit_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-dbinit",
- "taler-auditor-dbinit",
- "-c", ks->config_filename,
- "-r",
- NULL);
- if (NULL == ks->auditor_dbinit_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "auditor-dbinit" CMD, and possibly kills its
- * process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-auditor_dbinit_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct AuditorDbinitState *ks = cls;
-
- if (NULL != ks->auditor_dbinit_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (ks->auditor_dbinit_proc,
- SIGKILL));
- GNUNET_OS_process_wait (ks->auditor_dbinit_proc);
- GNUNET_OS_process_destroy (ks->auditor_dbinit_proc);
- ks->auditor_dbinit_proc = NULL;
- }
- GNUNET_free (ks);
-}
-
-
-/**
- * Offer "auditor-dbinit" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-auditor_dbinit_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct AuditorDbinitState *ks = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ks->auditor_dbinit_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make the "exec-auditor-dbinit" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_auditor_dbinit (const char *label,
- const char *config_filename)
-{
- struct AuditorDbinitState *ks;
-
- ks = GNUNET_new (struct AuditorDbinitState);
- ks->config_filename = config_filename;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ks,
- .label = label,
- .run = &auditor_dbinit_run,
- .cleanup = &auditor_dbinit_cleanup,
- .traits = &auditor_dbinit_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_auditor_api_cmd_exec_auditor_dbinit.c */
diff --git a/src/lib/testing_api_cmd_auditor_exec_wire_auditor.c b/src/lib/testing_api_cmd_auditor_exec_wire_auditor.c
@@ -1,166 +0,0 @@
-/*
- 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 lib/testing_api_cmd_auditor_exec_wire_auditor.c
- * @brief run the taler-wire-auditor command
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "auditor_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "wire-auditor" CMD.
- */
-struct WireAuditorState
-{
-
- /**
- * Process for the "wire-auditor" command.
- */
- struct GNUNET_OS_Process *wire_auditor_proc;
-
- /**
- * Configuration file used by the command.
- */
- const char *config_filename;
-};
-
-
-/**
- * Run the command; calls the `taler-wire-auditor' program.
- *
- * @param cls closure.
- * @param cmd the commaind being run.
- * @param is interpreter state.
- */
-static void
-wire_auditor_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct WireAuditorState *ks = cls;
-
- ks->wire_auditor_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-wire-auditor",
- "taler-wire-auditor",
- "-c", ks->config_filename,
- NULL);
- if (NULL == ks->wire_auditor_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "wire-auditor" CMD, and possibly kills its
- * process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-wire_auditor_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct WireAuditorState *ks = cls;
-
- if (NULL != ks->wire_auditor_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (ks->wire_auditor_proc,
- SIGKILL));
- GNUNET_OS_process_wait (ks->wire_auditor_proc);
- GNUNET_OS_process_destroy (ks->wire_auditor_proc);
- ks->wire_auditor_proc = NULL;
- }
- GNUNET_free (ks);
-}
-
-
-/**
- * Offer "wire-auditor" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-wire_auditor_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct WireAuditorState *ks = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ks->wire_auditor_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make the "exec wire-auditor" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_wire_auditor (const char *label,
- const char *config_filename)
-{
- struct WireAuditorState *ks;
-
- ks = GNUNET_new (struct WireAuditorState);
- ks->config_filename = config_filename;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ks,
- .label = label,
- .run = &wire_auditor_run,
- .cleanup = &wire_auditor_cleanup,
- .traits = &wire_auditor_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_auditor_api_cmd_exec_wire_auditor.c */
diff --git a/src/lib/testing_api_cmd_bank_admin_add_incoming.c b/src/lib/testing_api_cmd_bank_admin_add_incoming.c
@@ -1,596 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_admin_add_incoming.c
- * @brief implementation of a bank /admin/add-incoming command
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "backoff.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "fakebank transfer" CMD.
- */
-struct AdminAddIncomingState
-{
-
- /**
- * Label of any command that can trait-offer a reserve priv.
- */
- const char *reserve_reference;
-
- /**
- * Wire transfer amount.
- */
- struct TALER_Amount amount;
-
- /**
- * Base URL of the credited account.
- */
- const char *exchange_credit_url;
-
- /**
- * Money sender payto URL.
- */
- const char *payto_debit_account;
-
- /**
- * Username to use for authentication.
- */
- struct TALER_BANK_AuthenticationData auth;
-
- /**
- * Set (by the interpreter) to the reserve's private key
- * we used to make a wire transfer subject line with.
- */
- struct TALER_ReservePrivateKeyP reserve_priv;
-
- /**
- * Reserve public key matching @e reserve_priv.
- */
- struct TALER_ReservePublicKeyP reserve_pub;
-
- /**
- * Handle to the pending request at the fakebank.
- */
- struct TALER_BANK_AdminAddIncomingHandle *aih;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Set to the wire transfer's unique ID.
- */
- uint64_t serial_id;
-
- /**
- * Timestamp of the transaction (as returned from the bank).
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Merchant instance. Sometimes used to get the tip reserve
- * private key by reading the appropriate config section.
- */
- const char *instance;
-
- /**
- * Configuration filename. Used to get the tip reserve key
- * filename (used to obtain a public key to write in the
- * transfer subject).
- */
- const char *config_filename;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Was this command modified via
- * #TALER_TESTING_cmd_admin_add_incoming_with_retry to
- * enable retries?
- */
- int do_retry;
-};
-
-
-/**
- * Run the "fakebank transfer" CMD.
- *
- * @param cls closure.
- * @param cmd CMD being run.
- * @param is interpreter state.
- */
-static void
-admin_add_incoming_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #admin_add_incoming_run.
- *
- * @param cls a `struct AdminAddIncomingState`
- */
-static void
-do_retry (void *cls)
-{
- struct AdminAddIncomingState *fts = cls;
-
- fts->retry_task = NULL;
- admin_add_incoming_run (fts,
- NULL,
- fts->is);
-}
-
-
-/**
- * This callback will process the fakebank response to the wire
- * transfer. It just checks whether the HTTP response code is
- * acceptable.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
- * successful status request; 0 if the exchange's reply is
- * bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param serial_id unique ID of the wire transfer
- * @param timestamp time stamp of the transaction made.
- * @param json raw response
- */
-static void
-confirmation_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t serial_id,
- struct GNUNET_TIME_Absolute timestamp,
- const json_t *json)
-{
- struct AdminAddIncomingState *fts = cls;
- struct TALER_TESTING_Interpreter *is = fts->is;
-
- fts->aih = NULL;
- if (MHD_HTTP_OK != http_status)
- {
- if (GNUNET_YES == fts->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log
- (GNUNET_ERROR_TYPE_INFO,
- "Retrying fakebank transfer failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- fts->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
- fts->retry_task = GNUNET_SCHEDULER_add_delayed
- (fts->backoff,
- &do_retry,
- fts);
- return;
- }
- }
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fakebank returned HTTP status %u/%d\n",
- http_status,
- (int) ec);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- fts->serial_id = serial_id;
- fts->timestamp = timestamp;
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the "fakebank transfer" CMD.
- *
- * @param cls closure.
- * @param cmd CMD being run.
- * @param is interpreter state.
- */
-static void
-admin_add_incoming_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct AdminAddIncomingState *fts = cls;
-
- /* Use reserve public key as subject */
- if (NULL != fts->reserve_reference)
- {
- const struct TALER_TESTING_Command *ref;
- const struct TALER_ReservePrivateKeyP *reserve_priv;
-
- ref = TALER_TESTING_interpreter_lookup_command
- (is, fts->reserve_reference);
- if (NULL == ref)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_priv (ref,
- 0,
- &reserve_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv;
- }
- else
- {
- if (NULL != fts->instance)
- {
- char *section;
- char *keys;
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
- struct GNUNET_CONFIGURATION_Handle *cfg;
-
- GNUNET_assert (NULL != fts->config_filename);
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- fts->config_filename))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_asprintf (§ion,
- "instance-%s",
- fts->instance);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename
- (cfg,
- section,
- "TIP_RESERVE_PRIV_FILENAME",
- &keys))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Configuration fails to specify reserve"
- " private key filename in section %s\n",
- section);
- GNUNET_free (section);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys);
- GNUNET_free (keys);
- if (NULL == priv)
- {
- GNUNET_log_config_invalid
- (GNUNET_ERROR_TYPE_ERROR,
- section,
- "TIP_RESERVE_PRIV_FILENAME",
- "Failed to read private key");
- GNUNET_free (section);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- fts->reserve_priv.eddsa_priv = *priv;
- GNUNET_free (section);
- GNUNET_free (priv);
- GNUNET_CONFIGURATION_destroy (cfg);
- }
- else
- {
- /* No referenced reserve, no instance to take priv
- * from, no explicit subject given: create new key! */
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
-
- priv = GNUNET_CRYPTO_eddsa_key_create ();
- fts->reserve_priv.eddsa_priv = *priv;
- GNUNET_free (priv);
- }
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv,
- &fts->reserve_pub.eddsa_pub);
- fts->is = is;
- fts->aih
- = TALER_BANK_admin_add_incoming
- (TALER_TESTING_interpreter_get_context (is),
- &fts->auth,
- &fts->reserve_pub,
- &fts->amount,
- fts->payto_debit_account,
- &confirmation_cb,
- fts);
- if (NULL == fts->aih)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-}
-
-
-/**
- * Free the state of a "/admin/add-incoming" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure
- * @param cmd current CMD being cleaned up.
- */
-static void
-admin_add_incoming_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct AdminAddIncomingState *fts = cls;
-
- if (NULL != fts->aih)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %s did not complete\n",
- cmd->label);
- TALER_BANK_admin_add_incoming_cancel (fts->aih);
- fts->aih = NULL;
- }
- if (NULL != fts->retry_task)
- {
- GNUNET_SCHEDULER_cancel (fts->retry_task);
- fts->retry_task = NULL;
- }
- GNUNET_free (fts);
-}
-
-
-/**
- * Offer internal data from a "/admin/add-incoming" CMD to other
- * commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-admin_add_incoming_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct AdminAddIncomingState *fts = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_bank_row (&fts->serial_id),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
- fts->payto_debit_account),
- /* Used as a marker, content does not matter */
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
- "payto://void/the-exchange"),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
- fts->exchange_credit_url),
- TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
- TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
- TALER_TESTING_make_trait_reserve_priv (0,
- &fts->reserve_priv),
- TALER_TESTING_make_trait_reserve_pub (0,
- &fts->reserve_pub),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Create internal state for "/admin/add-incoming" CMD.
- *
- * @param amount the amount to transfer.
- * @param payto_debit_account which account sends money
- * @param auth authentication data
- * @return the internal state
- */
-static struct AdminAddIncomingState *
-make_fts (const char *amount,
- const struct TALER_BANK_AuthenticationData *auth,
- const char *payto_debit_account)
-{
- struct AdminAddIncomingState *fts;
-
- fts = GNUNET_new (struct AdminAddIncomingState);
- fts->exchange_credit_url = auth->wire_gateway_url;
- fts->payto_debit_account = payto_debit_account;
- fts->auth = *auth;
- if (GNUNET_OK !=
- TALER_string_to_amount (amount,
- &fts->amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s'\n",
- amount);
- GNUNET_assert (0);
- }
- return fts;
-}
-
-
-/**
- * Helper function to create admin/add-incoming command.
- *
- * @param label command label.
- * @param fts internal state to use
- * @return the command.
- */
-static struct TALER_TESTING_Command
-make_command (const char *label,
- struct AdminAddIncomingState *fts)
-{
- struct TALER_TESTING_Command cmd = {
- .cls = fts,
- .label = label,
- .run = &admin_add_incoming_run,
- .cleanup = &admin_add_incoming_cleanup,
- .traits = &admin_add_incoming_traits
- };
-
- return cmd;
-}
-
-
-/**
- * Create admin/add-incoming command.
- *
- * @param label command label.
- * @param amount amount to transfer.
- * @param payto_debit_account which account sends money.
- * @param auth authentication data
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_admin_add_incoming (const char *label,
- const char *amount,
- const struct
- TALER_BANK_AuthenticationData *auth,
- const char *payto_debit_account)
-{
- return make_command (label,
- make_fts (amount,
- auth,
- payto_debit_account));
-}
-
-
-/**
- * Create "/admin/add-incoming" CMD, letting the caller specify
- * a reference to a command that can offer a reserve private key.
- * This private key will then be used to construct the subject line
- * of the wire transfer.
- *
- * @param label command label.
- * @param amount the amount to transfer.
- * @param payto_debit_account which account sends money
- * @param auth authentication data
- * @param ref reference to a command that can offer a reserve
- * private key.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_admin_add_incoming_with_ref
- (const char *label,
- const char *amount,
- const struct TALER_BANK_AuthenticationData *auth,
- const char *payto_debit_account,
- const char *ref)
-{
- struct AdminAddIncomingState *fts;
-
- fts = make_fts (amount,
- auth,
- payto_debit_account);
- fts->reserve_reference = ref;
- return make_command (label,
- fts);
-}
-
-
-/**
- * Create "/admin/add-incoming" CMD, letting the caller specifying
- * the merchant instance. This version is useful when a tip
- * reserve should be topped up, in fact the interpreter will need
- * the "tipping instance" in order to get the instance public key
- * and make a wire transfer subject out of it.
- *
- * @param label command label.
- * @param amount amount to transfer.
- * @param payto_debit_account which account (expressed as a number)
- * gives money
- * @param auth authentication data
- * @param instance the instance that runs the tipping. Under this
- * instance, the configuration file will provide the private
- * key of the tipping reserve. This data will then used to
- * construct the wire transfer subject line.
- * @param config_filename configuration file to use.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_admin_add_incoming_with_instance
- (const char *label,
- const char *amount,
- const struct TALER_BANK_AuthenticationData *auth,
- const char *payto_debit_account,
- const char *instance,
- const char *config_filename)
-{
- struct AdminAddIncomingState *fts;
-
- fts = make_fts (amount,
- auth,
- payto_debit_account);
- fts->instance = instance;
- fts->config_filename = config_filename;
-
- return make_command (label,
- fts);
-}
-
-
-/**
- * Modify a fakebank transfer command to enable retries when the
- * reserve is not yet full or we get other transient errors from the
- * fakebank.
- *
- * @param cmd a fakebank transfer command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_admin_add_incoming_retry (struct TALER_TESTING_Command cmd)
-{
- struct AdminAddIncomingState *fts;
-
- GNUNET_assert (&admin_add_incoming_run == cmd.run);
- fts = cmd.cls;
- fts->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/* end of testing_api_cmd_bank_admin_add_incoming.c */
diff --git a/src/lib/testing_api_cmd_bank_admin_check.c b/src/lib/testing_api_cmd_bank_admin_check.c
@@ -1,225 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_admin_check.c
- * @brief command to check if a particular admin/add-incoming transfer took
- * place.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-
-
-/**
- * State for a "bank check" CMD.
- */
-struct BankAdminCheckState
-{
-
- /**
- * Expected transferred amount.
- */
- const char *amount;
-
- /**
- * Expected debit bank account.
- */
- const char *debit_payto;
-
- /**
- * Expected credit bank account.
- */
- const char *credit_payto;
-
- /**
- * Command providing the reserve public key trait to use.
- */
- const char *reserve_pub_ref;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
-};
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-check_bank_admin_transfer_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct BankAdminCheckState *bcs = cls;
- struct TALER_Amount amount;
- char *debit_account;
- char *credit_account;
- const char *debit_payto;
- const char *credit_payto;
- const struct TALER_ReservePublicKeyP *reserve_pub;
- const struct TALER_TESTING_Command *cmd_ref;
-
- cmd_ref
- = TALER_TESTING_interpreter_lookup_command (is,
- bcs->reserve_pub_ref);
- if (NULL == cmd_ref)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (cmd_ref,
- 0,
- &reserve_pub))
- {
- GNUNET_break (0);
- TALER_LOG_ERROR ("Command reference fails to provide reserve public key\n");
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_LOG_INFO ("Deposit reference NOT given\n");
- debit_payto = bcs->debit_payto;
- credit_payto = bcs->credit_payto;
- 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;
- }
- debit_account = TALER_xtalerbank_account_from_payto (debit_payto);
- credit_account = TALER_xtalerbank_account_from_payto (credit_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "converted debit_payto (%s) to debit_account (%s)\n",
- debit_payto,
- debit_account);
- if (GNUNET_OK !=
- TALER_FAKEBANK_check_credit (is->fakebank,
- &amount,
- debit_account,
- credit_account,
- reserve_pub))
- {
- GNUNET_break (0);
- GNUNET_free (credit_account);
- GNUNET_free (debit_account);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_free (credit_account);
- GNUNET_free (debit_account);
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Free the state of a "bank check" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-check_bank_admin_transfer_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct BankAdminCheckState *bcs = cls;
-
- GNUNET_free (bcs);
-}
-
-
-/**
- * Offer internal data from a "bank admin check" CMD state.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-check_bank_admin_transfer_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_trait_end ()
- };
-
- (void) cls;
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make a "bank check" CMD. It checks whether a particular wire transfer to
- * the exchange (credit) has been made or not.
- *
- * @param label the command label.
- * @param amount the amount expected to be transferred.
- * @param debit_payto the account that gave money.
- * @param credit_payto the account that received money.
- * @param reserve_pub_ref command that provides the reserve public key to expect
- * @return the command
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_bank_admin_transfer
- (const char *label,
- const char *amount,
- const char *debit_payto,
- const char *credit_payto,
- const char *reserve_pub_ref)
-{
- struct BankAdminCheckState *bcs;
-
- bcs = GNUNET_new (struct BankAdminCheckState);
- bcs->amount = amount;
- bcs->debit_payto = debit_payto;
- bcs->credit_payto = credit_payto;
- bcs->reserve_pub_ref = reserve_pub_ref;
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = bcs,
- .run = &check_bank_admin_transfer_run,
- .cleanup = &check_bank_admin_transfer_cleanup,
- .traits = &check_bank_admin_transfer_traits
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_bank_check.c b/src/lib/testing_api_cmd_bank_check.c
@@ -1,306 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_check.c
- * @brief command to check if a particular wire transfer took
- * place.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-
-
-/**
- * State for a "bank check" CMD.
- */
-struct BankCheckState
-{
-
- /**
- * Base URL of the exchange supposed to be
- * involved in the bank transaction.
- */
- const char *exchange_base_url;
-
- /**
- * Expected transferred amount.
- */
- const char *amount;
-
- /**
- * Expected debit bank account.
- */
- const char *debit_payto;
-
- /**
- * Expected credit bank account.
- */
- const char *credit_payto;
-
- /**
- * Binary form of the wire transfer subject.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Reference to a CMD that provides all the data
- * needed to issue the bank check. If NULL, that data
- * must exist here in the state.
- */
- const char *deposit_reference;
-};
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-check_bank_transfer_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct BankCheckState *bcs = cls;
- struct TALER_Amount amount;
- char *debit_account;
- char *credit_account;
- const char *exchange_base_url;
- const char *debit_payto;
- const char *credit_payto;
-
- if (NULL == bcs->deposit_reference)
- {
- TALER_LOG_INFO ("Deposit reference NOT given\n");
- debit_payto = bcs->debit_payto;
- credit_payto = bcs->credit_payto;
- 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;
- }
- }
- else
- {
- const struct TALER_TESTING_Command *deposit_cmd;
- const struct TALER_Amount *amount_ptr;
-
- TALER_LOG_INFO ("`%s' uses reference (%s/%p)\n",
- TALER_TESTING_interpreter_get_current_label
- (is),
- bcs->deposit_reference,
- bcs->deposit_reference);
- deposit_cmd
- = TALER_TESTING_interpreter_lookup_command (is,
- bcs->deposit_reference);
- if (NULL == deposit_cmd)
- TALER_TESTING_FAIL (is);
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (deposit_cmd,
- 0,
- &amount_ptr)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (deposit_cmd,
- TALER_TESTING_PT_DEBIT,
- &debit_payto)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (deposit_cmd,
- TALER_TESTING_PT_CREDIT,
- &credit_payto)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_url (deposit_cmd,
- TALER_TESTING_UT_EXCHANGE_BASE_URL,
- &exchange_base_url)) )
- TALER_TESTING_FAIL (is);
- amount = *amount_ptr;
- }
-
-
- debit_account = TALER_xtalerbank_account_from_payto (debit_payto);
- credit_account = TALER_xtalerbank_account_from_payto (credit_payto);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "converted debit_payto (%s) to debit_account (%s)\n",
- debit_payto,
- debit_account);
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "converted credit_payto (%s) to credit_account (%s)\n",
- credit_payto,
- credit_account);
-
- if (GNUNET_OK !=
- TALER_FAKEBANK_check_debit (is->fakebank,
- &amount,
- debit_account,
- credit_account,
- exchange_base_url,
- &bcs->wtid))
- {
- GNUNET_break (0);
- GNUNET_free (credit_account);
- GNUNET_free (debit_account);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_free (credit_account);
- GNUNET_free (debit_account);
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Free the state of a "bank check" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-check_bank_transfer_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct BankCheckState *bcs = cls;
-
- GNUNET_free (bcs);
-}
-
-
-/**
- * Offer internal data from a "bank check" CMD state.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-check_bank_transfer_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct BankCheckState *bcs = cls;
- struct TALER_WireTransferIdentifierRawP *wtid_ptr = &bcs->wtid;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_wtid (0,
- wtid_ptr),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- bcs->exchange_base_url),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make a "bank check" CMD. It checks whether a
- * particular wire transfer has been made or not.
- *
- * @param label the command label.
- * @param exchange_base_url base url of the exchange involved in
- * the wire transfer.
- * @param amount the amount expected to be transferred.
- * @param debit_payto the account that gave money.
- * @param credit_payto the account that received money.
- *
- * @return the command
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_bank_transfer (const char *label,
- const char *exchange_base_url,
- const char *amount,
- const char *debit_payto,
- const char *credit_payto)
-{
- struct BankCheckState *bcs;
-
- bcs = GNUNET_new (struct BankCheckState);
- bcs->exchange_base_url = exchange_base_url;
- bcs->amount = amount;
- bcs->debit_payto = debit_payto;
- bcs->credit_payto = credit_payto;
- bcs->deposit_reference = NULL;
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = bcs,
- .run = &check_bank_transfer_run,
- .cleanup = &check_bank_transfer_cleanup,
- .traits = &check_bank_transfer_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Define a "bank check" CMD that takes the input
- * data from another CMD that offers it.
- *
- * @param label command label.
- * @param deposit_reference reference to a CMD that is
- * able to provide the "check bank transfer" operation
- * input data.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_bank_transfer_with_ref
- (const char *label,
- const char *deposit_reference)
-{
- struct BankCheckState *bcs;
-
- bcs = GNUNET_new (struct BankCheckState);
- bcs->deposit_reference = deposit_reference;
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = bcs,
- .run = &check_bank_transfer_run,
- .cleanup = &check_bank_transfer_cleanup,
- .traits = &check_bank_transfer_traits
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_bank_check_empty.c b/src/lib/testing_api_cmd_bank_check_empty.c
@@ -1,103 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_check_empty.c
- * @brief command to check if a particular wire transfer took
- * place.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-
-
-/**
- * Cleanup the state, only defined to respect the API.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-check_bank_empty_cleanup
- (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- return;
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-check_bank_empty_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Some commands (notably "bank history") could randomly
- * look for traits; this way makes sure we don't segfault.
- */
-static int
-check_bank_empty_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Checks wheter all the wire transfers got "checked"
- * by the "bank check" CMD.
- *
- * @param label command label.
- *
- * @return the command
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_bank_empty (const char *label)
-{
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = &check_bank_empty_run,
- .cleanup = &check_bank_empty_cleanup,
- .traits = &check_bank_empty_traits
- };
-
- return cmd;
-}
diff --git a/src/lib/testing_api_cmd_bank_history_credit.c b/src/lib/testing_api_cmd_bank_history_credit.c
@@ -1,599 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_history_credit.c
- * @brief command to check the /history/incoming 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"
-
-
-/**
- * Item in the transaction history, as reconstructed from the
- * command history.
- */
-struct History
-{
-
- /**
- * Wire details.
- */
- struct TALER_BANK_CreditDetails details;
-
- /**
- * Serial ID of the wire transfer.
- */
- uint64_t row_id;
-
- /**
- * URL to free.
- */
- char *url;
-};
-
-
-/**
- * State for a "history" CMD.
- */
-struct HistoryState
-{
- /**
- * Base URL of the account offering the "history" operation.
- */
- char *account_url;
-
- /**
- * Reference to command defining the
- * first row number we want in the result.
- */
- const char *start_row_reference;
-
- /**
- * How many rows we want in the result, _at most_,
- * and ascending/descending.
- */
- long long num_results;
-
- /**
- * Handle to a pending "history" operation.
- */
- struct TALER_BANK_CreditHistoryHandle *hh;
-
- /**
- * Authentication data for the operation.
- */
- struct TALER_BANK_AuthenticationData auth;
-
- /**
- * Expected number of results (= rows).
- */
- uint64_t results_obtained;
-
- /**
- * Set to GNUNET_YES if the callback detects something
- * unexpected.
- */
- int failed;
-
- /**
- * Expected history.
- */
- struct History *h;
-
- /**
- * Length of @e h
- */
- unsigned int total;
-
-};
-
-
-/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- *
- * @return #GNUNET_OK on success
- */
-static int
-history_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- /* Must define this function because some callbacks
- * look for certain traits on _all_ the commands. */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Log which history we expected. Called when an error occurs.
- *
- * @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,
- unsigned int h_len,
- unsigned int off)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Transaction history (credit) mismatch at position %u/%u\n",
- off,
- h_len);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history:\n");
- for (unsigned int i = 0; i<h_len; i++)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "H(%u): %s (serial: %llu, subject: %s,"
- " counterpart: %s)\n",
- i,
- TALER_amount2s (&h[i].details.amount),
- (unsigned long long) h[i].row_id,
- TALER_B2S (&h[i].details.reserve_pub),
- h[i].details.debit_account_url);
- }
-}
-
-
-/**
- * This function constructs the list of history elements that
- * interest the account number of the caller. It has two main
- * loops: the first to figure out how many history elements have
- * to be allocated, and the second to actually populate every
- * element.
- *
- * @param is interpreter state (supposedly having the
- * current CMD pointing at a "history" CMD).
- * @param[out] rh history array to initialize.
- * @return number of entries in @a rh.
- */
-static unsigned int
-build_history (struct TALER_TESTING_Interpreter *is,
- struct History **rh)
-{
- struct HistoryState *hs = is->commands[is->ip].cls;
- unsigned int total;
- unsigned int pos;
- struct History *h;
- const struct TALER_TESTING_Command *add_incoming_cmd;
- int inc;
- unsigned int start;
- unsigned int end;
-
- /* @var turns GNUNET_YES whenever either no 'start' value was
- * given for the history query, or the given value is found
- * in the list of all the CMDs. *///
- int ok;
- const uint64_t *row_id_start = NULL;
-
- 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)
- {
- TALER_LOG_DEBUG ("Checking history at FIRST transaction (EMPTY)\n");
- *rh = NULL;
- return 0;
- }
-
- if (hs->num_results > 0)
- {
- inc = 1; /* _inc_rement */
- start = 0;
- end = is->ip - 1;
- }
- else
- {
- inc = -1;
- start = is->ip - 1;
- end = 0;
- }
-
- ok = GNUNET_NO;
- if (NULL == row_id_start)
- ok = GNUNET_YES;
- h = NULL;
- total = 0;
- GNUNET_array_grow (h,
- total,
- 4);
- pos = 0;
- for (unsigned int off = start; off != end + inc; off += inc)
- {
- const struct TALER_TESTING_Command *cmd = &is->commands[off];
- const uint64_t *row_id;
- const char *credit_account;
- const char *debit_account;
- const struct TALER_Amount *amount;
- const struct TALER_ReservePublicKeyP *reserve_pub;
- const char *exchange_credit_url;
-
- /* The following command allows us to skip over those CMDs
- * that do not offer a "row_id" trait. Such skipped CMDs are
- * not interesting for building a history. *///
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_bank_row (cmd,
- &row_id)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_CREDIT,
- &credit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_DEBIT,
- &debit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (cmd,
- 0,
- &amount)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (cmd,
- 0,
- &reserve_pub)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_url (cmd,
- TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
- &exchange_credit_url)) )
- continue; /* not an interesting event */
- /* Seek "/history/incoming" starting row. */
- if ( (NULL != row_id_start) &&
- (*row_id_start == *row_id) &&
- (GNUNET_NO == ok) )
- {
- /* Until here, nothing counted. */
- ok = GNUNET_YES;
- continue;
- }
- /* when 'start' was _not_ given, then ok == GNUNET_YES */
- if (GNUNET_NO == ok)
- continue; /* skip until we find the marker */
- if (0 != strcasecmp (hs->account_url,
- exchange_credit_url))
- continue; /* account missmatch */
- if (total >= GNUNET_MAX (hs->num_results,
- -hs->num_results) )
- {
- TALER_LOG_DEBUG ("Hit history limit\n");
- break;
- }
- TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
- debit_account,
- credit_account,
- hs->account_url);
- /* found matching record, make sure we have room */
- if (pos == total)
- GNUNET_array_grow (h,
- total,
- pos * 2);
- h[pos].url = GNUNET_strdup (debit_account);
- h[pos].details.debit_account_url = h[pos].url;
- h[pos].details.amount = *amount;
- h[pos].row_id = *row_id;
- h[pos].details.reserve_pub = *reserve_pub;
- h[pos].details.credit_account_url = exchange_credit_url;
- pos++;
- }
- GNUNET_assert (GNUNET_YES == ok);
- GNUNET_array_grow (h,
- total,
- pos);
- if (0 == pos)
- TALER_LOG_DEBUG ("Empty credit history computed\n");
- *rh = h;
- return total;
-}
-
-
-/**
- * Check that the "/history/incoming" response matches the
- * CMD whose offset in the list of CMDs is @a off.
- *
- * @param is the interpreter state.
- * @param h expected history (array)
- * @param total length of @a h
- * @param off the offset (of the CMD list) where the command
- * to check is.
- * @param details the expected transaction details.
- * @return #GNUNET_OK if the transaction is what we expect.
- */
-static int
-check_result (struct TALER_TESTING_Interpreter *is,
- struct History *h,
- unsigned int total,
- unsigned int off,
- const struct TALER_BANK_CreditDetails *details)
-{
- if (off >= total)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Test says history has at most %u"
- " results, but got result #%u to check\n",
- total,
- off);
- print_expected (h,
- total,
- off);
- return GNUNET_SYSERR;
- }
- if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub,
- &details->reserve_pub)) ||
- (0 != TALER_amount_cmp (&h[off].details.amount,
- &details->amount)) ||
- (0 != strcasecmp (h[off].details.debit_account_url,
- details->debit_account_url)) )
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "expected debit_account_url: %s\n",
- details->debit_account_url);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "actual debit_account_url: %s\n",
- h[off].details.debit_account_url);
- print_expected (h,
- total,
- off);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * This callback will (1) check that the HTTP response code
- * is acceptable and (2) that the history is consistent. The
- * consistency is checked by going through all the past CMDs,
- * reconstructing then the expected history as of those, and
- * finally check it against what the bank returned.
- *
- * @param cls closure.
- * @param http_status HTTP response code, #MHD_HTTP_OK (200)
- * for successful status request 0 if the bank's reply is
- * bogus (fails to follow the protocol),
- * #MHD_HTTP_NO_CONTENT if there are no more results; on
- * success the last callback is always of this status
- * (even if `abs(num_results)` were already returned).
- * @param ec taler status code.
- * @param row_id monotonically increasing counter corresponding to
- * the transaction.
- * @param details details about the wire transfer.
- * @param json detailed response from the HTTPD, or NULL if
- * reply was not in JSON.
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
- */
-static int
-history_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t row_id,
- const struct TALER_BANK_CreditDetails *details,
- const json_t *json)
-{
- struct TALER_TESTING_Interpreter *is = cls;
- struct HistoryState *hs = is->commands[is->ip].cls;
-
- (void) row_id;
- if (NULL == details)
- {
- hs->hh = NULL;
- if ( (hs->results_obtained != hs->total) ||
- (GNUNET_YES == hs->failed) ||
- (MHD_HTTP_NO_CONTENT != http_status) )
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history of length %u, got %llu;"
- " HTTP status code: %u/%d, failed: %d\n",
- hs->total,
- (unsigned long long) hs->results_obtained,
- http_status,
- (int) ec,
- hs->failed);
- print_expected (hs->h,
- hs->total,
- UINT_MAX);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
- TALER_TESTING_interpreter_next (is);
- return GNUNET_OK;
- }
- if (MHD_HTTP_OK != http_status)
- {
- hs->hh = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unwanted response code from /history/incoming: %u\n",
- http_status);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
-
- /* check current element */
- if (GNUNET_OK != check_result (is,
- hs->h,
- hs->total,
- hs->results_obtained,
- details))
- {
- char *acc;
-
- GNUNET_break (0);
- acc = json_dumps (json,
- JSON_COMPACT);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Result %u was `%s'\n",
- (unsigned int) hs->results_obtained++,
- acc);
- if (NULL != acc)
- free (acc);
- hs->failed = GNUNET_YES;
- return GNUNET_SYSERR;
- }
- hs->results_obtained++;
- return GNUNET_OK;
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-history_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct HistoryState *hs = cls;
- uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
- const uint64_t *row_ptr;
-
- (void) cmd;
- /* 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_ptr))
- TALER_TESTING_FAIL (is);
- else
- row_id = *row_ptr;
- TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
- (unsigned long long) row_id);
- }
- hs->total = build_history (is,
- &hs->h);
- hs->hh = TALER_BANK_credit_history (is->ctx,
- &hs->auth,
- row_id,
- hs->num_results,
- &history_cb,
- is);
- GNUNET_assert (NULL != hs->hh);
-}
-
-
-/**
- * Free the state from a "history" CMD, and possibly cancel
- * a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-history_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct HistoryState *hs = cls;
-
- (void) cmd;
- if (NULL != hs->hh)
- {
- TALER_LOG_WARNING ("/history/incoming did not complete\n");
- TALER_BANK_credit_history_cancel (hs->hh);
- }
- GNUNET_free (hs->account_url);
- for (unsigned int off = 0; off<hs->total; off++)
- GNUNET_free (hs->h[off].url);
- GNUNET_free_non_null (hs->h);
- GNUNET_free (hs);
-}
-
-
-/**
- * Make a "history" CMD.
- *
- * @param label command label.
- * @param auth authentication data to talk with the wire gateway
- * @param start_row_reference reference to a command that can
- * offer a row identifier, to be used as the starting row
- * to accept in the result.
- * @param num_results how many rows we want in the result.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_bank_credits (const char *label,
- const struct
- TALER_BANK_AuthenticationData *auth,
- const char *start_row_reference,
- long long num_results)
-{
- struct HistoryState *hs;
-
- hs = GNUNET_new (struct HistoryState);
- hs->account_url = GNUNET_strdup (auth->wire_gateway_url);
- hs->start_row_reference = start_row_reference;
- hs->num_results = num_results;
- hs->auth = *auth;
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = hs,
- .run = &history_run,
- .cleanup = &history_cleanup,
- .traits = &history_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_credit_history.c */
diff --git a/src/lib/testing_api_cmd_bank_history_debit.c b/src/lib/testing_api_cmd_bank_history_debit.c
@@ -1,602 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_history_debit.c
- * @brief command to check the /history/outgoing 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"
-
-/**
- * Item in the transaction history, as reconstructed from the
- * command history.
- */
-struct History
-{
-
- /**
- * Wire details.
- */
- struct TALER_BANK_DebitDetails details;
-
- /**
- * Serial ID of the wire transfer.
- */
- uint64_t row_id;
-
- /**
- * URL to free.
- */
- char *c_url;
-
- /**
- * URL to free.
- */
- char *d_url;
-};
-
-
-/**
- * State for a "history" CMD.
- */
-struct HistoryState
-{
- /**
- * Base URL of the account offering the "history" operation.
- */
- const char *account_url;
-
- /**
- * Reference to command defining the
- * first row number we want in the result.
- */
- const char *start_row_reference;
-
- /**
- * How many rows we want in the result, _at most_,
- * and ascending/descending.
- */
- long long num_results;
-
- /**
- * Login data to use to authenticate.
- */
- struct TALER_BANK_AuthenticationData auth;
-
- /**
- * Handle to a pending "history" operation.
- */
- struct TALER_BANK_DebitHistoryHandle *hh;
-
- /**
- * Expected number of results (= rows).
- */
- uint64_t results_obtained;
-
- /**
- * Set to #GNUNET_YES if the callback detects something
- * unexpected.
- */
- int failed;
-
- /**
- * Expected history.
- */
- struct History *h;
-
- /**
- * Length of @e h
- */
- unsigned int total;
-
-};
-
-
-/**
- * Offer internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret set to the wanted data.
- * @param trait name of the trait.
- * @param index index number of the traits to be returned.
- *
- * @return #GNUNET_OK on success
- */
-static int
-history_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- /* Must define this function because some callbacks
- * look for certain traits on _all_ the commands. */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Log which history we expected. Called when an error occurs.
- *
- * @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,
- unsigned int h_len,
- unsigned int off)
-{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Transaction history (debit) mismatch at position %u/%u\n",
- off,
- h_len);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history:\n");
- for (unsigned int i = 0; i<h_len; i++)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "H(%u): %s (serial: %llu, subject: %s, counterpart: %s)\n",
- i,
- TALER_amount2s (&h[i].details.amount),
- (unsigned long long) h[i].row_id,
- TALER_B2S (&h[i].details.wtid),
- h[i].details.credit_account_url);
- }
-}
-
-
-/**
- * This function constructs the list of history elements that
- * interest the account number of the caller. It has two main
- * loops: the first to figure out how many history elements have
- * to be allocated, and the second to actually populate every
- * element.
- *
- * @param is interpreter state (supposedly having the
- * current CMD pointing at a "history" CMD).
- * @param[out] rh history array to initialize.
- * @return number of entries in @a rh.
- */
-static unsigned int
-build_history (struct TALER_TESTING_Interpreter *is,
- struct History **rh)
-{
- struct HistoryState *hs = is->commands[is->ip].cls;
- unsigned int total;
- unsigned int pos;
- struct History *h;
- const struct TALER_TESTING_Command *add_incoming_cmd;
- int inc;
- int start;
- int end;
- /* #GNUNET_YES whenever either no 'start' value was given for the history
- * query, or the given value is found in the list of all the CMDs. */
- int ok;
- const uint64_t *row_id_start = NULL;
-
- 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)
- {
- TALER_LOG_DEBUG ("Checking history at first CMD..\n");
- *rh = NULL;
- return 0;
- }
-
- /* AKA 'delta' */
- if (hs->num_results > 0)
- {
- inc = 1; /* _inc_rement: go forwards */
- start = 0;
- end = is->ip;
- }
- else
- {
- inc = -1; /* decrement: we go backwards */
- start = is->ip - 1;
- end = -1; /* range is exclusive, do look at 0! */
- }
-
- ok = GNUNET_NO;
- if (NULL == row_id_start)
- ok = GNUNET_YES;
- h = NULL;
- total = 0;
- GNUNET_array_grow (h,
- total,
- 4);
- pos = 0;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checking commands %u to %u for debit history\n",
- start,
- end);
- for (int off = start; off != end; off += inc)
- {
- const struct TALER_TESTING_Command *cmd = &is->commands[off];
- const uint64_t *row_id;
- const char *debit_account;
- const char *credit_account;
- const struct TALER_Amount *amount;
- const struct TALER_WireTransferIdentifierRawP *wtid;
- const char *exchange_base_url;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Checking if command %s is relevant for debit history\n",
- cmd->label);
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_bank_row (cmd,
- &row_id)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_DEBIT,
- &debit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_payto (cmd,
- TALER_TESTING_PT_CREDIT,
- &credit_account)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (cmd,
- 0,
- &amount)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_wtid (cmd,
- 0,
- &wtid)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_url (cmd,
- TALER_TESTING_UT_EXCHANGE_BASE_URL,
- &exchange_base_url)) )
- continue; /* not an event we care about */
- /* Seek "/history/outgoing" starting row. */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Command %s is relevant for debit history!\n",
- cmd->label);
- if ( (NULL != row_id_start) &&
- (*row_id_start == *row_id) &&
- (GNUNET_NO == ok) )
- {
- /* Until here, nothing counted. */
- ok = GNUNET_YES;
- continue;
- }
- /* when 'start' was _not_ given, then ok == GNUNET_YES */
- if (GNUNET_NO == ok)
- continue; /* skip until we find the marker */
- if (total >= GNUNET_MAX (hs->num_results,
- -hs->num_results) )
- {
- TALER_LOG_DEBUG ("Hit history limit\n");
- break;
- }
- TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
- debit_account,
- credit_account,
- hs->account_url);
- /* found matching record, make sure we have room */
- if (pos == total)
- GNUNET_array_grow (h,
- total,
- pos * 2);
- h[pos].c_url = GNUNET_strdup (credit_account);
- h[pos].d_url = GNUNET_strdup (debit_account);
- h[pos].details.credit_account_url = h[pos].c_url;
- h[pos].details.debit_account_url = h[pos].d_url;
- h[pos].details.amount = *amount;
- h[pos].row_id = *row_id;
- h[pos].details.wtid = *wtid;
- h[pos].details.exchange_base_url = exchange_base_url;
- pos++;
- }
- GNUNET_assert (GNUNET_YES == ok);
- GNUNET_array_grow (h,
- total,
- pos);
- if (0 == pos)
- TALER_LOG_DEBUG ("Empty debit history computed\n");
- *rh = h;
- return total;
-}
-
-
-/**
- * Check that the "/history/outgoing" response matches the
- * CMD whose offset in the list of CMDs is @a off.
- *
- * @param is the interpreter state.
- * @param h expected history
- * @param total number of entries in @a h
- * @param off the offset (of the CMD list) where the command
- * to check is.
- * @param details the expected transaction details.
- * @return #GNUNET_OK if the transaction is what we expect.
- */
-static int
-check_result (struct TALER_TESTING_Interpreter *is,
- struct History *h,
- uint64_t total,
- unsigned int off,
- const struct TALER_BANK_DebitDetails *details)
-{
- 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 ( (0 != GNUNET_memcmp (&h[off].details.wtid,
- &details->wtid)) ||
- (0 != TALER_amount_cmp (&h[off].details.amount,
- &details->amount)) ||
- (0 != strcasecmp (h[off].details.credit_account_url,
- details->credit_account_url)) )
- {
- GNUNET_break (0);
- print_expected (h,
- total,
- off);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * This callback will (1) check that the HTTP response code
- * is acceptable and (2) that the history is consistent. The
- * consistency is checked by going through all the past CMDs,
- * reconstructing then the expected history as of those, and
- * finally check it against what the bank returned.
- *
- * @param cls closure.
- * @param http_status HTTP response code, #MHD_HTTP_OK (200)
- * for successful status request 0 if the bank's reply is
- * bogus (fails to follow the protocol),
- * #MHD_HTTP_NO_CONTENT if there are no more results; on
- * success the last callback is always of this status
- * (even if `abs(num_results)` were already returned).
- * @param ec taler status code.
- * @param row_id monotonically increasing counter corresponding to
- * the transaction.
- * @param details details about the wire transfer.
- * @param json detailed response from the HTTPD, or NULL if
- * reply was not in JSON.
- * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
- */
-static int
-history_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t row_id,
- const struct TALER_BANK_DebitDetails *details,
- const json_t *json)
-{
- struct TALER_TESTING_Interpreter *is = cls;
- struct HistoryState *hs = is->commands[is->ip].cls;
-
- (void) row_id;
- if (NULL == details)
- {
- hs->hh = NULL;
- if ( (hs->results_obtained != hs->total) ||
- (GNUNET_YES == hs->failed) ||
- (MHD_HTTP_NO_CONTENT != http_status) )
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Expected history of length %u, got %llu;"
- " HTTP status code: %u/%d, failed: %d\n",
- hs->total,
- (unsigned long long) hs->results_obtained,
- http_status,
- (int) ec,
- hs->failed);
- print_expected (hs->h,
- hs->total,
- UINT_MAX);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
- TALER_TESTING_interpreter_next (is);
- return GNUNET_OK;
- }
- if (MHD_HTTP_OK != http_status)
- {
- hs->hh = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unwanted response code from /history/outgoing: %u\n",
- http_status);
- TALER_TESTING_interpreter_fail (is);
- return GNUNET_SYSERR;
- }
-
- /* check current element */
- if (GNUNET_OK != check_result (is,
- hs->h,
- hs->total,
- hs->results_obtained,
- details))
- {
- char *acc;
-
- GNUNET_break (0);
- acc = json_dumps (json,
- JSON_COMPACT);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Result %u was `%s'\n",
- (unsigned int) hs->results_obtained++,
- acc);
- if (NULL != acc)
- free (acc);
- hs->failed = GNUNET_YES;
- return GNUNET_SYSERR;
- }
- hs->results_obtained++;
- return GNUNET_OK;
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-history_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct HistoryState *hs = cls;
- uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
- const uint64_t *row_ptr;
-
- (void) cmd;
- /* 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_ptr))
- TALER_TESTING_FAIL (is);
- else
- row_id = *row_ptr;
- TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
- (unsigned long long) row_id);
- }
- hs->total = build_history (is, &hs->h);
- hs->hh = TALER_BANK_debit_history (is->ctx,
- &hs->auth,
- row_id,
- hs->num_results,
- &history_cb,
- is);
- GNUNET_assert (NULL != hs->hh);
-}
-
-
-/**
- * Free the state from a "history" CMD, and possibly cancel
- * a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-history_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct HistoryState *hs = cls;
-
- (void) cmd;
- if (NULL != hs->hh)
- {
- TALER_LOG_WARNING ("/history/outgoing did not complete\n");
- TALER_BANK_debit_history_cancel (hs->hh);
- }
- for (unsigned int off = 0; off<hs->total; off++)
- {
- GNUNET_free (hs->h[off].c_url);
- GNUNET_free (hs->h[off].d_url);
- }
- GNUNET_free_non_null (hs->h);
- GNUNET_free (hs);
-}
-
-
-/**
- * Make a "history" CMD.
- *
- * @param label command label.
- * @param auth login data to use
- * @param start_row_reference reference to a command that can
- * offer a row identifier, to be used as the starting row
- * to accept in the result.
- * @param num_results how many rows we want in the result.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_bank_debits (const char *label,
- const struct TALER_BANK_AuthenticationData *auth,
- const char *start_row_reference,
- long long num_results)
-{
- struct HistoryState *hs;
-
- hs = GNUNET_new (struct HistoryState);
- hs->account_url = auth->wire_gateway_url;
- hs->start_row_reference = start_row_reference;
- hs->num_results = num_results;
- hs->auth = *auth;
-
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = hs,
- .run = &history_run,
- .cleanup = &history_cleanup,
- .traits = &history_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_bank_history_debit.c */
diff --git a/src/lib/testing_api_cmd_bank_transfer.c b/src/lib/testing_api_cmd_bank_transfer.c
@@ -1,405 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_bank_transfer.c
- * @brief implementation of a bank /transfer command
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "backoff.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_bank_service.h"
-#include "taler_fakebank_lib.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "transfer" CMD.
- */
-struct TransferState
-{
-
- /**
- * Wire transfer amount.
- */
- struct TALER_Amount amount;
-
- /**
- * Base URL of the debit account.
- */
- const char *account_debit_url;
-
- /**
- * Money receiver payto URL.
- */
- char *payto_debit_account;
-
- /**
- * Money receiver account URL.
- */
- const char *payto_credit_account;
-
- /**
- * Username to use for authentication.
- */
- struct TALER_BANK_AuthenticationData auth;
-
- /**
- * Base URL of the exchange.
- */
- const char *exchange_base_url;
-
- /**
- * Wire transfer identifier to use.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /**
- * Handle to the pending request at the fakebank.
- */
- struct TALER_BANK_WireExecuteHandle *weh;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Set to the wire transfer's unique ID.
- */
- uint64_t serial_id;
-
- /**
- * Timestamp of the transaction (as returned from the bank).
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Configuration filename. Used to get the tip reserve key
- * filename (used to obtain a public key to write in the
- * transfer subject).
- */
- const char *config_filename;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Was this command modified via
- * #TALER_TESTING_cmd_admin_add_incoming_with_retry to
- * enable retries?
- */
- int do_retry;
-};
-
-
-/**
- * Run the "transfer" CMD.
- *
- * @param cls closure.
- * @param cmd CMD being run.
- * @param is interpreter state.
- */
-static void
-transfer_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #transfer_run.
- *
- * @param cls a `struct TransferState`
- */
-static void
-do_retry (void *cls)
-{
- struct TransferState *fts = cls;
-
- fts->retry_task = NULL;
- transfer_run (fts,
- NULL,
- fts->is);
-}
-
-
-/**
- * This callback will process the fakebank response to the wire
- * transfer. It just checks whether the HTTP response code is
- * acceptable.
- *
- * @param cls closure with the interpreter state
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
- * successful status request; 0 if the exchange's reply is
- * bogus (fails to follow the protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param serial_id unique ID of the wire transfer
- * @param timestamp time stamp of the transaction made.
- */
-static void
-confirmation_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint64_t serial_id,
- struct GNUNET_TIME_Absolute timestamp)
-{
- struct TransferState *fts = cls;
- struct TALER_TESTING_Interpreter *is = fts->is;
-
- fts->weh = NULL;
- if (MHD_HTTP_OK != http_status)
- {
- if (GNUNET_YES == fts->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying transfer failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- fts->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
- fts->retry_task = GNUNET_SCHEDULER_add_delayed
- (fts->backoff,
- &do_retry,
- fts);
- return;
- }
- }
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fakebank returned HTTP status %u/%d\n",
- http_status,
- (int) ec);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- fts->serial_id = serial_id;
- fts->timestamp = timestamp;
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the "transfer" CMD.
- *
- * @param cls closure.
- * @param cmd CMD being run.
- * @param is interpreter state.
- */
-static void
-transfer_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TransferState *fts = cls;
- void *buf;
- size_t buf_size;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Transfer of %s from %s to %s\n",
- TALER_amount2s (&fts->amount),
- fts->account_debit_url,
- fts->payto_credit_account);
- TALER_BANK_prepare_wire_transfer (fts->payto_credit_account,
- &fts->amount,
- fts->exchange_base_url,
- &fts->wtid,
- &buf,
- &buf_size);
- fts->is = is;
- fts->weh
- = TALER_BANK_execute_wire_transfer
- (TALER_TESTING_interpreter_get_context (is),
- &fts->auth,
- buf,
- buf_size,
- &confirmation_cb,
- fts);
- GNUNET_free (buf);
- if (NULL == fts->weh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-}
-
-
-/**
- * Free the state of a "fakebank transfer" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure
- * @param cmd current CMD being cleaned up.
- */
-static void
-transfer_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct TransferState *fts = cls;
-
- if (NULL != fts->weh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %s did not complete\n",
- cmd->label);
- TALER_BANK_execute_wire_transfer_cancel (fts->weh);
- fts->weh = NULL;
- }
- if (NULL != fts->retry_task)
- {
- GNUNET_SCHEDULER_cancel (fts->retry_task);
- fts->retry_task = NULL;
- }
- GNUNET_free (fts->payto_debit_account);
- GNUNET_free (fts);
-}
-
-
-/**
- * Offer internal data from a "fakebank transfer" CMD to other
- * commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-transfer_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct TransferState *fts = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- fts->exchange_base_url),
- TALER_TESTING_make_trait_bank_row (&fts->serial_id),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
- fts->payto_credit_account),
- TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
- fts->payto_debit_account),
- TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
- TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
- TALER_TESTING_make_trait_wtid (0,
- &fts->wtid),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Create transfer command.
- *
- * @param label command label.
- * @param amount amount to transfer.
- * @param auth authentication data to use
- * @param payto_debit_account which account sends money.
- * @param payto_credit_account which account receives money.
- * @param wtid wire transfer identifier to use
- * @param exchange_base_url exchange URL to use
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_transfer (const char *label,
- const char *amount,
- const struct TALER_BANK_AuthenticationData *auth,
- const char *payto_debit_account,
- const char *payto_credit_account,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const char *exchange_base_url)
-{
- struct TransferState *fts;
-
- fts = GNUNET_new (struct TransferState);
- fts->account_debit_url = auth->wire_gateway_url;
- fts->exchange_base_url = exchange_base_url;
- fts->payto_debit_account = GNUNET_strdup (payto_debit_account);
- fts->payto_credit_account = payto_credit_account;
- fts->auth = *auth;
- fts->wtid = *wtid;
- if (GNUNET_OK !=
- TALER_string_to_amount (amount,
- &fts->amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %s\n",
- amount,
- label);
- GNUNET_assert (0);
- }
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = fts,
- .label = label,
- .run = &transfer_run,
- .cleanup = &transfer_cleanup,
- .traits = &transfer_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a transfer command to enable retries when the reserve is not yet
- * full or we get other transient errors from the bank.
- *
- * @param cmd a fakebank transfer command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd)
-{
- struct TransferState *fts;
-
- GNUNET_assert (&transfer_run == cmd.run);
- fts = cmd.cls;
- fts->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/* end of testing_api_cmd_transfer.c */
diff --git a/src/lib/testing_api_cmd_batch.c b/src/lib/testing_api_cmd_batch.c
@@ -1,228 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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 lib/testing_api_cmd_batch.c
- * @brief Implement batch-execution of CMDs.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "batch" CMD.
- */
-struct BatchState
-{
- /**
- * CMDs batch.
- */
- struct TALER_TESTING_Command *batch;
-
- /**
- * Internal command pointer.
- */
- unsigned int batch_ip;
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command being executed.
- * @param is the interpreter state.
- */
-static void
-batch_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct BatchState *bs = cls;
-
- if (NULL != bs->batch[bs->batch_ip].label)
- TALER_LOG_INFO ("Running batched command: %s\n",
- bs->batch[bs->batch_ip].label);
-
- /* hit end command, leap to next top-level command. */
- if (NULL == bs->batch[bs->batch_ip].label)
- {
- TALER_LOG_INFO ("Exiting from batch: %s\n",
- cmd->label);
- TALER_TESTING_interpreter_next (is);
- return;
- }
-
- bs->batch[bs->batch_ip].run (bs->batch[bs->batch_ip].cls,
- &bs->batch[bs->batch_ip],
- is);
-}
-
-
-/**
- * Cleanup the state from a "reserve status" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-batch_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct BatchState *bs = cls;
-
- for (unsigned int i = 0;
- NULL != bs->batch[i].label;
- i++)
- bs->batch[i].cleanup (bs->batch[i].cls,
- &bs->batch[i]);
- GNUNET_free_non_null (bs->batch);
- GNUNET_free (bs);
-}
-
-
-/**
- * Offer internal data from a "batch" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-batch_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
-#define CURRENT_CMD_INDEX 0
-#define BATCH_INDEX 1
-
- struct BatchState *bs = cls;
-
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_cmd
- (CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]),
- TALER_TESTING_make_trait_cmd
- (BATCH_INDEX, bs->batch),
- TALER_TESTING_trait_end ()
- };
-
- /* Always return current command. */
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Create a "batch" command. Such command takes a
- * end_CMD-terminated array of CMDs and executed them.
- * Once it hits the end CMD, it passes the control
- * to the next top-level CMD, regardless of it being
- * another batch or ordinary CMD.
- *
- * @param label the command label.
- * @param batch array of CMDs to execute.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_batch (const char *label,
- struct TALER_TESTING_Command *batch)
-{
- struct BatchState *bs;
- unsigned int i;
-
- bs = GNUNET_new (struct BatchState);
-
- /* Get number of commands. */
- for (i = 0; NULL != batch[i].label; i++)
- /* noop */
- ;
-
- bs->batch = GNUNET_new_array (i + 1,
- struct TALER_TESTING_Command);
- memcpy (bs->batch,
- batch,
- sizeof (struct TALER_TESTING_Command) * i);
- {
- struct TALER_TESTING_Command cmd = {
- .cls = bs,
- .label = label,
- .run = &batch_run,
- .cleanup = &batch_cleanup,
- .traits = &batch_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Advance internal pointer to next command.
- *
- * @param is interpreter state.
- */
-void
-TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is)
-{
- struct BatchState *bs = is->commands[is->ip].cls;
-
- if (NULL == bs->batch[bs->batch_ip].label)
- {
- is->ip++;
- return;
- }
-
- bs->batch_ip++;
-}
-
-
-/**
- * Test if this command is a batch command.
- *
- * @return false if not, true if it is a batch command
- */
-int
-TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd)
-{
- return cmd->run == &batch_run;
-}
-
-
-/**
- * Obtain what command the batch is at.
- *
- * @return cmd current batch command
- */
-struct TALER_TESTING_Command *
-TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
-{
- struct BatchState *bs = cmd->cls;
-
- return &bs->batch[bs->batch_ip];
-}
diff --git a/src/lib/testing_api_cmd_check_keys.c b/src/lib/testing_api_cmd_check_keys.c
@@ -1,359 +0,0 @@
-/*
- 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 lib/testing_api_cmd_check_keys.c
- * @brief Implementation of "check keys" test command. XXX-NOTE:
- * the number of 'expected keys' is NOT the number of the
- * downloaded keys, but rather the number of keys that the
- * libtalerutil library keeps locally. As for the current
- * design, keys are _never_ discarded by the library,
- * therefore their (expected) number is monotonically
- * ascending.
- *
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "check keys" CMD.
- */
-struct CheckKeysState
-{
- /**
- * This number will instruct the CMD interpreter to
- * make sure that /keys was downloaded `generation` times
- * _before_ running the very CMD logic.
- */
- unsigned int generation;
-
- /**
- * How many denomination keys the exchange is
- * supposed to have.
- */
- unsigned int num_denom_keys;
-
- /**
- * If this value is GNUNET_YES, then the "cherry
- * picking" facility is turned off; whole /keys is
- * downloaded.
- */
- unsigned int pull_all_keys;
-
- /**
- * If GNUNET_YES, then the user must specify the
- * last_denom_issue_date manually. This way, it is possible
- * to force whatever X value here (including 0): /keys?last_denom_issue=X.
- */
- unsigned int set_last_denom;
-
- /**
- * Value X to set as the URL parameter:
- * "/keys?last_denom_issue=X" is used only when `set_last_denom'
- * equals GNUNET_YES.
- */
- struct GNUNET_TIME_Absolute last_denom_date;
-
- /**
- * If GNUNET_YES, then we'll provide the "/keys" request.
- * with the "now" argument.
- */
- int with_now;
-
- /**
- * Fake now as passed by the user.
- */
- struct GNUNET_TIME_Absolute now;
-
-};
-
-
-/**
- * Run the "check keys" command.
- *
- * @param cls closure.
- * @param cmd the command currently being executed.
- * @param is the interpreter state.
- */
-static void
-check_keys_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct CheckKeysState *cks = cls;
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "cmd `%s' (ip: %u), key generation: %d\n",
- cmd->label,
- is->ip,
- is->key_generation);
-
- if (is->key_generation < cks->generation)
- {
- is->working = GNUNET_NO;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Triggering GET /keys, cmd `%s'\n",
- cmd->label);
-
- if (GNUNET_YES == cks->set_last_denom)
- {
- TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n");
- TALER_EXCHANGE_set_last_denom (is->exchange,
- cks->last_denom_date);
- }
-
- if (GNUNET_YES == cks->with_now)
- TALER_EXCHANGE_set_now (is->exchange,
- cks->now);
- /* Redownload /keys. */
- GNUNET_break
- (0 == TALER_EXCHANGE_check_keys_current
- (is->exchange,
- GNUNET_YES,
- cks->pull_all_keys).abs_value_us);
- return;
- }
-
-#if 0
- /**
- * Not sure this check makes sense: GET /keys is performed on
- * a "maybe" basis, so it can get quite hard to track /keys
- * request. Rather, this CMD should just check if /keys was
- * requested AT LEAST n times before going ahead with checks.
- *///
- if (is->key_generation > cks->generation)
- {
- /* We got /keys too often, strange. Fatal. May theoretically
- happen if somehow we were really unlucky and /keys expired
- "naturally", but obviously with a sane configuration this
- should also not be. */
- GNUNET_break (0);
- TALER_LOG_ERROR ("Acutal- vs expected key"
- " generation: %u vs %u\n",
- is->key_generation,
- cks->generation);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-#endif
- /* "/keys" was updated, let's check they were OK! */
- if (cks->num_denom_keys != is->keys->num_denom_keys)
- {
- /* Did not get the expected number of denomination keys! */
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Got %u keys in step %s, expected %u\n",
- is->keys->num_denom_keys,
- cmd->label,
- cks->num_denom_keys);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- /* Let's unset the fake now before moving on. */
- TALER_EXCHANGE_unset_now (is->exchange);
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-check_keys_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct CheckKeysState *cks = cls;
-
- GNUNET_free (cks);
-}
-
-
-/**
- * Make a "check keys" command. This type of command
- * checks whether the number of denomination keys from
- * @a exchange matches @a num_denom_keys. Additionally,
- * it lets the user set a last denom issue date to be
- * used in the request for /keys.
- *
- * @param label command label
- * @param generation when this command is run, exactly @a
- * generation /keys downloads took place. If the number
- * of downloads is less than @a generation, the logic will
- * first make sure that @a generation downloads are done,
- * and _then_ execute the rest of the command.
- * @param num_denom_keys expected number of denomination keys.
- * @param last_denom_date date to be set in the "last_denom_issue"
- * URL parameter of /keys.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_with_last_denom (const char *label,
- unsigned int generation,
- unsigned int num_denom_keys,
- struct GNUNET_TIME_Absolute
- last_denom_date)
-{
- struct CheckKeysState *cks;
-
- cks = GNUNET_new (struct CheckKeysState);
- cks->generation = generation;
- cks->num_denom_keys = num_denom_keys;
- cks->set_last_denom = GNUNET_YES;
- cks->last_denom_date = last_denom_date;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cks,
- .label = label,
- .run = &check_keys_run,
- .cleanup = &check_keys_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a "check keys" command. This type of command
- * checks whether the number of denomination keys from
- * @a exchange matches @a num_denom_keys.
- *
- * @param label command label
- * @param generation when this command is run, exactly @a
- * generation /keys downloads took place. If the number
- * of downloads is less than @a generation, the logic will
- * first make sure that @a generation downloads are done,
- * and _then_ execute the rest of the command.
- * @param num_denom_keys expected number of denomination keys.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys (const char *label,
- unsigned int generation,
- unsigned int num_denom_keys)
-{
- struct CheckKeysState *cks;
-
- cks = GNUNET_new (struct CheckKeysState);
- cks->generation = generation;
- cks->num_denom_keys = num_denom_keys;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cks,
- .label = label,
- .run = &check_keys_run,
- .cleanup = &check_keys_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a "check keys" command. This type of command
- * checks whether the number of denomination keys from
- * @a exchange matches @a num_denom_keys.
- *
- * @param label command label
- * @param generation when this command is run, exactly @a
- * generation /keys downloads took place. If the number
- * of downloads is less than @a generation, the logic will
- * first make sure that @a generation downloads are done,
- * and _then_ execute the rest of the command.
- * @param num_denom_keys expected number of denomination keys.
- * @param now timestamp to use when fetching keys
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_with_now (const char *label,
- unsigned int generation,
- unsigned int num_denom_keys,
- struct GNUNET_TIME_Absolute now)
-{
- struct CheckKeysState *cks;
-
- cks = GNUNET_new (struct CheckKeysState);
- cks->generation = generation;
- cks->num_denom_keys = num_denom_keys;
- cks->now = now;
- cks->with_now = GNUNET_YES;
-
- /* Force to NOT cherry pick, otherwise they conflict. */
- cks->pull_all_keys = GNUNET_YES;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cks,
- .label = label,
- .run = &check_keys_run,
- .cleanup = &check_keys_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a "check keys" command that forcedly does NOT cherry pick;
- * just redownload the whole /keys. Then checks whether the number
- * of denomination keys from @a exchange matches @a num_denom_keys.
- *
- * @param label command label
- * @param generation when this command is run, exactly @a
- * generation /keys downloads took place. If the number
- * of downloads is less than @a generation, the logic will
- * first make sure that @a generation downloads are done,
- * and _then_ execute the rest of the command.
- * @param num_denom_keys expected number of denomination keys.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label,
- unsigned int generation,
- unsigned int num_denom_keys)
-{
- struct CheckKeysState *cks;
-
- cks = GNUNET_new (struct CheckKeysState);
- cks->generation = generation;
- cks->num_denom_keys = num_denom_keys;
- cks->pull_all_keys = GNUNET_YES;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cks,
- .label = label,
- .run = &check_keys_run,
- .cleanup = &check_keys_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_check_keys.c */
diff --git a/src/lib/testing_api_cmd_deposit.c b/src/lib/testing_api_cmd_deposit.c
@@ -1,568 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_deposit.c
- * @brief command for testing /deposit.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-#include "taler_signatures.h"
-#include "backoff.h"
-
-
-/**
- * State for a "deposit" CMD.
- */
-struct DepositState
-{
-
- /**
- * Amount to deposit.
- */
- struct TALER_Amount amount;
-
- /**
- * Reference to any command that is able to provide a coin.
- */
- const char *coin_reference;
-
- /**
- * If @e coin_reference refers to an operation that generated
- * an array of coins, this value determines which coin to pick.
- */
- unsigned int coin_index;
-
- /**
- * Wire details of who is depositing -- this would be merchant
- * wire details in a normal scenario.
- */
- json_t *wire_details;
-
- /**
- * JSON string describing what a proposal is about.
- */
- json_t *contract_terms;
-
- /**
- * Refund deadline. Zero for no refunds.
- */
- struct GNUNET_TIME_Absolute refund_deadline;
-
- /**
- * Set (by the interpreter) to a fresh private key. This
- * key will be used to sign the deposit request.
- */
- struct TALER_MerchantPrivateKeyP merchant_priv;
-
- /**
- * Deposit handle while operation is running.
- */
- struct TALER_EXCHANGE_DepositHandle *dh;
-
- /**
- * Timestamp of the /deposit operation.
- */
- struct GNUNET_TIME_Absolute timestamp;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
- /**
- * Set to #GNUNET_YES if the /deposit succeeded
- * and we now can provide the resulting traits.
- */
- int traits_ready;
-
- /**
- * Signing key used by the exchange to sign the
- * deposit confirmation.
- */
- struct TALER_ExchangePublicKeyP exchange_pub;
-
- /**
- * Signature from the exchange on the
- * deposit confirmation.
- */
- struct TALER_ExchangeSignatureP exchange_sig;
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-deposit_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #deposit_run.
- *
- * @param cls a `struct DepositState`
- */
-static void
-do_retry (void *cls)
-{
- struct DepositState *ds = cls;
-
- ds->retry_task = NULL;
- deposit_run (ds,
- NULL,
- ds->is);
-}
-
-
-/**
- * Callback to analyze the /deposit response, just used to
- * check if the response code is acceptable.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param exchange_sig signature provided by the exchange
- * (NULL on errors)
- * @param exchange_pub public key of the exchange,
- * used for signing the response.
- * @param obj raw response from the exchange.
- */
-static void
-deposit_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangeSignatureP *exchange_sig,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *obj)
-{
- struct DepositState *ds = cls;
-
- ds->dh = NULL;
- if (ds->expected_response_code != http_status)
- {
- if (GNUNET_YES == ds->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying deposit failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- ds->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- ds->backoff = EXCHANGE_LIB_BACKOFF (ds->backoff);
- ds->retry_task
- = GNUNET_SCHEDULER_add_delayed (ds->backoff,
- &do_retry,
- ds);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- ds->is->commands[ds->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (obj, stderr, 0);
- TALER_TESTING_interpreter_fail (ds->is);
- return;
- }
- if (MHD_HTTP_OK == http_status)
- {
- ds->traits_ready = GNUNET_YES;
- ds->exchange_pub = *exchange_pub;
- ds->exchange_sig = *exchange_sig;
- }
- TALER_TESTING_interpreter_next (ds->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-deposit_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct DepositState *ds = cls;
- const struct TALER_TESTING_Command *coin_cmd;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
- const struct TALER_DenominationSignature *denom_pub_sig;
- struct TALER_CoinSpendSignatureP coin_sig;
- struct GNUNET_TIME_Absolute wire_deadline;
- struct GNUNET_CRYPTO_EddsaPrivateKey *merchant_priv;
- struct TALER_MerchantPublicKeyP merchant_pub;
- struct GNUNET_HashCode h_contract_terms;
-
- ds->is = is;
- GNUNET_assert (ds->coin_reference);
- coin_cmd = TALER_TESTING_interpreter_lookup_command
- (is,
- ds->coin_reference);
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if ( (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (coin_cmd,
- ds->coin_index,
- &coin_priv)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_denom_pub (coin_cmd,
- ds->coin_index,
- &denom_pub)) ||
- (GNUNET_OK !=
- TALER_TESTING_get_trait_denom_sig (coin_cmd,
- ds->coin_index,
- &denom_pub_sig)) ||
- (GNUNET_OK !=
- TALER_JSON_hash (ds->contract_terms,
- &h_contract_terms)) )
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
-
- merchant_priv = GNUNET_CRYPTO_eddsa_key_create ();
- ds->merchant_priv.eddsa_priv = *merchant_priv;
- GNUNET_free (merchant_priv);
-
- if (0 != ds->refund_deadline.abs_value_us)
- {
- struct GNUNET_TIME_Relative refund_deadline;
-
- refund_deadline = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline);
- wire_deadline = GNUNET_TIME_relative_to_absolute
- (GNUNET_TIME_relative_multiply (refund_deadline, 2));
- }
- else
- {
- ds->refund_deadline = ds->timestamp;
- wire_deadline = GNUNET_TIME_relative_to_absolute
- (GNUNET_TIME_UNIT_ZERO);
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
- &merchant_pub.eddsa_pub);
-
- (void) GNUNET_TIME_round_abs (&wire_deadline);
-
- {
- struct TALER_DepositRequestPS dr;
-
- memset (&dr, 0, sizeof (dr));
- dr.purpose.size = htonl
- (sizeof (struct TALER_DepositRequestPS));
- dr.purpose.purpose = htonl
- (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
- dr.h_contract_terms = h_contract_terms;
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
- &dr.h_wire));
- dr.timestamp = GNUNET_TIME_absolute_hton (ds->timestamp);
- dr.refund_deadline = GNUNET_TIME_absolute_hton
- (ds->refund_deadline);
- TALER_amount_hton (&dr.amount_with_fee,
- &ds->amount);
- TALER_amount_hton (&dr.deposit_fee,
- &denom_pub->fee_deposit);
- dr.merchant = merchant_pub;
- dr.coin_pub = coin_pub;
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
- &dr.purpose,
- &coin_sig.eddsa_signature));
- }
- ds->dh = TALER_EXCHANGE_deposit (is->exchange,
- &ds->amount,
- wire_deadline,
- ds->wire_details,
- &h_contract_terms,
- &coin_pub,
- denom_pub_sig,
- &denom_pub->key,
- ds->timestamp,
- &merchant_pub,
- ds->refund_deadline,
- &coin_sig,
- &deposit_cb,
- ds);
-
- if (NULL == ds->dh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-}
-
-
-/**
- * Free the state of a "deposit" CMD, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure, must be a `struct DepositState`.
- * @param cmd the command which is being cleaned up.
- */
-static void
-deposit_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct DepositState *ds = cls;
-
- if (NULL != ds->dh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ds->is->ip,
- cmd->label);
- TALER_EXCHANGE_deposit_cancel (ds->dh);
- ds->dh = NULL;
- }
- if (NULL != ds->retry_task)
- {
- GNUNET_SCHEDULER_cancel (ds->retry_task);
- ds->retry_task = NULL;
- }
- json_decref (ds->wire_details);
- json_decref (ds->contract_terms);
- GNUNET_free (ds);
-}
-
-
-/**
- * Offer internal data from a "deposit" CMD, to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-deposit_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct DepositState *ds = cls;
- const struct TALER_TESTING_Command *coin_cmd;
- /* Will point to coin cmd internals. */
- const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
-
- coin_cmd
- = TALER_TESTING_interpreter_lookup_command (ds->is,
- ds->coin_reference);
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ds->is);
- return GNUNET_NO;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (coin_cmd,
- ds->coin_index,
- &coin_spent_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ds->is);
- return GNUNET_NO;
- }
- {
- struct TALER_TESTING_Trait traits[] = {
- /* First two traits are only available if
- ds->traits is #GNUNET_YES */
- TALER_TESTING_make_trait_exchange_pub (0,
- &ds->exchange_pub),
- TALER_TESTING_make_trait_exchange_sig (0,
- &ds->exchange_sig),
- /* These traits are always available */
- TALER_TESTING_make_trait_coin_priv (0,
- coin_spent_priv),
- TALER_TESTING_make_trait_wire_details (0,
- ds->wire_details),
- TALER_TESTING_make_trait_contract_terms (0,
- ds->contract_terms),
- TALER_TESTING_make_trait_merchant_priv (0,
- &ds->merchant_priv),
- TALER_TESTING_make_trait_amount_obj (0,
- &ds->amount),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait ((ds->traits_ready)
- ? traits
- : &traits[2],
- ret,
- trait,
- index);
- }
-}
-
-
-/**
- * Create a "deposit" command.
- *
- * @param label command label.
- * @param coin_reference reference to any operation that can
- * provide a coin.
- * @param coin_index if @a withdraw_reference offers an array of
- * coins, this parameter selects which one in that array.
- * This value is currently ignored, as only one-coin
- * withdrawals are implemented.
- * @param target_account_payto target account for the "deposit"
- * request.
- * @param contract_terms contract terms to be signed over by the
- * coin.
- * @param refund_deadline refund deadline, zero means 'no refunds'.
- * Note, if time were absolute, then it would have come
- * one day and disrupt tests meaning.
- * @param amount how much is going to be deposited.
- * @param expected_response_code expected HTTP response code.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit (const char *label,
- const char *coin_reference,
- unsigned int coin_index,
- const char *target_account_payto,
- const char *contract_terms,
- struct GNUNET_TIME_Relative refund_deadline,
- const char *amount,
- unsigned int expected_response_code)
-{
- struct DepositState *ds;
- json_t *wire_details;
-
- wire_details = TALER_TESTING_make_wire_details (target_account_payto);
- ds = GNUNET_new (struct DepositState);
- ds->coin_reference = coin_reference;
- ds->coin_index = coin_index;
- ds->wire_details = wire_details;
- ds->contract_terms = json_loads (contract_terms,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == ds->contract_terms)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse contract terms `%s' for CMD `%s'\n",
- contract_terms,
- label);
- GNUNET_assert (0);
- }
- ds->timestamp = GNUNET_TIME_absolute_get ();
- (void) GNUNET_TIME_round_abs (&ds->timestamp);
-
- json_object_set_new (ds->contract_terms,
- "timestamp",
- GNUNET_JSON_from_time_abs (ds->timestamp));
- if (0 != refund_deadline.rel_value_us)
- {
- ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
- (void) GNUNET_TIME_round_abs (&ds->refund_deadline);
- json_object_set_new (ds->contract_terms,
- "refund_deadline",
- GNUNET_JSON_from_time_abs (ds->refund_deadline));
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (amount,
- &ds->amount));
- ds->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ds,
- .label = label,
- .run = &deposit_run,
- .cleanup = &deposit_cleanup,
- .traits = &deposit_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a deposit command to enable retries when we get transient
- * errors from the exchange.
- *
- * @param cmd a deposit command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct DepositState *ds;
-
- GNUNET_assert (&deposit_run == cmd.run);
- ds = cmd.cls;
- ds->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/* end of testing_api_cmd_deposit.c */
diff --git a/src/lib/testing_api_cmd_exec_aggregator.c b/src/lib/testing_api_cmd_exec_aggregator.c
@@ -1,167 +0,0 @@
-/*
- 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 lib/testing_api_cmd_exec_aggregator.c
- * @brief run the taler-exchange-aggregator command
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "aggregator" CMD.
- */
-struct AggregatorState
-{
-
- /**
- * Aggregator process.
- */
- struct GNUNET_OS_Process *aggregator_proc;
-
- /**
- * Configuration file used by the aggregator.
- */
- const char *config_filename;
-};
-
-
-/**
- * Run the command. Use the `taler-exchange-aggregator' program.
- *
- * @param cls closure.
- * @param cmd command being run.
- * @param is interpreter state.
- */
-static void
-aggregator_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct AggregatorState *as = cls;
-
- as->aggregator_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-aggregator",
- "taler-exchange-aggregator",
- "-c", as->config_filename,
- "-t", /* exit when done */
- NULL);
- if (NULL == as->aggregator_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "aggregator" CMD, and possibly kill its
- * process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-aggregator_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct AggregatorState *as = cls;
-
- if (NULL != as->aggregator_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (as->aggregator_proc,
- SIGKILL));
- GNUNET_OS_process_wait (as->aggregator_proc);
- GNUNET_OS_process_destroy (as->aggregator_proc);
- as->aggregator_proc = NULL;
- }
- GNUNET_free (as);
-}
-
-
-/**
- * Offer "aggregator" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success
- */
-static int
-aggregator_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct AggregatorState *as = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &as->aggregator_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make a "aggregator" CMD.
- *
- * @param label command label.
- * @param config_filename configuration file for the
- * aggregator to use.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_aggregator (const char *label,
- const char *config_filename)
-{
- struct AggregatorState *as;
-
- as = GNUNET_new (struct AggregatorState);
- as->config_filename = config_filename;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = as,
- .label = label,
- .run = &aggregator_run,
- .cleanup = &aggregator_cleanup,
- .traits = &aggregator_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_exec_aggregator.c */
diff --git a/src/lib/testing_api_cmd_exec_auditor-sign.c b/src/lib/testing_api_cmd_exec_auditor-sign.c
@@ -1,233 +0,0 @@
-/*
- 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 lib/testing_api_cmd_exec_auditor-sign.c
- * @brief run the taler-exchange-aggregator command
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "auditor sign" CMD.
- */
-struct AuditorSignState
-{
-
- /**
- * Handle to the process making the signature.
- */
- struct GNUNET_OS_Process *auditor_sign_proc;
-
- /**
- * Configuration file used by the command.
- */
- const char *config_filename;
-
- /**
- * File name of signed blob.
- */
- char *signed_keys_out;
-};
-
-
-/**
- * Run the command; calls the `taler-auditor-sign' program.
- *
- * @param cls closure.
- * @param cmd the command.
- * @param is interpreter state.
- */
-static void
-auditor_sign_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct AuditorSignState *ass = cls;
-
- struct GNUNET_CONFIGURATION_Handle *cfg;
- char *test_home_dir;
- char *exchange_master_pub;
- struct GNUNET_TIME_Absolute now;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK != GNUNET_CONFIGURATION_load
- (cfg, ass->config_filename))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "paths",
- "TALER_TEST_HOME",
- &test_home_dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "paths",
- "TALER_TEST_HOME");
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- now = GNUNET_TIME_absolute_get ();
- GNUNET_asprintf
- (&ass->signed_keys_out,
- "%s/.local/share/taler/auditors/auditor-%llu.out",
- test_home_dir,
- (unsigned long long) now.abs_value_us);
- GNUNET_free (test_home_dir);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "MASTER_PUBLIC_KEY",
- &exchange_master_pub))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "MASTER_PUBLIC_KEY");
- GNUNET_CONFIGURATION_destroy (cfg);
-
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_CONFIGURATION_destroy (cfg);
-
- ass->auditor_sign_proc = GNUNET_OS_start_process
- (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-sign",
- "taler-auditor-sign",
- "-c", ass->config_filename,
- "-u", "http://auditor/",
- "-m", exchange_master_pub,
- "-r", "auditor.in",
- "-o", ass->signed_keys_out,
- NULL);
- GNUNET_free (exchange_master_pub);
- if (NULL == ass->auditor_sign_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "auditor sign" CMD, and possibly
- * kill its process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-auditor_sign_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct AuditorSignState *ass = cls;
-
- if (NULL != ass->auditor_sign_proc)
- {
- GNUNET_break (0 == GNUNET_OS_process_kill
- (ass->auditor_sign_proc, SIGKILL));
- GNUNET_OS_process_wait (ass->auditor_sign_proc);
- GNUNET_OS_process_destroy (ass->auditor_sign_proc);
- ass->auditor_sign_proc = NULL;
- }
- GNUNET_free_non_null (ass->signed_keys_out);
- GNUNET_free (ass);
-}
-
-
-/**
- * Offer "auditor sign" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-auditor_sign_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct AuditorSignState *ass = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ass->auditor_sign_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make a "auditor sign" CMD.
- *
- * @param label command label
- * @param config_filename configuration filename
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_auditor_sign (const char *label,
- const char *config_filename)
-{
- struct AuditorSignState *ass;
-
- ass = GNUNET_new (struct AuditorSignState);
- ass->config_filename = config_filename;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ass,
- .label = label,
- .run = &auditor_sign_run,
- .cleanup = &auditor_sign_cleanup,
- .traits = &auditor_sign_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_exec_auditor-sign.c */
diff --git a/src/lib/testing_api_cmd_exec_keyup.c b/src/lib/testing_api_cmd_exec_keyup.c
@@ -1,236 +0,0 @@
-/*
- 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 lib/testing_api_cmd_exec_keyup.c
- * @brief run the taler-exchange-keyup command
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "keyup" CMD.
- */
-struct KeyupState
-{
-
- /**
- * Process for the "keyup" command.
- */
- struct GNUNET_OS_Process *keyup_proc;
-
- /**
- * Configuration file used by the command.
- */
- const char *config_filename;
-
- /**
- * If GNUNET_YES, then the fake @e now value will be
- * passed to taler-exchange-keyup via the --time
- * option.
- */
- unsigned int with_now;
-
- /**
- * User-provided fake now.
- */
- struct GNUNET_TIME_Absolute now;
-};
-
-
-/**
- * Run the command; calls the `taler-exchange-keyup' program.
- *
- * @param cls closure.
- * @param cmd the commaind being run.
- * @param is interpreter state.
- */
-static void
-keyup_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct KeyupState *ks = cls;
-
- if (GNUNET_YES == ks->with_now)
- {
- ks->keyup_proc = GNUNET_OS_start_process
- (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", ks->config_filename,
- "-o", "auditor.in",
- "--time",
- GNUNET_STRINGS_absolute_time_to_string (ks->now),
- NULL);
- }
- else
- ks->keyup_proc = GNUNET_OS_start_process
- (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", ks->config_filename,
- "-o", "auditor.in",
- NULL);
-
- if (NULL == ks->keyup_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- /* This function does not tell whether the command
- * succeeded or not! */
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "keyup" CMD, and possibly kills its
- * process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-keyup_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct KeyupState *ks = cls;
-
- if (NULL != ks->keyup_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (ks->keyup_proc,
- SIGKILL));
- GNUNET_OS_process_wait (ks->keyup_proc);
- GNUNET_OS_process_destroy (ks->keyup_proc);
- ks->keyup_proc = NULL;
- }
- GNUNET_free (ks);
-}
-
-
-/**
- * Offer "keyup" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- *
- * @return #GNUNET_OK on success.
- */
-static int
-keyup_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct KeyupState *ks = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0, &ks->keyup_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make the "keyup" CMD, with "--timestamp" option.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @param now Unix timestamp representing the fake "now".
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_keyup_with_now
- (const char *label,
- const char *config_filename,
- struct GNUNET_TIME_Absolute now)
-{
- struct KeyupState *ks;
-
- ks = GNUNET_new (struct KeyupState);
- ks->config_filename = config_filename;
- ks->now = now;
- ks->with_now = GNUNET_YES;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ks,
- .label = label,
- .run = &keyup_run,
- .cleanup = &keyup_cleanup,
- .traits = &keyup_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make the "keyup" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_keyup (const char *label,
- const char *config_filename)
-{
- struct KeyupState *ks;
-
- ks = GNUNET_new (struct KeyupState);
- ks->config_filename = config_filename;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ks,
- .label = label,
- .run = &keyup_run,
- .cleanup = &keyup_cleanup,
- .traits = &keyup_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_exec_keyup.c */
diff --git a/src/lib/testing_api_cmd_exec_wirewatch.c b/src/lib/testing_api_cmd_exec_wirewatch.c
@@ -1,168 +0,0 @@
-/*
- 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 lib/testing_api_cmd_exec_wirewatch.c
- * @brief run the taler-exchange-wirewatch command
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "wirewatch" CMD.
- */
-struct WirewatchState
-{
-
- /**
- * Process for the wirewatcher.
- */
- struct GNUNET_OS_Process *wirewatch_proc;
-
- /**
- * Configuration file used by the wirewatcher.
- */
- const char *config_filename;
-};
-
-/**
- * Run the command; use the `taler-exchange-wirewatch' program.
- *
- * @param cls closure.
- * @param cmd command currently being executed.
- * @param is interpreter state.
- */
-static void
-wirewatch_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct WirewatchState *ws = cls;
-
- ws->wirewatch_proc
- = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-wirewatch",
- "taler-exchange-wirewatch",
- "-c", ws->config_filename,
- "-T", /* exit when done */
- NULL);
- if (NULL == ws->wirewatch_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Free the state of a "wirewatch" CMD, and possibly
- * kills its process if it did not terminate regularly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-wirewatch_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct WirewatchState *ws = cls;
-
- if (NULL != ws->wirewatch_proc)
- {
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (ws->wirewatch_proc,
- SIGKILL));
- GNUNET_OS_process_wait (ws->wirewatch_proc);
- GNUNET_OS_process_destroy (ws->wirewatch_proc);
- ws->wirewatch_proc = NULL;
- }
- GNUNET_free (ws);
-}
-
-
-/**
- * Offer "wirewatch" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-wirewatch_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct WirewatchState *ws = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_process (0,
- &ws->wirewatch_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Make a "wirewatch" CMD.
- *
- * @param label command label.
- * @param config_filename configuration filename.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_exec_wirewatch (const char *label,
- const char *config_filename)
-{
- struct WirewatchState *ws;
-
- ws = GNUNET_new (struct WirewatchState);
- ws->config_filename = config_filename;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ws,
- .label = label,
- .run = &wirewatch_run,
- .cleanup = &wirewatch_cleanup,
- .traits = &wirewatch_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_exec_wirewatch.c */
diff --git a/src/lib/testing_api_cmd_insert_deposit.c b/src/lib/testing_api_cmd_insert_deposit.c
@@ -1,319 +0,0 @@
-/*
- 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 lib/testing_api_cmd_insert_deposit.c
- * @brief deposit a coin directly into the database.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "auditor_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-#include "taler_exchangedb_plugin.h"
-
-
-/**
- * State for a "insert-deposit" CMD.
- */
-struct InsertDepositState
-{
- /**
- * Configuration file used by the command.
- */
- const struct TALER_TESTING_DatabaseConnection *dbc;
-
- /**
- * Human-readable name of the shop.
- */
- const char *merchant_name;
-
- /**
- * Merchant account name (NOT a payto-URI).
- */
- const char *merchant_account;
-
- /**
- * Deadline before which the aggregator should
- * send the payment to the merchant.
- */
- struct GNUNET_TIME_Relative wire_deadline;
-
- /**
- * Amount to deposit, inclusive of deposit fee.
- */
- const char *amount_with_fee;
-
- /**
- * Deposit fee.
- */
- const char *deposit_fee;
-};
-
-/**
- * Setup (fake) information about a coin used in deposit.
- *
- * @param[out] issue information to initialize with "valid" data
- */
-static void
-fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
-{
- memset (issue, 0, sizeof (struct
- TALER_EXCHANGEDB_DenominationKeyInformationP));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:1",
- &issue->properties.value));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_withdraw));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_deposit));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_refresh));
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount_nbo ("EUR:0.1",
- &issue->properties.fee_refund));
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the commaind being run.
- * @param is interpreter state.
- */
-static void
-insert_deposit_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct InsertDepositState *ids = cls;
- struct TALER_EXCHANGEDB_Deposit deposit;
- struct TALER_MerchantPrivateKeyP merchant_priv;
- struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
- struct TALER_DenominationPublicKey dpk;
- struct GNUNET_CRYPTO_RsaPrivateKey *denom_priv;
- struct GNUNET_HashCode hc;
-
- // prepare and store issue first.
- fake_issue (&issue);
- denom_priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
- dpk.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv);
- GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key,
- &issue.properties.denom_hash);
-
- if ( (GNUNET_OK !=
- ids->dbc->plugin->start (ids->dbc->plugin->cls,
- ids->dbc->session,
- "talertestinglib: denomination insertion")) ||
- (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- ids->dbc->plugin->insert_denomination_info (ids->dbc->plugin->cls,
- ids->dbc->session,
- &dpk,
- &issue)) ||
- (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- ids->dbc->plugin->commit (ids->dbc->plugin->cls,
- ids->dbc->session)) )
- {
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- /* prepare and store deposit now. */
- memset (&deposit,
- 0,
- sizeof (deposit));
-
- GNUNET_CRYPTO_kdf (&merchant_priv,
- sizeof (struct TALER_MerchantPrivateKeyP),
- "merchant-priv",
- strlen ("merchant-priv"),
- ids->merchant_name,
- strlen (ids->merchant_name),
- NULL,
- 0);
- GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
- &deposit.merchant_pub.eddsa_pub);
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &deposit.h_contract_terms);
- if ( (GNUNET_OK !=
- TALER_string_to_amount (ids->amount_with_fee,
- &deposit.amount_with_fee)) ||
- (GNUNET_OK !=
- TALER_string_to_amount (ids->deposit_fee,
- &deposit.deposit_fee)) )
- {
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key,
- &deposit.coin.denom_pub_hash);
-
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
- &hc);
- deposit.coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (denom_priv,
- &hc);
- {
- char *str;
-
- GNUNET_asprintf (&str,
- "payto://x-taler-bank/localhost/%s",
- ids->merchant_account);
- deposit.receiver_wire_account
- = json_pack ("{s:s, s:s}",
- "salt", "this-is-a-salt-value",
- "url", str);
- GNUNET_free (str);
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (
- deposit.receiver_wire_account,
- &deposit.h_wire));
- deposit.timestamp = GNUNET_TIME_absolute_get ();
- GNUNET_TIME_round_abs (&deposit.timestamp);
- deposit.wire_deadline = GNUNET_TIME_relative_to_absolute (
- ids->wire_deadline);
- GNUNET_TIME_round_abs (&deposit.wire_deadline);
-
- /* finally, actually perform the DB operation */
- if ( (GNUNET_OK !=
- ids->dbc->plugin->start (ids->dbc->plugin->cls,
- ids->dbc->session,
- "libtalertesting: insert deposit")) ||
- (0 >
- ids->dbc->plugin->ensure_coin_known (ids->dbc->plugin->cls,
- ids->dbc->session,
- &deposit.coin)) ||
- (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls,
- ids->dbc->session,
- &deposit)) ||
- (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
- ids->dbc->plugin->commit (ids->dbc->plugin->cls,
- ids->dbc->session)) )
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- }
-
- GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature);
- GNUNET_CRYPTO_rsa_public_key_free (dpk.rsa_public_key);
- GNUNET_CRYPTO_rsa_private_key_free (denom_priv);
- json_decref (deposit.receiver_wire_account);
-
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Free the state of a "auditor-dbinit" CMD, and possibly kills its
- * process if it did not terminate correctly.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-insert_deposit_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct InsertDepositState *ids = cls;
-
- GNUNET_free (ids);
-}
-
-
-/**
- * Offer "insert-deposit" CMD internal data to other commands.
- *
- * @param cls closure.
- * @param[out] ret result
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-insert_deposit_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- return GNUNET_NO;
-}
-
-
-/**
- * Make the "insert-deposit" CMD.
- *
- * @param label command label.
- * @param dbc collects database plugin and session handles.
- * @param merchant_name Human-readable name of the merchant.
- * @param merchant_account merchant's account name (NOT a payto:// URI)
- * @param wire_deadline point in time where the aggregator should have
- * wired money to the merchant.
- * @param amount_with_fee amount to deposit (inclusive of deposit fee)
- * @param deposit_fee deposit fee
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_insert_deposit (const char *label,
- const struct
- TALER_TESTING_DatabaseConnection *dbc,
- const char *merchant_name,
- const char *merchant_account,
- struct GNUNET_TIME_Relative wire_deadline,
- const char *amount_with_fee,
- const char *deposit_fee)
-{
- struct InsertDepositState *ids;
-
- ids = GNUNET_new (struct InsertDepositState);
- ids->dbc = dbc;
- ids->merchant_name = merchant_name;
- ids->merchant_account = merchant_account;
- ids->wire_deadline = wire_deadline;
- ids->amount_with_fee = amount_with_fee;
- ids->deposit_fee = deposit_fee;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ids,
- .label = label,
- .run = &insert_deposit_run,
- .cleanup = &insert_deposit_cleanup,
- .traits = &insert_deposit_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_insert_deposit.c */
diff --git a/src/lib/testing_api_cmd_recoup.c b/src/lib/testing_api_cmd_recoup.c
@@ -1,620 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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 lib/testing_api_cmd_recoup.c
- * @brief Implement the /revoke and /recoup test commands.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "revoke" CMD.
- */
-struct RevokeState
-{
- /**
- * Expected HTTP status code.
- */
- unsigned int expected_response_code;
-
- /**
- * Command that offers a denomination to revoke.
- */
- const char *coin_reference;
-
- /**
- * The interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * The revoke process handle.
- */
- struct GNUNET_OS_Process *revoke_proc;
-
- /**
- * Configuration file name.
- */
- const char *config_filename;
-
- /**
- * Encoding of the denomination (to revoke) public key hash.
- */
- char *dhks;
-
-};
-
-
-/**
- * State for a "pay back" CMD.
- */
-struct RecoupState
-{
- /**
- * Expected HTTP status code.
- */
- unsigned int expected_response_code;
-
- /**
- * Command that offers a reserve private key,
- * plus a coin to be paid back.
- */
- const char *coin_reference;
-
- /**
- * The interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Amount expected to be paid back.
- */
- const char *amount;
-
- /**
- * Handle to the ongoing operation.
- */
- struct TALER_EXCHANGE_RecoupHandle *ph;
-
- /**
- * NULL if coin was not refreshed, otherwise reference
- * to the melt operation underlying @a coin_reference.
- */
- const char *melt_reference;
-
-};
-
-
-/**
- * Parser reference to a coin.
- *
- * @param coin_reference of format $LABEL['#' $INDEX]?
- * @param[out] cref where we return a copy of $LABEL
- * @param[out] idx where we set $INDEX
- * @return #GNUNET_SYSERR if $INDEX is present but not numeric
- */
-static int
-parse_coin_reference (const char *coin_reference,
- char **cref,
- unsigned int *idx)
-{
- const char *index;
-
- /* We allow command references of the form "$LABEL#$INDEX" or
- just "$LABEL", which implies the index is 0. Figure out
- which one it is. */
- index = strchr (coin_reference, '#');
- if (NULL == index)
- {
- *idx = 0;
- *cref = GNUNET_strdup (coin_reference);
- return GNUNET_OK;
- }
- *cref = GNUNET_strndup (coin_reference,
- index - coin_reference);
- if (1 != sscanf (index + 1,
- "%u",
- idx))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n",
- index,
- __FILE__,
- __LINE__);
- GNUNET_free (*cref);
- *cref = NULL;
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Check the result of the recoup request: checks whether
- * the HTTP response code is good, and that the coin that
- * was paid back belonged to the right reserve.
- *
- * @param cls closure
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param amount amount the exchange will wire back for this coin.
- * @param timestamp what time did the exchange receive the
- * /recoup request
- * @param reserve_pub public key of the reserve receiving the recoup, NULL if refreshed or on error
- * @param old_coin_pub public key of the dirty coin, NULL if not refreshed or on error
- * @param full_response raw response from the exchange.
- */
-static void
-recoup_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_Amount *amount,
- struct GNUNET_TIME_Absolute timestamp,
- const struct TALER_ReservePublicKeyP *reserve_pub,
- const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
- const json_t *full_response)
-{
- struct RecoupState *ps = cls;
- struct TALER_TESTING_Interpreter *is = ps->is;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
- const struct TALER_TESTING_Command *reserve_cmd;
- char *cref;
- unsigned int idx;
-
- ps->ph = NULL;
- if (ps->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- fprintf (stderr, "\n");
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- parse_coin_reference (ps->coin_reference,
- &cref,
- &idx))
- {
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- reserve_cmd = TALER_TESTING_interpreter_lookup_command
- (is, cref);
- GNUNET_free (cref);
-
- if (NULL == reserve_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- switch (http_status)
- {
- case MHD_HTTP_OK:
- /* first, check amount */
- {
- struct TALER_Amount expected_amount;
-
- if (GNUNET_OK !=
- TALER_string_to_amount (ps->amount, &expected_amount))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (amount, &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount missmatch to command %s\n",
- cmd->label);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- /* now, check old_coin_pub or reserve_pub, respectively */
- if (NULL != ps->melt_reference)
- {
- const struct TALER_TESTING_Command *melt_cmd;
- const struct TALER_CoinSpendPrivateKeyP *dirty_priv;
- struct TALER_CoinSpendPublicKeyP oc;
-
- melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
- ps->melt_reference);
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (melt_cmd,
- 0,
- &dirty_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv,
- &oc.eddsa_pub);
- if (0 != GNUNET_memcmp (&oc,
- old_coin_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- else
- {
- const struct TALER_ReservePrivateKeyP *reserve_priv;
- struct TALER_ReservePublicKeyP rp;
-
- if (NULL == reserve_pub)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv
- (reserve_cmd, idx, &reserve_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
- &rp.eddsa_pub);
- if (0 != GNUNET_memcmp (reserve_pub, &rp))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unmanaged HTTP status code %u.\n",
- http_status);
- break;
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-recoup_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RecoupState *ps = cls;
- const struct TALER_TESTING_Command *coin_cmd;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- const struct TALER_DenominationBlindingKeyP *blinding_key;
- const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
- const struct TALER_DenominationSignature *coin_sig;
- struct TALER_PlanchetSecretsP planchet;
- char *cref;
- unsigned int idx;
-
- ps->is = is;
- if (GNUNET_OK !=
- parse_coin_reference (ps->coin_reference,
- &cref,
- &idx))
- {
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- coin_cmd = TALER_TESTING_interpreter_lookup_command
- (is, cref);
- GNUNET_free (cref);
-
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_cmd, idx, &coin_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK != TALER_TESTING_get_trait_blinding_key
- (coin_cmd, idx, &blinding_key))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- planchet.coin_priv = *coin_priv;
- planchet.blinding_key = *blinding_key;
-
- if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
- (coin_cmd, idx, &denom_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig
- (coin_cmd, idx, &coin_sig))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Trying to get '%s..' paid back\n",
- TALER_B2S (&denom_pub->h_key));
-
- ps->ph = TALER_EXCHANGE_recoup (is->exchange,
- denom_pub,
- coin_sig,
- &planchet,
- NULL != ps->melt_reference,
- recoup_cb,
- ps);
- GNUNET_assert (NULL != ps->ph);
-}
-
-
-/**
- * Cleanup the state.
- *
- * @param cls closure, must be a `struct RevokeState`.
- * @param cmd the command which is being cleaned up.
- */
-static void
-revoke_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RevokeState *rs = cls;
-
- if (NULL != rs->revoke_proc)
- {
- GNUNET_break (0 == GNUNET_OS_process_kill
- (rs->revoke_proc, SIGKILL));
- GNUNET_OS_process_wait (rs->revoke_proc);
- GNUNET_OS_process_destroy (rs->revoke_proc);
- rs->revoke_proc = NULL;
- }
- GNUNET_free_non_null (rs->dhks);
- GNUNET_free (rs);
-}
-
-
-/**
- * Cleanup the "recoup" CMD state, and possibly cancel
- * a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-recoup_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RecoupState *ps = cls;
- if (NULL != ps->ph)
- {
- TALER_EXCHANGE_recoup_cancel (ps->ph);
- ps->ph = NULL;
- }
- GNUNET_free (ps);
-}
-
-
-/**
- * Offer internal data from a "revoke" CMD to other CMDs.
- *
- * @param cls closure
- * @param[out] ret result (could be anything)
- * @param trait name of the trait
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success
- */
-static int
-revoke_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct RevokeState *rs = cls;
- struct TALER_TESTING_Trait traits[] = {
- /* Needed by the handler which waits the proc'
- * death and calls the next command */
- TALER_TESTING_make_trait_process (0, &rs->revoke_proc),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Run the "revoke" command. The core of the function
- * is to call the "keyup" utility passing it the base32
- * encoding of the denomination to revoke.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-revoke_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RevokeState *rs = cls;
- const struct TALER_TESTING_Command *coin_cmd;
- const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
-
- rs->is = is;
- /* Get denom pub from trait */
- coin_cmd = TALER_TESTING_interpreter_lookup_command
- (is, rs->coin_reference);
-
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_denom_pub
- (coin_cmd, 0, &denom_pub));
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Trying to revoke denom '%s..'\n",
- TALER_B2S (&denom_pub->h_key));
-
- rs->dhks = GNUNET_STRINGS_data_to_string_alloc
- (&denom_pub->h_key, sizeof (struct GNUNET_HashCode));
-
- rs->revoke_proc = GNUNET_OS_start_process
- (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", rs->config_filename,
- "-r", rs->dhks,
- NULL);
-
- if (NULL == rs->revoke_proc)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Revoke is ongoing..\n");
-
- is->reload_keys = GNUNET_OK;
- TALER_TESTING_wait_for_sigchld (is);
-}
-
-
-/**
- * Make a "recoup" command.
- *
- * @param label the command label
- * @param expected_response_code expected HTTP status code
- * @param coin_reference reference to any command which
- * offers a coin & reserve private key.
- * @param amount denomination to pay back.
- * @param melt_reference NULL if coin was not refreshed
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_recoup (const char *label,
- unsigned int expected_response_code,
- const char *coin_reference,
- const char *amount,
- const char *melt_reference)
-{
- struct RecoupState *ps;
-
- ps = GNUNET_new (struct RecoupState);
- ps->expected_response_code = expected_response_code;
- ps->coin_reference = coin_reference;
- ps->amount = amount;
- ps->melt_reference = melt_reference;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ps,
- .label = label,
- .run = &recoup_run,
- .cleanup = &recoup_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a "revoke" command.
- *
- * @param label the command label.
- * @param expected_response_code expected HTTP status code.
- * @param coin_reference reference to a CMD that will offer the
- * denomination to revoke.
- * @param config_filename configuration file name.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_revoke (const char *label,
- unsigned int expected_response_code,
- const char *coin_reference,
- const char *config_filename)
-{
-
- struct RevokeState *rs;
-
- rs = GNUNET_new (struct RevokeState);
- rs->expected_response_code = expected_response_code;
- rs->coin_reference = coin_reference;
- rs->config_filename = config_filename;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rs,
- .label = label,
- .run = &revoke_run,
- .cleanup = &revoke_cleanup,
- .traits = &revoke_traits
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_refresh.c b/src/lib/testing_api_cmd_refresh.c
@@ -1,1411 +0,0 @@
-/*
- 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 lib/testing_api_cmd_refresh.c
- * @brief commands for testing all "refresh" features.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-#include "taler_signatures.h"
-#include "backoff.h"
-
-
-/**
- * Information about a fresh coin generated by the refresh
- * operation.
- */
-struct TALER_TESTING_FreshCoinData
-{
-
- /**
- * If @e amount is NULL, this specifies the denomination key to
- * use. Otherwise, this will be set (by the interpreter) to the
- * denomination PK matching @e amount.
- */
- const struct TALER_EXCHANGE_DenomPublicKey *pk;
-
- /**
- * Set (by the interpreter) to the exchange's signature over the
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Set (by the interpreter) to the coin's private key.
- */
- struct TALER_CoinSpendPrivateKeyP coin_priv;
-
- /**
- * The blinding key (needed for recoup operations).
- */
- struct TALER_DenominationBlindingKeyP blinding_key;
-
-};
-
-
-/**
- * State for a "refresh melt" command.
- */
-struct RefreshMeltState
-{
-
- /**
- * Reference to reserve_withdraw operations for coin to
- * be used for the /refresh/melt operation.
- */
- const char *coin_reference;
-
- /**
- * "Crypto data" used in the refresh operation.
- */
- char *refresh_data;
-
- /**
- * Reference to a previous melt command.
- */
- const char *melt_reference;
-
- /**
- * Melt handle while operation is running.
- */
- struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Array of the denomination public keys
- * corresponding to the @e num_fresh_coins;
- */
- struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
-
- /**
- * Private key of the dirty coin being melted.
- */
- const struct TALER_CoinSpendPrivateKeyP *melt_priv;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Number of bytes in @e refresh_data.
- */
- size_t refresh_data_length;
-
- /**
- * Amounts to be generated during melt.
- */
- const char **melt_fresh_amounts;
-
- /**
- * Number of fresh coins generated by the melt.
- */
- unsigned int num_fresh_coins;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * if set to #GNUNET_YES, then two /refresh/melt operations
- * will be performed. This is needed to trigger the logic
- * that manages those already-made requests. Note: it
- * is not possible to just copy-and-paste a test refresh melt
- * CMD to have the same effect, because every data preparation
- * generates new planchets that (in turn) make the whole "hash"
- * different from any previous one, therefore NOT allowing the
- * exchange to pick any previous /rerfesh/melt operation from
- * the database.
- */
- unsigned int double_melt;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
- /**
- * Set by the melt callback as it comes from the exchange.
- */
- uint16_t noreveal_index;
-};
-
-
-/**
- * State for a "refresh reveal" CMD.
- */
-struct RefreshRevealState
-{
- /**
- * Link to a "refresh melt" command.
- */
- const char *melt_reference;
-
- /**
- * Reveal handle while operation is running.
- */
- struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
-
- /**
- * Convenience struct to keep in one place all the
- * data related to one fresh coin, set by the reveal callback
- * as it comes from the exchange.
- */
- struct TALER_TESTING_FreshCoinData *fresh_coins;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Number of fresh coins withdrawn, set by the
- * reveal callback as it comes from the exchange,
- * it is the length of the @e fresh_coins array.
- */
- unsigned int num_fresh_coins;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
-};
-
-
-/**
- * State for a "refresh link" CMD.
- */
-struct RefreshLinkState
-{
- /**
- * Link to a "refresh reveal" command.
- */
- const char *reveal_reference;
-
- /**
- * Handle to the ongoing operation.
- */
- struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Should we retry on (transient) failures?
- */
- int do_retry;
-
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_reveal_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #refresh_reveal_run.
- *
- * @param cls a `struct RefreshRevealState`
- */
-static void
-do_reveal_retry (void *cls)
-{
- struct RefreshRevealState *rrs = cls;
-
- rrs->retry_task = NULL;
- refresh_reveal_run (rrs,
- NULL,
- rrs->is);
-}
-
-
-/**
- * "refresh reveal" request callback; it checks that the response
- * code is expected and copies into its command's state the data
- * coming from the exchange, namely the fresh coins.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param num_coins number of fresh coins created, length of the
- * @a sigs and @a coin_privs arrays, 0 if the operation
- * failed.
- * @param coin_privs array of @a num_coins private keys for the
- * coins that were created, NULL on error.
- * @param sigs array of signature over @a num_coins coins,
- * NULL on error.
- * @param full_response raw exchange response.
- */
-static void
-reveal_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_coins,
- const struct TALER_PlanchetSecretsP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const json_t *full_response)
-{
- struct RefreshRevealState *rrs = cls;
- const struct TALER_TESTING_Command *melt_cmd;
-
- rrs->rrh = NULL;
- if (rrs->expected_response_code != http_status)
- {
- if (GNUNET_YES == rrs->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying refresh reveal failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- rrs->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff);
- rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff,
- &do_reveal_retry,
- rrs);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- rrs->is->commands[rrs->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- melt_cmd = TALER_TESTING_interpreter_lookup_command
- (rrs->is, rrs->melt_reference);
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- rrs->num_fresh_coins = num_coins;
- switch (http_status)
- {
- case MHD_HTTP_OK:
- rrs->fresh_coins = GNUNET_new_array (num_coins,
- struct TALER_TESTING_FreshCoinData);
- for (unsigned int i = 0; i<num_coins; i++)
- {
- struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_denom_pub (melt_cmd,
- i,
- &fc->pk))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- fc->coin_priv = coin_privs[i].coin_priv;
- fc->blinding_key = coin_privs[i].blinding_key;
- fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup
- (sigs[i].rsa_signature);
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unknown HTTP status %d\n",
- http_status);
- }
- TALER_TESTING_interpreter_next (rrs->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_reveal_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefreshRevealState *rrs = cls;
- struct RefreshMeltState *rms;
- const struct TALER_TESTING_Command *melt_cmd;
-
- rrs->is = is;
- melt_cmd = TALER_TESTING_interpreter_lookup_command
- (is, rrs->melt_reference);
-
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rrs->is);
- return;
- }
- rms = melt_cmd->cls;
- rrs->rrh = TALER_EXCHANGE_refresh_reveal
- (is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- rms->noreveal_index,
- &reveal_cb, rrs);
-
- if (NULL == rrs->rrh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-}
-
-
-/**
- * Free the state from a "refresh reveal" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-refresh_reveal_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefreshRevealState *rrs = cls;
-
- if (NULL != rrs->rrh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rrs->is->ip,
- cmd->label);
-
- TALER_EXCHANGE_refresh_reveal_cancel (rrs->rrh);
- rrs->rrh = NULL;
- }
- if (NULL != rrs->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rrs->retry_task);
- rrs->retry_task = NULL;
- }
-
- for (unsigned int j = 0; j < rrs->num_fresh_coins; j++)
- GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature);
-
- GNUNET_free_non_null (rrs->fresh_coins);
- rrs->fresh_coins = NULL;
- rrs->num_fresh_coins = 0;
- GNUNET_free (rrs);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_link_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #refresh_link_run.
- *
- * @param cls a `struct RefreshLinkState`
- */
-static void
-do_link_retry (void *cls)
-{
- struct RefreshLinkState *rls = cls;
-
- rls->retry_task = NULL;
- refresh_link_run (rls,
- NULL,
- rls->is);
-}
-
-
-/**
- * "refresh link" operation callback, checks that HTTP response
- * code is expected _and_ that all the linked coins were actually
- * withdrawn by the "refresh reveal" CMD.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code
- * @param num_coins number of fresh coins created, length of the
- * @a sigs and @a coin_privs arrays, 0 if the operation
- * failed.
- * @param coin_privs array of @a num_coins private keys for the
- * coins that were created, NULL on error.
- * @param sigs array of signature over @a num_coins coins, NULL on
- * error.
- * @param pubs array of public keys for the @a sigs,
- * NULL on error.
- * @param full_response raw response from the exchange.
- */
-static void
-link_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int num_coins,
- const struct TALER_CoinSpendPrivateKeyP *coin_privs,
- const struct TALER_DenominationSignature *sigs,
- const struct TALER_DenominationPublicKey *pubs,
- const json_t *full_response)
-{
-
- struct RefreshLinkState *rls = cls;
- const struct TALER_TESTING_Command *reveal_cmd;
- struct TALER_TESTING_Command *link_cmd
- = &rls->is->commands[rls->is->ip];
- unsigned int found;
- const unsigned int *num_fresh_coins;
-
- rls->rlh = NULL;
- if (rls->expected_response_code != http_status)
- {
- if (GNUNET_YES == rls->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying refresh link failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- rls->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- rls->backoff = EXCHANGE_LIB_BACKOFF (rls->backoff);
- rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff,
- &do_link_retry,
- rls);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- link_cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- reveal_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rls->reveal_reference);
-
- if (NULL == reveal_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- switch (http_status)
- {
- case MHD_HTTP_OK:
- /* check that number of coins returned matches */
- if (GNUNET_OK != TALER_TESTING_get_trait_uint
- (reveal_cmd, 0, &num_fresh_coins))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- if (num_coins != *num_fresh_coins)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected number of fresh coins: %d vs %d in %s:%u\n",
- num_coins,
- *num_fresh_coins,
- __FILE__,
- __LINE__);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- /* check that the coins match */
- for (unsigned int i = 0; i<num_coins; i++)
- for (unsigned int j = i + 1; j<num_coins; j++)
- if (0 == GNUNET_memcmp
- (&coin_privs[i], &coin_privs[j]))
- GNUNET_break (0);
- /* Note: coins might be legitimately permutated in here... */
- found = 0;
-
- /* Will point to the pointer inside the cmd state. */
- const struct TALER_TESTING_FreshCoinData *fc = NULL;
-
- if (GNUNET_OK != TALER_TESTING_get_trait_fresh_coins
- (reveal_cmd, 0, &fc))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- for (unsigned int i = 0; i<num_coins; i++)
- for (unsigned int j = 0; j<num_coins; j++)
- {
- if ( (0 == GNUNET_memcmp
- (&coin_privs[i], &fc[j].coin_priv)) &&
- (0 == GNUNET_CRYPTO_rsa_signature_cmp
- (fc[i].sig.rsa_signature,
- sigs[j].rsa_signature)) &&
- (0 == GNUNET_CRYPTO_rsa_public_key_cmp
- (fc[i].pk->key.rsa_public_key,
- pubs[j].rsa_public_key)) )
- {
- found++;
- break;
- }
- }
- if (found != num_coins)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Only %u/%u coins match expectations\n",
- found, num_coins);
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown HTTP response code %u.\n",
- http_status);
- }
- TALER_TESTING_interpreter_next (rls->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_link_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefreshLinkState *rls = cls;
- struct RefreshRevealState *rrs;
- struct RefreshMeltState *rms;
- const struct TALER_TESTING_Command *reveal_cmd;
- const struct TALER_TESTING_Command *melt_cmd;
- const struct TALER_TESTING_Command *coin_cmd;
-
- rls->is = is;
- reveal_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rls->reveal_reference);
-
- if (NULL == reveal_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- rrs = reveal_cmd->cls;
- melt_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rrs->melt_reference);
-
- if (NULL == melt_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- /* find reserve_withdraw command */
- {
- rms = melt_cmd->cls;
- coin_cmd = TALER_TESTING_interpreter_lookup_command
- (rls->is, rms->coin_reference);
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
- }
-
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_cmd, 0, &coin_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-
- /* finally, use private key from withdraw sign command */
- rls->rlh = TALER_EXCHANGE_refresh_link
- (is->exchange, coin_priv, &link_cb, rls);
-
- if (NULL == rls->rlh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rls->is);
- return;
- }
-}
-
-
-/**
- * Free the state of the "refresh link" CMD, and possibly
- * cancel a operation thereof.
- *
- * @param cls closure
- * @param cmd the command which is being cleaned up.
- */
-static void
-refresh_link_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefreshLinkState *rls = cls;
-
- if (NULL != rls->rlh)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rls->is->ip,
- cmd->label);
- TALER_EXCHANGE_refresh_link_cancel (rls->rlh);
- rls->rlh = NULL;
- }
- if (NULL != rls->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rls->retry_task);
- rls->retry_task = NULL;
- }
- GNUNET_free (rls);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_melt_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #refresh_melt_run.
- *
- * @param cls a `struct RefreshMeltState`
- */
-static void
-do_melt_retry (void *cls)
-{
- struct RefreshMeltState *rms = cls;
-
- rms->retry_task = NULL;
- refresh_melt_run (rms,
- NULL,
- rms->is);
-}
-
-
-/**
- * Callback for a "refresh melt" operation; checks if the HTTP
- * response code is okay and re-run the melt operation if the
- * CMD was set to do so.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param noreveal_index choice by the exchange in the
- * cut-and-choose protocol, UINT16_MAX on error.
- * @param exchange_pub public key the exchange used for signing.
- * @param full_response raw response body from the exchange.
- */
-static void
-melt_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- uint32_t noreveal_index,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *full_response)
-{
- struct RefreshMeltState *rms = cls;
-
- rms->rmh = NULL;
- if (rms->expected_response_code != http_status)
- {
- if (GNUNET_YES == rms->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying refresh melt failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- rms->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- rms->backoff = EXCHANGE_LIB_BACKOFF (rms->backoff);
- rms->retry_task = GNUNET_SCHEDULER_add_delayed
- (rms->backoff,
- &do_melt_retry,
- rms);
- return;
- }
- }
- GNUNET_log
- (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- rms->is->commands[rms->is->ip].label,
- __FILE__,
- __LINE__);
- json_dumpf (full_response, stderr, 0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- rms->noreveal_index = noreveal_index;
-
- if (GNUNET_YES == rms->double_melt)
- {
- TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
- rms->is->commands[rms->is->ip].label);
- rms->rmh = TALER_EXCHANGE_refresh_melt
- (rms->is->exchange, rms->refresh_data_length,
- rms->refresh_data, &melt_cb, rms);
- rms->double_melt = GNUNET_NO;
- return;
- }
- TALER_TESTING_interpreter_next (rms->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refresh_melt_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefreshMeltState *rms = cls;
- unsigned int num_fresh_coins;
- const char *default_melt_fresh_amounts[] = {
- "EUR:1", "EUR:1", "EUR:1", "EUR:0.1",
- NULL
- };
- const char **melt_fresh_amounts;
-
- if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts))
- melt_fresh_amounts = default_melt_fresh_amounts;
- rms->is = is;
- rms->noreveal_index = UINT16_MAX;
- for (num_fresh_coins = 0;
- NULL != melt_fresh_amounts[num_fresh_coins];
- num_fresh_coins++)
- ;
- rms->num_fresh_coins = num_fresh_coins;
- rms->fresh_pks = GNUNET_new_array
- (num_fresh_coins,
- struct TALER_EXCHANGE_DenomPublicKey);
- {
- struct TALER_Amount melt_amount;
- struct TALER_Amount fresh_amount;
- const struct TALER_DenominationSignature *melt_sig;
- const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
- const struct TALER_TESTING_Command *coin_command;
-
- if (NULL == (coin_command
- = TALER_TESTING_interpreter_lookup_command
- (is, rms->coin_reference)))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
-
- if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
- (coin_command, 0, &rms->melt_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_denom_sig (coin_command,
- 0,
- &melt_sig))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
- (coin_command, 0, &melt_denom_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- /* Melt amount starts with the melt fee of the old coin; we'll add the
- values and withdraw fees of the fresh coins next */
- melt_amount = melt_denom_pub->fee_refresh;
- for (unsigned int i = 0; i<num_fresh_coins; i++)
- {
- const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
-
- if (GNUNET_OK != TALER_string_to_amount
- (melt_fresh_amounts[i], &fresh_amount))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at index %u\n",
- melt_fresh_amounts[i], i);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- fresh_pk = TALER_TESTING_find_pk
- (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount);
- if (NULL == fresh_pk)
- {
- GNUNET_break (0);
- /* Subroutine logs specific error */
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_add (&melt_amount,
- &melt_amount,
- &fresh_amount));
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_add (&melt_amount,
- &melt_amount,
- &fresh_pk->fee_withdraw));
- rms->fresh_pks[i] = *fresh_pk;
- /* Make a deep copy of the RSA key */
- rms->fresh_pks[i].key.rsa_public_key
- = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key);
- }
- rms->refresh_data
- = TALER_EXCHANGE_refresh_prepare (rms->melt_priv,
- &melt_amount,
- melt_sig,
- melt_denom_pub,
- num_fresh_coins,
- rms->fresh_pks,
- &rms->refresh_data_length);
-
- if (NULL == rms->refresh_data)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- rms->rmh = TALER_EXCHANGE_refresh_melt (is->exchange,
- rms->refresh_data_length,
- rms->refresh_data,
- &melt_cb,
- rms);
-
- if (NULL == rms->rmh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (rms->is);
- return;
- }
- }
-}
-
-
-/**
- * Free the "refresh melt" CMD state, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure, must be a `struct RefreshMeltState`.
- * @param cmd the command which is being cleaned up.
- */
-static void
-refresh_melt_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefreshMeltState *rms = cls;
-
- if (NULL != rms->rmh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rms->is->ip, rms->is->commands[rms->is->ip].label);
- TALER_EXCHANGE_refresh_melt_cancel (rms->rmh);
- rms->rmh = NULL;
- }
- if (NULL != rms->retry_task)
- {
- GNUNET_SCHEDULER_cancel (rms->retry_task);
- rms->retry_task = NULL;
- }
- if (NULL != rms->fresh_pks)
- {
- for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
- GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key);
- }
- GNUNET_free_non_null (rms->fresh_pks);
- rms->fresh_pks = NULL;
- GNUNET_free_non_null (rms->refresh_data);
- rms->refresh_data = NULL;
- rms->refresh_data_length = 0;
- GNUNET_free_non_null (rms->melt_fresh_amounts);
- GNUNET_free (rms);
-}
-
-
-/**
- * Offer internal data to the "refresh melt" CMD.
- *
- * @param cls closure.
- * @param[out] ret result (could be anything).
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-refresh_melt_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct RefreshMeltState *rms = cls;
-
- if (index >= rms->num_fresh_coins)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- {
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]),
- TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
- }
-}
-
-
-/**
- * Parse list of amounts for melt operation.
- *
- * @param[in,out] rms where to store the list
- * @param ap NULL-termianted list of amounts to be melted (one per fresh coin)
- * @return #GNUNET_OK on success
- */
-static int
-parse_amounts (struct RefreshMeltState *rms,
- va_list ap)
-{
- unsigned int len;
- unsigned int off;
- const char *amount;
-
- len = 0;
- off = 0;
- while (NULL != (amount = va_arg (ap, const char *)))
- {
- if (len == off)
- {
- struct TALER_Amount a;
-
- GNUNET_array_grow (rms->melt_fresh_amounts,
- len,
- off + 16);
- if (GNUNET_OK !=
- TALER_string_to_amount (amount, &a))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at index %u\n",
- amount, off);
- GNUNET_free (rms->melt_fresh_amounts);
- rms->melt_fresh_amounts = NULL;
- return GNUNET_SYSERR;
- }
- rms->melt_fresh_amounts[off++] = amount;
- }
- }
- if (0 == off)
- return GNUNET_OK; /* no amounts given == use defaults! */
- /* ensure NULL-termination */
- GNUNET_array_grow (rms->melt_fresh_amounts,
- len,
- off + 1);
- return GNUNET_OK;
-}
-
-
-/**
- * Create a "refresh melt" command.
- *
- * @param label command label.
- * @param coin_reference reference to a command
- * that will provide a coin to refresh.
- * @param expected_response_code expected HTTP code.
- * @param ... NULL-terminated list of amounts to be melted
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt (const char *label,
- const char *coin_reference,
- unsigned int expected_response_code,
- ...)
-{
- struct RefreshMeltState *rms;
- va_list ap;
-
- rms = GNUNET_new (struct RefreshMeltState);
- rms->coin_reference = coin_reference;
- rms->expected_response_code = expected_response_code;
- va_start (ap, expected_response_code);
- GNUNET_assert (GNUNET_OK ==
- parse_amounts (rms, ap));
- va_end (ap);
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = rms,
- .run = &refresh_melt_run,
- .cleanup = &refresh_melt_cleanup,
- .traits = &refresh_melt_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Create a "refresh melt" CMD that does TWO /refresh/melt
- * requests. This was needed to test the replay of a valid melt
- * request, see #5312.
- *
- * @param label command label
- * @param coin_reference reference to a command that will provide
- * a coin to refresh
- * @param expected_response_code expected HTTP code
- * @param ... NULL-terminated list of amounts to be melted
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt_double (const char *label,
- const char *coin_reference,
- unsigned int expected_response_code,
- ...)
-{
- struct RefreshMeltState *rms;
- va_list ap;
-
- rms = GNUNET_new (struct RefreshMeltState);
- rms->coin_reference = coin_reference;
- rms->expected_response_code = expected_response_code;
- rms->double_melt = GNUNET_YES;
- va_start (ap, expected_response_code);
- GNUNET_assert (GNUNET_OK ==
- parse_amounts (rms, ap));
- va_end (ap);
- {
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .cls = rms,
- .run = &refresh_melt_run,
- .cleanup = &refresh_melt_cleanup,
- .traits = &refresh_melt_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a "refresh melt" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct RefreshMeltState *rms;
-
- GNUNET_assert (&refresh_melt_run == cmd.run);
- rms = cmd.cls;
- rms->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/**
- * Offer internal data from a "refresh reveal" CMD.
- *
- * @param cls closure.
- * @param[out] ret result (could be anything).
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-refresh_reveal_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct RefreshRevealState *rrs = cls;
- unsigned int num_coins = rrs->num_fresh_coins;
-#define NUM_TRAITS ((num_coins * 4) + 3)
- struct TALER_TESTING_Trait traits[NUM_TRAITS];
-
- /* Making coin privs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[i] = TALER_TESTING_make_trait_coin_priv
- (i, &rrs->fresh_coins[i].coin_priv);
-
- /* Making denom pubs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[num_coins + i]
- = TALER_TESTING_make_trait_denom_pub
- (i, rrs->fresh_coins[i].pk);
-
- /* Making denom sigs traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[(num_coins * 2) + i]
- = TALER_TESTING_make_trait_denom_sig
- (i, &rrs->fresh_coins[i].sig);
- /* blinding key traits */
- for (unsigned int i = 0; i<num_coins; i++)
- traits[(num_coins * 3) + i]
- = TALER_TESTING_make_trait_blinding_key (i,
- &rrs->fresh_coins[i].blinding_key),
-
- /* number of fresh coins */
- traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint
- (0, &rrs->num_fresh_coins);
-
- /* whole array of fresh coins */
- traits[(num_coins * 4) + 1]
- = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins),
-
- /* end of traits */
- traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end ();
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Create a "refresh reveal" command.
- *
- * @param label command label.
- * @param melt_reference reference to a "refresh melt" command.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_reveal (const char *label,
- const char *melt_reference,
- unsigned int expected_response_code)
-{
- struct RefreshRevealState *rrs;
-
- rrs = GNUNET_new (struct RefreshRevealState);
- rrs->melt_reference = melt_reference;
- rrs->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rrs,
- .label = label,
- .run = &refresh_reveal_run,
- .cleanup = &refresh_reveal_cleanup,
- .traits = &refresh_reveal_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a "refresh reveal" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct RefreshRevealState *rrs;
-
- GNUNET_assert (&refresh_reveal_run == cmd.run);
- rrs = cmd.cls;
- rrs->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/**
- * Create a "refresh link" command.
- *
- * @param label command label.
- * @param reveal_reference reference to a "refresh reveal" CMD.
- * @param expected_response_code expected HTTP response code
- * @return the "refresh link" command
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_link (const char *label,
- const char *reveal_reference,
- unsigned int expected_response_code)
-{
- struct RefreshLinkState *rrs;
-
- rrs = GNUNET_new (struct RefreshLinkState);
- rrs->reveal_reference = reveal_reference;
- rrs->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rrs,
- .label = label,
- .run = &refresh_link_run,
- .cleanup = &refresh_link_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a "refresh link" command to enable retries.
- *
- * @param cmd command
- * @return modified command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct RefreshLinkState *rls;
-
- GNUNET_assert (&refresh_link_run == cmd.run);
- rls = cmd.cls;
- rls->do_retry = GNUNET_YES;
- return cmd;
-}
diff --git a/src/lib/testing_api_cmd_refund.c b/src/lib/testing_api_cmd_refund.c
@@ -1,333 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-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 lib/testing_api_cmd_refund.c
- * @brief Implement the /refund test command, plus other
- * corollary commands (?).
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "refund" CMD.
- */
-struct RefundState
-{
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Amount to be refunded.
- */
- const char *refund_amount;
-
- /**
- * Expected refund fee.
- */
- const char *refund_fee;
-
- /**
- * Reference to any command that can provide a coin to refund.
- */
- const char *coin_reference;
-
- /**
- * Refund transaction identifier.
- */
- uint64_t refund_transaction_id;
-
- /**
- * Connection to the exchange.
- */
- struct TALER_EXCHANGE_Handle *exchange;
-
- /**
- * Handle to the refund operation.
- */
- struct TALER_EXCHANGE_RefundHandle *rh;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Check the result for the refund request, just check if the
- * response code is acceptable.
- *
- * @param cls closure
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param exchange_pub public key the exchange
- * used for signing @a obj.
- * @param obj response object.
- */
-static void
-refund_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *obj)
-{
-
- struct RefundState *rs = cls;
- struct TALER_TESTING_Command *refund_cmd;
-
- refund_cmd = &rs->is->commands[rs->is->ip];
- rs->rh = NULL;
- if (rs->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- refund_cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (obj, stderr, 0);
- TALER_TESTING_interpreter_fail (rs->is);
- return;
- }
- TALER_TESTING_interpreter_next (rs->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-refund_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct RefundState *rs = cls;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- struct TALER_CoinSpendPublicKeyP coin;
- const json_t *contract_terms;
- struct GNUNET_HashCode h_contract_terms;
- struct TALER_Amount refund_fee;
- struct TALER_Amount refund_amount;
- const struct TALER_MerchantPrivateKeyP *merchant_priv;
- const struct TALER_TESTING_Command *coin_cmd;
-
- rs->exchange = is->exchange;
- rs->is = is;
-
- if (GNUNET_OK !=
- TALER_string_to_amount (rs->refund_amount,
- &refund_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u/%s\n",
- rs->refund_amount,
- is->ip,
- cmd->label);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_string_to_amount (rs->refund_fee,
- &refund_fee))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %u/%s\n",
- rs->refund_fee,
- is->ip,
- cmd->label);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
- rs->coin_reference);
- if (NULL == coin_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_contract_terms (coin_cmd,
- 0,
- &contract_terms))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (contract_terms,
- &h_contract_terms));
-
- /* Hunting for a coin .. */
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (coin_cmd,
- 0,
- &coin_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin.eddsa_pub);
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_merchant_priv (coin_cmd,
- 0,
- &merchant_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- rs->rh = TALER_EXCHANGE_refund (rs->exchange,
- &refund_amount,
- &refund_fee,
- &h_contract_terms,
- &coin,
- rs->refund_transaction_id,
- merchant_priv,
- &refund_cb,
- rs);
- GNUNET_assert (NULL != rs->rh);
-}
-
-
-/**
- * Free the state from a "refund" CMD, and possibly cancel
- * a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-refund_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct RefundState *rs = cls;
-
- if (NULL != rs->rh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- rs->is->ip,
- cmd->label);
- TALER_EXCHANGE_refund_cancel (rs->rh);
- rs->rh = NULL;
- }
- GNUNET_free (rs);
-}
-
-
-/**
- * Create a "refund" command.
- *
- * @param label command label.
- * @param expected_response_code expected HTTP status code.
- * @param refund_amount the amount to ask a refund for.
- * @param refund_fee expected refund fee.
- * @param coin_reference reference to a command that can
- * provide a coin to be refunded.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refund (const char *label,
- unsigned int expected_response_code,
- const char *refund_amount,
- const char *refund_fee,
- const char *coin_reference)
-{
- struct RefundState *rs;
-
- rs = GNUNET_new (struct RefundState);
-
- rs->expected_response_code = expected_response_code;
- rs->refund_amount = refund_amount;
- rs->refund_fee = refund_fee;
- rs->coin_reference = coin_reference;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rs,
- .label = label,
- .run = &refund_run,
- .cleanup = &refund_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Create a "refund" command, allow to specify refund transaction
- * id. Mainly used to create conflicting requests.
- *
- * @param label command label.
- * @param expected_response_code expected HTTP status code.
- * @param refund_amount the amount to ask a refund for.
- * @param refund_fee expected refund fee.
- * @param coin_reference reference to a command that can
- * provide a coin to be refunded.
- * @param refund_transaction_id transaction id to use
- * in the request.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_refund_with_id
- (const char *label,
- unsigned int expected_response_code,
- const char *refund_amount,
- const char *refund_fee,
- const char *coin_reference,
- uint64_t refund_transaction_id)
-{
- struct RefundState *rs;
-
- rs = GNUNET_new (struct RefundState);
- rs->expected_response_code = expected_response_code;
- rs->refund_amount = refund_amount;
- rs->refund_fee = refund_fee;
- rs->coin_reference = coin_reference;
- rs->refund_transaction_id = refund_transaction_id;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = rs,
- .label = label,
- .run = &refund_run,
- .cleanup = &refund_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_serialize_keys.c b/src/lib/testing_api_cmd_serialize_keys.c
@@ -1,296 +0,0 @@
-/*
- 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 lib/testing_api_cmd_serialize_keys.c
- * @brief Lets tests use the keys serialization API.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include <jansson.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Internal state for a serialize-keys CMD.
- */
-struct SerializeKeysState
-{
- /**
- * Serialized keys.
- */
- json_t *keys;
-
- /**
- * Exchange URL. Needed because the exchange gets disconnected
- * from, after keys serialization. This value is then needed by
- * subsequent commands that have to reconnect to the exchagne.
- */
- char *exchange_url;
-};
-
-
-/**
- * Internal state for a connect-with-state CMD.
- */
-struct ConnectWithStateState
-{
-
- /**
- * Reference to a CMD that offers a serialized key-state
- * that will be used in the reconnection.
- */
- const char *state_reference;
-
- /**
- * If set to GNUNET_YES, then the /keys callback has already
- * been passed the control to the next CMD. This is necessary
- * because it is not uncommon that the /keys callback gets
- * invoked multiple times, and without this flag, we would keep
- * going "next" CMD upon every invocation (causing impredictable
- * behaviour as for the instruction pointer.)
- */
- unsigned int consumed;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-serialize_keys_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct SerializeKeysState *sks = cls;
-
- sks->keys = TALER_EXCHANGE_serialize_data (is->exchange);
- if (NULL == sks->keys)
- TALER_TESTING_interpreter_fail (is);
-
- sks->exchange_url = GNUNET_strdup
- (TALER_EXCHANGE_get_base_url (is->exchange));
- TALER_EXCHANGE_disconnect (is->exchange);
- is->exchange = NULL;
- is->working = GNUNET_NO;
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state of a "serialize keys" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-serialize_keys_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct SerializeKeysState *sks = cls;
-
- if (NULL != sks->keys)
- {
- json_decref (sks->keys);
- }
- GNUNET_free_non_null (sks->exchange_url);
- GNUNET_free (sks);
-}
-
-
-/**
- * Offer serialized keys as trait.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-serialize_keys_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct SerializeKeysState *sks = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_exchange_keys (0, sks->keys),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- sks->exchange_url),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-connect_with_state_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct ConnectWithStateState *cwss = cls;
- const struct TALER_TESTING_Command *state_cmd;
- const json_t *serialized_keys;
- const char *exchange_url;
-
- /* This command usually gets rescheduled after serialized
- * reconnection. */
- if (GNUNET_YES == cwss->consumed)
- {
- TALER_TESTING_interpreter_next (is);
- return;
- }
-
- cwss->is = is;
- state_cmd = TALER_TESTING_interpreter_lookup_command
- (is, cwss->state_reference);
-
- /* Command providing serialized keys not found. */
- if (NULL == state_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_exchange_keys (state_cmd,
- 0,
- &serialized_keys));
- {
- char *dump;
-
- dump = json_dumps (serialized_keys,
- JSON_INDENT (1));
- TALER_LOG_DEBUG ("Serialized key-state: %s\n",
- dump);
- free (dump);
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_url (state_cmd,
- TALER_TESTING_UT_EXCHANGE_BASE_URL,
- &exchange_url));
- is->exchange = TALER_EXCHANGE_connect (is->ctx,
- exchange_url,
- TALER_TESTING_cert_cb,
- cwss,
- TALER_EXCHANGE_OPTION_DATA,
- serialized_keys,
- TALER_EXCHANGE_OPTION_END);
- cwss->consumed = GNUNET_YES;
-}
-
-
-/**
- * Cleanup the state of a "connect with state" CMD. Just
- * a placeholder to avoid jumping on an invalid address.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-connect_with_state_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct ConnectWithStateState *cwss = cls;
-
- GNUNET_free (cwss);
-}
-
-
-/**
- * Make a serialize-keys CMD. It will ask for
- * keys serialization __and__ disconnect from the
- * exchange.
- *
- * @param label CMD label
- * @return the CMD.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_serialize_keys (const char *label)
-{
- struct SerializeKeysState *sks;
-
- sks = GNUNET_new (struct SerializeKeysState);
- {
- struct TALER_TESTING_Command cmd = {
- .cls = sks,
- .label = label,
- .run = serialize_keys_run,
- .cleanup = serialize_keys_cleanup,
- .traits = serialize_keys_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a connect-with-state CMD. This command
- * will use a serialized key state to reconnect
- * to the exchange.
- *
- * @param label command label
- * @param state_reference label of a CMD offering
- * a serialized key state.
- * @return the CMD.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_connect_with_state (const char *label,
- const char *state_reference)
-{
- struct ConnectWithStateState *cwss;
-
- cwss = GNUNET_new (struct ConnectWithStateState);
- cwss->state_reference = state_reference;
- cwss->consumed = GNUNET_NO;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = cwss,
- .label = label,
- .run = connect_with_state_run,
- .cleanup = connect_with_state_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_signal.c b/src/lib/testing_api_cmd_signal.c
@@ -1,116 +0,0 @@
-/*
- 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 lib/testing_api_cmd_signal.c
- * @brief command(s) to send signals to processes.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "signal" CMD.
- */
-struct SignalState
-{
- /**
- * The process to send the signal to.
- */
- struct GNUNET_OS_Process *process;
-
- /**
- * The signal to send to the process.
- */
- int signal;
-};
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-signal_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct SignalState *ss = cls;
-
- GNUNET_break (0 == GNUNET_OS_process_kill
- (ss->process, ss->signal));
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Signaling '%d'..\n",
- ss->signal);
- sleep (6);
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state from a "signal" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-signal_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct SignalState *ss = cls;
-
- GNUNET_free (ss);
-}
-
-
-/**
- * Create a "signal" CMD.
- *
- * @param label command label.
- * @param process handle to the process to signal.
- * @param signal signal to send.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_signal (const char *label,
- struct GNUNET_OS_Process *process,
- int signal)
-{
- struct SignalState *ss;
-
- ss = GNUNET_new (struct SignalState);
- ss->process = process;
- ss->signal = signal;
-
-
- struct TALER_TESTING_Command cmd = {
- .cls = ss,
- .label = label,
- .run = &signal_run,
- .cleanup = &signal_cleanup
- };
-
- return cmd;
-}
diff --git a/src/lib/testing_api_cmd_sleep.c b/src/lib/testing_api_cmd_sleep.c
@@ -1,134 +0,0 @@
-/*
- 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 lib/testing_api_cmd_sleep.c
- * @brief command(s) to sleep for a bit
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "sleep" CMD.
- */
-struct SleepState
-{
-
- /**
- * How long should we sleep?
- */
- unsigned int duration;
-};
-
-
-/**
- * No traits to offer, just provide a stub to be called when
- * some CMDs iterates through the list of all the commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the trait to return.
- * @return #GNUNET_OK on success.
- */
-static int
-sleep_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- return GNUNET_NO;
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-sleep_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct SleepState *ss = cls;
-
- sleep (ss->duration);
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Cleanup the state from a "sleep" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-sleep_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct SleepState *ss = cls;
-
- (void) cmd;
- GNUNET_free (ss);
-}
-
-
-/**
- * Sleep for @a duration_s seconds.
- *
- * @param label command label.
- * @param duration_s number of seconds to sleep
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_sleep (const char *label,
- unsigned int duration_s)
-{
- struct SleepState *ss;
-
- ss = GNUNET_new (struct SleepState);
- ss->duration = duration_s;
-
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ss,
- .label = label,
- .run = &sleep_run,
- .cleanup = &sleep_cleanup,
- .traits = &sleep_traits
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_sleep.c */
diff --git a/src/lib/testing_api_cmd_status.c b/src/lib/testing_api_cmd_status.c
@@ -1,238 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2020 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 lib/testing_api_cmd_status.c
- * @brief Implement the /reserve/status test command.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "status" CMD.
- */
-struct StatusState
-{
- /**
- * Label to the command which created the reserve to check,
- * needed to resort the reserve key.
- */
- const char *reserve_reference;
-
- /**
- * Handle to the "reserve status" operation.
- */
- struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
-
- /**
- * Expected reserve balance.
- */
- const char *expected_balance;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Check that the reserve balance and HTTP response code are
- * both acceptable.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param json original JSON response from the exchange
- * @param balance current balance in the reserve, NULL on error.
- * @param history_length number of entries in the transaction
- * history, 0 on error.
- * @param history detailed transaction history, NULL on error.
- */
-static void
-reserve_status_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const json_t *json,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_EXCHANGE_ReserveHistory *history)
-{
- struct StatusState *ss = cls;
- struct TALER_Amount eb;
-
- ss->rsh = NULL;
- if (ss->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected HTTP response code: %d in %s:%u\n",
- http_status,
- __FILE__,
- __LINE__);
- TALER_TESTING_interpreter_fail (ss->is);
- return;
- }
-
- GNUNET_assert (GNUNET_OK ==
- TALER_string_to_amount (ss->expected_balance,
- &eb));
-
- if (0 != TALER_amount_cmp (&eb,
- balance))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected amount in reserve: %s\n",
- TALER_amount_to_string (balance));
- TALER_TESTING_interpreter_fail (ss->is);
- return;
- }
-
- /**
- * TODO (#6049): We should check that reserve history is consistent. Every
- * command which relates to reserve 'x' should be added in a linked list of
- * all commands that relate to the same reserve 'x'.
- *
- * API-wise, any command that relates to a reserve should offer a
- * method called e.g. "compare_with_history" that takes an element
- * of the array returned by "/reserve/status" and checks if that
- * element correspond to itself (= the command exposing the check-
- * method).
- *
- * IDEA: Maybe realize this via another trait, some kind of
- * "reserve history update trait" which returns information about
- * how the command changes the history (provided only by commands
- * that change reserve balances)?
- *///
- TALER_TESTING_interpreter_next (ss->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command being executed.
- * @param is the interpreter state.
- */
-static void
-status_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct StatusState *ss = cls;
- const struct TALER_TESTING_Command *create_reserve;
- const struct TALER_ReservePublicKeyP *reserve_pubp;
-
- ss->is = is;
- create_reserve
- = TALER_TESTING_interpreter_lookup_command (is,
- ss->reserve_reference);
-
- if (NULL == create_reserve)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (create_reserve,
- 0,
- &reserve_pubp))
- {
- GNUNET_break (0);
- TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- ss->rsh = TALER_EXCHANGE_reserve_status (is->exchange,
- reserve_pubp,
- &reserve_status_cb,
- ss);
-}
-
-
-/**
- * Cleanup the state from a "reserve status" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-status_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct StatusState *ss = cls;
-
- if (NULL != ss->rsh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ss->is->ip,
- cmd->label);
- TALER_EXCHANGE_reserve_status_cancel (ss->rsh);
- ss->rsh = NULL;
- }
- GNUNET_free (ss);
-}
-
-
-/**
- * Create a "reserve status" command.
- *
- * @param label the command label.
- * @param reserve_reference reference to the reserve to check.
- * @param expected_balance expected balance for the reserve.
- * @param expected_response_code expected HTTP response code.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_status (const char *label,
- const char *reserve_reference,
- const char *expected_balance,
- unsigned int expected_response_code)
-{
- struct StatusState *ss;
-
- GNUNET_assert (NULL != reserve_reference);
- ss = GNUNET_new (struct StatusState);
- ss->reserve_reference = reserve_reference;
- ss->expected_balance = expected_balance;
- ss->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ss,
- .label = label,
- .run = &status_run,
- .cleanup = &status_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_track.c b/src/lib/testing_api_cmd_track.c
@@ -1,806 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2020 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 lib/testing_api_cmd_track.c
- * @brief Implement the testing CMDs for the /track operations.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-/**
- * State for a "track transaction" CMD.
- */
-struct TrackTransactionState
-{
-
- /**
- * If non NULL, will provide a WTID to be compared against
- * the one returned by the "track transaction" operation.
- */
- const char *bank_transfer_reference;
-
- /**
- * The WTID associated by the transaction being tracked.
- */
- struct TALER_WireTransferIdentifierRawP wtid;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Reference to any operation that can provide a transaction.
- * Will be the transaction to track.
- */
- const char *transaction_reference;
-
- /**
- * Index of the coin involved in the transaction. Recall:
- * at the exchange, the tracking is done _per coin_.
- */
- unsigned int coin_index;
-
- /**
- * Handle to the "track transaction" pending operation.
- */
- struct TALER_EXCHANGE_TrackTransactionHandle *tth;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * State for a "track transfer" CMD.
- */
-struct TrackTransferState
-{
-
- /**
- * Expected amount for the WTID being tracked.
- */
- const char *expected_total_amount;
-
- /**
- * Expected fee for this WTID.
- */
- const char *expected_wire_fee;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Reference to any operation that can provide a WTID.
- * Will be the WTID to track.
- */
- const char *wtid_reference;
-
- /**
- * Reference to any operation that can provide wire details.
- * Those wire details will then be matched against the credit
- * bank account of the tracked WTID. This way we can test that
- * a wire transfer paid back one particular bank account.
- */
- const char *wire_details_reference;
-
- /**
- * Reference to any operation that can provide an amount.
- * This way we can check that the transferred amount matches
- * our expectations.
- */
- const char *total_amount_reference;
-
- /**
- * Index to the WTID to pick, in case @a wtid_reference has
- * many on offer.
- */
- unsigned int index;
-
- /**
- * Handle to a pending "track transfer" operation.
- */
- struct TALER_EXCHANGE_TrackTransferHandle *tth;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Checks what is returned by the "track transaction" operation.
- * Checks that the HTTP response code is acceptable, and - if the
- * right reference is non NULL - that the wire transfer subject
- * line matches our expectations.
- *
- * @param cls closure.
- * @param http_status HTTP status code we got.
- * @param ec taler-specific error code.
- * @param exchange_pub public key of the exchange
- * @param json original json reply (may include signatures, those
- * have then been validated already).
- * @param wtid wire transfer identifier, NULL if exchange did not
- * execute the transaction yet.
- * @param execution_time actual or planned execution time for the
- * wire transfer.
- * @param coin_contribution contribution to the total amount of
- * the deposited coin (can be NULL).
- */
-static void
-deposit_wtid_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *json,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_Amount *coin_contribution)
-{
- struct TrackTransactionState *tts = cls;
- struct TALER_TESTING_Interpreter *is = tts->is;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
-
- (void) coin_contribution;
- (void) exchange_pub;
- tts->tth = NULL;
- if (tts->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (json, stderr, 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- tts->wtid = *wtid;
- if (NULL != tts->bank_transfer_reference)
- {
- const struct TALER_TESTING_Command *bank_transfer_cmd;
- const struct TALER_WireTransferIdentifierRawP *wtid_want;
-
- /* _this_ wire transfer subject line. */
- bank_transfer_cmd = TALER_TESTING_interpreter_lookup_command
- (is, tts->bank_transfer_reference);
- if (NULL == bank_transfer_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_wtid
- (bank_transfer_cmd, 0, &wtid_want))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- /* Compare that expected and gotten subjects match. */
- if (0 != GNUNET_memcmp (wtid,
- wtid_want))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
- }
- break;
- case MHD_HTTP_ACCEPTED:
- /* allowed, nothing to check here */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* allowed, nothing to check here */
- break;
- default:
- GNUNET_break (0);
- break;
- }
- TALER_TESTING_interpreter_next (tts->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-track_transaction_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct TrackTransactionState *tts = cls;
- const struct TALER_TESTING_Command *transaction_cmd;
- const struct TALER_CoinSpendPrivateKeyP *coin_priv;
- struct TALER_CoinSpendPublicKeyP coin_pub;
- const json_t *contract_terms;
- const json_t *wire_details;
- struct GNUNET_HashCode h_wire_details;
- struct GNUNET_HashCode h_contract_terms;
- const struct TALER_MerchantPrivateKeyP *merchant_priv;
-
- tts->is = is;
- transaction_cmd
- = TALER_TESTING_interpreter_lookup_command (tts->is,
- tts->transaction_reference);
- if (NULL == transaction_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_coin_priv (transaction_cmd,
- tts->coin_index,
- &coin_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
- &coin_pub.eddsa_pub);
-
- /* Get the strings.. */
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_wire_details (transaction_cmd,
- 0,
- &wire_details))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_contract_terms (transaction_cmd,
- 0,
- &contract_terms))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- if ( (NULL == wire_details) ||
- (NULL == contract_terms) )
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- /* Should not fail here, json has been parsed already */
- GNUNET_assert
- ( (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (wire_details,
- &h_wire_details)) &&
- (GNUNET_OK ==
- TALER_JSON_hash (contract_terms,
- &h_contract_terms)) );
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_merchant_priv (transaction_cmd,
- 0,
- &merchant_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- tts->tth = TALER_EXCHANGE_track_transaction (is->exchange,
- merchant_priv,
- &h_wire_details,
- &h_contract_terms,
- &coin_pub,
- &deposit_wtid_cb,
- tts);
- GNUNET_assert (NULL != tts->tth);
-}
-
-
-/**
- * Cleanup the state from a "track transaction" CMD, and possibly
- * cancel a operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-track_transaction_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct TrackTransactionState *tts = cls;
-
- if (NULL != tts->tth)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- tts->is->ip,
- cmd->label);
- TALER_EXCHANGE_track_transaction_cancel (tts->tth);
- tts->tth = NULL;
- }
- GNUNET_free (tts);
-}
-
-
-/**
- * Offer internal data from a "track transaction" CMD.
- *
- * @param cls closure.
- * @param[out] ret result (could be anything).
- * @param trait name of the trait.
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success.
- */
-static int
-track_transaction_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct TrackTransactionState *tts = cls;
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_wtid (0, &tts->wtid),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
-}
-
-
-/**
- * Create a "track transaction" command.
- *
- * @param label the command label.
- * @param transaction_reference reference to a deposit operation,
- * will be used to get the input data for the track.
- * @param coin_index index of the coin involved in the transaction.
- * @param expected_response_code expected HTTP response code.
- * @param bank_transfer_reference reference to a command that
- * can offer a WTID so as to check that against what WTID
- * the tracked operation has. Set as NULL if not needed.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_track_transaction (const char *label,
- const char *transaction_reference,
- unsigned int coin_index,
- unsigned int expected_response_code,
- const char *bank_transfer_reference)
-{
- struct TrackTransactionState *tts;
-
- tts = GNUNET_new (struct TrackTransactionState);
- tts->transaction_reference = transaction_reference;
- tts->expected_response_code = expected_response_code;
- tts->bank_transfer_reference = bank_transfer_reference;
- tts->coin_index = coin_index;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = tts,
- .label = label,
- .run = &track_transaction_run,
- .cleanup = &track_transaction_cleanup,
- .traits = &track_transaction_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Cleanup the state for a "track transfer" CMD, and possibly
- * cancel a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-track_transfer_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
-
- struct TrackTransferState *tts = cls;
-
- if (NULL != tts->tth)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- tts->is->ip,
- cmd->label);
- TALER_EXCHANGE_track_transfer_cancel (tts->tth);
- tts->tth = NULL;
- }
- GNUNET_free (tts);
-}
-
-
-/**
- * Check whether the HTTP response code from a "track transfer"
- * operation is acceptable, and all other values like total amount,
- * wire fees and hashed wire details as well.
- *
- * @param cls closure.
- * @param http_status HTTP status code we got.
- * @param ec taler-specific error code.
- * @param exchange_pub public key the exchange used for signing
- * the response.
- * @param json original json reply (may include signatures, those
- * have then been validated already).
- * @param h_wire hash of the wire transfer address the transfer
- * went to, or NULL on error.
- * @param execution_time time when the exchange claims to have
- * performed the wire transfer.
- * @param total_amount total amount of the wire transfer, or NULL
- * if the exchange could not provide any @a wtid (set only
- * if @a http_status is "200 OK").
- * @param wire_fee wire fee that was charged by the exchange.
- * @param details_length length of the @a details array.
- * @param details array with details about the combined
- * transactions.
- */
-static void
-track_transfer_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_ExchangePublicKeyP *exchange_pub,
- const json_t *json,
- const struct GNUNET_HashCode *h_wire,
- struct GNUNET_TIME_Absolute execution_time,
- const struct TALER_Amount *total_amount,
- const struct TALER_Amount *wire_fee,
- unsigned int details_length,
- const struct TALER_TrackTransferDetails *details)
-{
- struct TrackTransferState *tts = cls;
- struct TALER_TESTING_Interpreter *is = tts->is;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
- struct TALER_Amount expected_amount;
-
- (void) exchange_pub;
- tts->tth = NULL;
- if (tts->expected_response_code != http_status)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u to command %s in %s:%u\n",
- http_status,
- cmd->label,
- __FILE__,
- __LINE__);
- json_dumpf (json, stderr, 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- switch (http_status)
- {
- case MHD_HTTP_OK:
- if (NULL == tts->expected_total_amount)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (NULL == tts->expected_wire_fee)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_string_to_amount (tts->expected_total_amount,
- &expected_amount))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (0 != TALER_amount_cmp (total_amount,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Total amount missmatch to command %s - "
- "%s vs %s\n",
- cmd->label,
- TALER_amount_to_string (total_amount),
- TALER_amount_to_string (&expected_amount));
- json_dumpf (json, stderr, 0);
- fprintf (stderr, "\n");
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_string_to_amount (tts->expected_wire_fee,
- &expected_amount))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (0 != TALER_amount_cmp (wire_fee,
- &expected_amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee missmatch to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- /**
- * Optionally checking: (1) wire-details for this transfer
- * match the ones from a referenced "deposit" operation -
- * or any operation that could provide wire-details. (2)
- * Total amount for this transfer matches the one from any
- * referenced command that could provide one.
- */if (NULL != tts->wire_details_reference)
- {
- const struct TALER_TESTING_Command *wire_details_cmd;
- const json_t *wire_details;
- struct GNUNET_HashCode h_wire_details;
-
- if (NULL == (wire_details_cmd
- = TALER_TESTING_interpreter_lookup_command
- (is, tts->wire_details_reference)))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_wire_details (wire_details_cmd,
- 0,
- &wire_details))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_assert
- (GNUNET_OK ==
- TALER_JSON_merchant_wire_signature_hash (wire_details,
- &h_wire_details));
-
- if (0 != GNUNET_memcmp (&h_wire_details,
- h_wire))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire hash missmath to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- if (NULL != tts->total_amount_reference)
- {
- const struct TALER_TESTING_Command *total_amount_cmd;
- const struct TALER_Amount *total_amount_from_reference;
-
- if (NULL == (total_amount_cmd
- = TALER_TESTING_interpreter_lookup_command
- (is, tts->total_amount_reference)))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_amount_obj (total_amount_cmd,
- 0,
- &total_amount_from_reference))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- if (0 != TALER_amount_cmp (total_amount,
- total_amount_from_reference))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Amount missmath to command %s\n",
- cmd->label);
- json_dumpf (json, stderr, 0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- }
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command under execution.
- * @param is the interpreter state.
- */
-static void
-track_transfer_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- /* looking for a wtid to track .. */
- struct TrackTransferState *tts = cls;
- struct TALER_WireTransferIdentifierRawP wtid;
- const struct TALER_WireTransferIdentifierRawP *wtid_ptr;
-
- /* If no reference is given, we'll use a all-zeros
- * WTID */
- memset (&wtid, 0, sizeof (wtid));
- wtid_ptr = &wtid;
-
- tts->is = is;
- if (NULL != tts->wtid_reference)
- {
- const struct TALER_TESTING_Command *wtid_cmd;
-
- wtid_cmd = TALER_TESTING_interpreter_lookup_command
- (tts->is, tts->wtid_reference);
-
- if (NULL == wtid_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
-
- if (GNUNET_OK != TALER_TESTING_get_trait_wtid
- (wtid_cmd, tts->index, &wtid_ptr))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (tts->is);
- return;
- }
- GNUNET_assert (NULL != wtid_ptr);
- }
- tts->tth = TALER_EXCHANGE_track_transfer (is->exchange,
- wtid_ptr,
- &track_transfer_cb,
- tts);
- GNUNET_assert (NULL != tts->tth);
-}
-
-
-/**
- * Make a "track transfer" CMD where no "expected"-arguments,
- * except the HTTP response code, are given. The best use case
- * is when what matters to check is the HTTP response code, e.g.
- * when a bogus WTID was passed.
- *
- * @param label the command label
- * @param wtid_reference reference to any command which can provide
- * a wtid. If NULL is given, then a all zeroed WTID is
- * used that will at 99.9999% probability NOT match any
- * existing WTID known to the exchange.
- * @param index index number of the WTID to track, in case there
- * are multiple on offer.
- * @param expected_response_code expected HTTP response code.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_track_transfer_empty (const char *label,
- const char *wtid_reference,
- unsigned int index,
- unsigned int expected_response_code)
-{
- struct TrackTransferState *tts;
-
- tts = GNUNET_new (struct TrackTransferState);
- tts->wtid_reference = wtid_reference;
- tts->index = index;
- tts->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = tts,
- .label = label,
- .run = &track_transfer_run,
- .cleanup = &track_transfer_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Make a "track transfer" command, specifying which amount and
- * wire fee are expected.
- *
- * @param label the command label.
- * @param wtid_reference reference to any command which can provide
- * a wtid. Will be the one tracked.
- * @param index in case there are multiple WTID offered, this
- * parameter selects a particular one.
- * @param expected_response_code expected HTTP response code.
- * @param expected_total_amount how much money we expect being moved
- * with this wire-transfer.
- * @param expected_wire_fee expected wire fee.
- * @return the command
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_track_transfer (const char *label,
- const char *wtid_reference,
- unsigned int index,
- unsigned int expected_response_code,
- const char *expected_total_amount,
- const char *expected_wire_fee)
-{
- struct TrackTransferState *tts;
-
- tts = GNUNET_new (struct TrackTransferState);
- tts->wtid_reference = wtid_reference;
- tts->index = index;
- tts->expected_response_code = expected_response_code;
- tts->expected_total_amount = expected_total_amount;
- tts->expected_wire_fee = expected_wire_fee;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = tts,
- .label = label,
- .run = &track_transfer_run,
- .cleanup = &track_transfer_cleanup
- };
-
- return cmd;
- }
-}
-
-
-/* end of testing_api_cmd_track.c */
diff --git a/src/lib/testing_api_cmd_wait.c b/src/lib/testing_api_cmd_wait.c
@@ -1,134 +0,0 @@
-/*
- 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 lib/testing_api_cmd_wait.c
- * @brief command(s) to wait on some process
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Cleanup the state from a "wait service" CMD.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-wait_service_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- (void) cls;
- (void) cmd;
- /* nothing to clean. */
- return;
-}
-
-
-/**
- * No traits to offer, just provide a stub to be called when
- * some CMDs iterates through the list of all the commands.
- *
- * @param cls closure.
- * @param[out] ret result.
- * @param trait name of the trait.
- * @param index index number of the trait to return.
- * @return #GNUNET_OK on success.
- */
-static int
-wait_service_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- (void) cls;
- (void) ret;
- (void) trait;
- (void) index;
- return GNUNET_NO;
-}
-
-
-/**
- * Run a "wait service" CMD.
- *
- * @param cls closure.
- * @param cmd the command being run.
- * @param is the interpreter state.
- */
-static void
-wait_service_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- unsigned int iter = 0;
- const char *url = cmd->cls;
- char *wget_cmd;
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null",
- url);
- do
- {
- fprintf (stderr, ".");
-
- if (10 == iter++)
- {
- TALER_LOG_ERROR ("Could not reach the proxied service\n");
- TALER_TESTING_interpreter_fail (is);
- GNUNET_free (wget_cmd);
- return;
- }
- }
- while (0 != system (wget_cmd));
-
- GNUNET_free (wget_cmd);
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * This CMD simply tries to connect via HTTP to the
- * service addressed by @a url. It attemps 10 times
- * before giving up and make the test fail.
- *
- * @param label label for the command.
- * @param url complete URL to connect to.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_wait_service (const char *label,
- const char *url)
-{
- struct TALER_TESTING_Command cmd = {
- .label = label,
- .run = wait_service_run,
- .cleanup = wait_service_cleanup,
- .traits = wait_service_traits,
- .cls = (void *) url
- };
-
- return cmd;
-}
-
-
-/* end of testing_api_cmd_sleep.c */
diff --git a/src/lib/testing_api_cmd_wire.c b/src/lib/testing_api_cmd_wire.c
@@ -1,235 +0,0 @@
-/*
- 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 lib/testing_api_cmd_wire.c
- * @brief command for testing /wire.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * State for a "wire" CMD.
- */
-struct WireState
-{
-
- /**
- * Handle to the /wire operation.
- */
- struct TALER_EXCHANGE_WireHandle *wh;
-
- /**
- * Which wire-method we expect is offered by the exchange.
- */
- const char *expected_method;
-
- /**
- * Flag indicating if the expected method is actually
- * offered.
- */
- unsigned int method_found;
-
- /**
- * Fee we expect is charged for this wire-transfer method.
- */
- const char *expected_fee;
-
- /**
- * Expected HTTP response code.
- */
- unsigned int expected_response_code;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-};
-
-
-/**
- * Check whether the HTTP response code is acceptable, that
- * the expected wire method is offered by the exchange, and
- * that the wire fee is acceptable too.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param accounts_len length of the @a accounts array.
- * @param accounts list of wire accounts of the exchange,
- * NULL on error.
- */
-static void
-wire_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- unsigned int accounts_len,
- const struct TALER_EXCHANGE_WireAccount *accounts)
-{
- struct WireState *ws = cls;
- struct TALER_TESTING_Command *cmd = \
- &ws->is->commands[ws->is->ip];
- struct TALER_Amount expected_fee;
-
- TALER_LOG_DEBUG ("Checking parsed /wire response\n");
- ws->wh = NULL;
- if (ws->expected_response_code != http_status)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return;
- }
-
- if (MHD_HTTP_OK == http_status)
- {
- for (unsigned int i = 0; i<accounts_len; i++)
- {
- char *method;
-
- method = TALER_payto_get_method (accounts[i].url);
- if (0 == strcmp (ws->expected_method,
- method))
- {
- ws->method_found = GNUNET_OK;
- if (NULL != ws->expected_fee)
- {
- GNUNET_assert
- (GNUNET_OK ==
- TALER_string_to_amount (ws->expected_fee,
- &expected_fee));
- const struct TALER_EXCHANGE_WireAggregateFees *waf;
- for (waf = accounts[i].fees;
- NULL != waf;
- waf = waf->next)
- {
- if (0 != TALER_amount_cmp (&waf->wire_fee,
- &expected_fee))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee missmatch to command %s\n",
- cmd->label);
- TALER_TESTING_interpreter_fail (ws->is);
- GNUNET_free (method);
- return;
- }
- }
- }
- }
- TALER_LOG_DEBUG ("Freeing method '%s'\n",
- method);
- GNUNET_free (method);
- }
- if (GNUNET_OK != ws->method_found)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "/wire does not offer method '%s'\n",
- ws->expected_method);
- TALER_TESTING_interpreter_fail (ws->is);
- return;
- }
- }
-
- TALER_TESTING_interpreter_next (ws->is);
-}
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the command to execute.
- * @param is the interpreter state.
- */
-static void
-wire_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct WireState *ws = cls;
- ws->is = is;
- ws->wh = TALER_EXCHANGE_wire (is->exchange,
- &wire_cb,
- ws);
-}
-
-
-/**
- * Cleanup the state of a "wire" CMD, and possibly cancel a
- * pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command which is being cleaned up.
- */
-static void
-wire_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct WireState *ws = cls;
-
- if (NULL != ws->wh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %u (%s) did not complete\n",
- ws->is->ip,
- cmd->label);
- TALER_EXCHANGE_wire_cancel (ws->wh);
- ws->wh = NULL;
- }
- GNUNET_free (ws);
-}
-
-
-/**
- * Create a "wire" command.
- *
- * @param label the command label.
- * @param expected_method which wire-transfer method is expected
- * to be offered by the exchange.
- * @param expected_fee the fee the exchange should charge.
- * @param expected_response_code the HTTP response the exchange
- * should return.
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_wire (const char *label,
- const char *expected_method,
- const char *expected_fee,
- unsigned int expected_response_code)
-{
- struct WireState *ws;
-
- ws = GNUNET_new (struct WireState);
- ws->expected_method = expected_method;
- ws->expected_fee = expected_fee;
- ws->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ws,
- .label = label,
- .run = &wire_run,
- .cleanup = &wire_cleanup
- };
-
- return cmd;
- }
-}
diff --git a/src/lib/testing_api_cmd_withdraw.c b/src/lib/testing_api_cmd_withdraw.c
@@ -1,535 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_cmd_withdraw.c
- * @brief main interpreter loop for testcases
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <microhttpd.h>
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-#include "backoff.h"
-
-
-/**
- * State for a "withdraw" CMD.
- */
-struct WithdrawState
-{
-
- /**
- * Which reserve should we withdraw from?
- */
- const char *reserve_reference;
-
- /**
- * String describing the denomination value we should withdraw.
- * A corresponding denomination key must exist in the exchange's
- * offerings. Can be NULL if @e pk is set instead.
- */
- struct TALER_Amount amount;
-
- /**
- * If @e amount is NULL, this specifies the denomination key to
- * use. Otherwise, this will be set (by the interpreter) to the
- * denomination PK matching @e amount.
- */
- struct TALER_EXCHANGE_DenomPublicKey *pk;
-
- /**
- * Exchange base URL. Only used as offered trait.
- */
- char *exchange_url;
-
- /**
- * Interpreter state (during command).
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Set (by the interpreter) to the exchange's signature over the
- * coin's public key.
- */
- struct TALER_DenominationSignature sig;
-
- /**
- * Private key material of the coin, set by the interpreter.
- */
- struct TALER_PlanchetSecretsP ps;
-
- /**
- * Withdraw handle (while operation is running).
- */
- struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
-
- /**
- * Task scheduled to try later.
- */
- struct GNUNET_SCHEDULER_Task *retry_task;
-
- /**
- * How long do we wait until we retry?
- */
- struct GNUNET_TIME_Relative backoff;
-
- /**
- * Expected HTTP response code to the request.
- */
- unsigned int expected_response_code;
-
- /**
- * Was this command modified via
- * #TALER_TESTING_cmd_withdraw_with_retry to
- * enable retries?
- */
- int do_retry;
-};
-
-
-/**
- * Run the command.
- *
- * @param cls closure.
- * @param cmd the commaind being run.
- * @param is interpreter state.
- */
-static void
-withdraw_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is);
-
-
-/**
- * Task scheduled to re-try #withdraw_run.
- *
- * @param cls a `struct WithdrawState`
- */
-static void
-do_retry (void *cls)
-{
- struct WithdrawState *ws = cls;
-
- ws->retry_task = NULL;
- withdraw_run (ws,
- NULL,
- ws->is);
-}
-
-
-/**
- * "reserve withdraw" operation callback; checks that the
- * response code is expected and store the exchange signature
- * in the state.
- *
- * @param cls closure.
- * @param http_status HTTP response code.
- * @param ec taler-specific error code.
- * @param sig signature over the coin, NULL on error.
- * @param full_response raw response.
- */
-static void
-reserve_withdraw_cb (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const struct TALER_DenominationSignature *sig,
- const json_t *full_response)
-{
- struct WithdrawState *ws = cls;
- struct TALER_TESTING_Interpreter *is = ws->is;
-
- ws->wsh = NULL;
- if (ws->expected_response_code != http_status)
- {
- if (GNUNET_YES == ws->do_retry)
- {
- if ( (0 == http_status) ||
- (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
- (TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS == ec) ||
- (TALER_EC_WITHDRAW_RESERVE_UNKNOWN == ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Retrying withdraw failed with %u/%d\n",
- http_status,
- (int) ec);
- /* on DB conflicts, do not use backoff */
- if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
- ws->backoff = GNUNET_TIME_UNIT_ZERO;
- else
- ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);
- ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff,
- &do_retry,
- ws);
- return;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected response code %u/%d to command %s in %s:%u\n",
- http_status,
- (int) ec,
- TALER_TESTING_interpreter_get_current_label (is),
- __FILE__,
- __LINE__);
- json_dumpf (full_response,
- stderr,
- 0);
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- switch (http_status)
- {
- case MHD_HTTP_OK:
- if (NULL == sig)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- ws->sig.rsa_signature
- = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
- break;
- case MHD_HTTP_FORBIDDEN:
- /* nothing to check */
- break;
- case MHD_HTTP_CONFLICT:
- /* nothing to check */
- break;
- case MHD_HTTP_NOT_FOUND:
- /* nothing to check */
- break;
- default:
- /* Unsupported status code (by test harness) */
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Withdraw test command does not support status code %u\n",
- http_status);
- GNUNET_break (0);
- break;
- }
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Run the command.
- */
-static void
-withdraw_run (void *cls,
- const struct TALER_TESTING_Command *cmd,
- struct TALER_TESTING_Interpreter *is)
-{
- struct WithdrawState *ws = cls;
- const struct TALER_ReservePrivateKeyP *rp;
- const struct TALER_TESTING_Command *create_reserve;
- const struct TALER_EXCHANGE_DenomPublicKey *dpk;
-
- (void) cmd;
- create_reserve = TALER_TESTING_interpreter_lookup_command
- (is, ws->reserve_reference);
- if (NULL == create_reserve)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_priv (create_reserve,
- 0,
- &rp))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
- TALER_planchet_setup_random (&ws->ps);
- ws->is = is;
-
- dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange),
- &ws->amount);
- if (NULL == dpk)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to determine denomination key at %s\n",
- (NULL != cmd) ? cmd->label : "<retried command>");
- GNUNET_assert (0);
- }
- else
- {
- /* We copy the denomination key, as re-querying /keys
- * would free the old one. */
- ws->pk = TALER_EXCHANGE_copy_denomination_key (dpk);
- }
-
- ws->wsh = TALER_EXCHANGE_reserve_withdraw (is->exchange,
- ws->pk,
- rp,
- &ws->ps,
- &reserve_withdraw_cb,
- ws);
- if (NULL == ws->wsh)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-}
-
-
-/**
- * Free the state of a "withdraw" CMD, and possibly cancel
- * a pending operation thereof.
- *
- * @param cls closure.
- * @param cmd the command being freed.
- */
-static void
-withdraw_cleanup (void *cls,
- const struct TALER_TESTING_Command *cmd)
-{
- struct WithdrawState *ws = cls;
-
- if (NULL != ws->wsh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Command %s did not complete\n",
- cmd->label);
- TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh);
- ws->wsh = NULL;
- }
- if (NULL != ws->retry_task)
- {
- GNUNET_SCHEDULER_cancel (ws->retry_task);
- ws->retry_task = NULL;
- }
- if (NULL != ws->sig.rsa_signature)
- {
- GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature);
- ws->sig.rsa_signature = NULL;
- }
- if (NULL != ws->pk)
- {
- TALER_EXCHANGE_destroy_denomination_key (ws->pk);
- ws->pk = NULL;
- }
- GNUNET_free_non_null (ws->exchange_url);
- GNUNET_free (ws);
-}
-
-
-/**
- * Offer internal data to a "withdraw" CMD state to other
- * commands.
- *
- * @param cls closure
- * @param[out] ret result (could be anything)
- * @param trait name of the trait
- * @param index index number of the object to offer.
- * @return #GNUNET_OK on success
- */
-static int
-withdraw_traits (void *cls,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- struct WithdrawState *ws = cls;
- const struct TALER_TESTING_Command *reserve_cmd;
- const struct TALER_ReservePrivateKeyP *reserve_priv;
- const struct TALER_ReservePublicKeyP *reserve_pub;
-
- /* We offer the reserve key where these coins were withdrawn
- * from. */
- reserve_cmd = TALER_TESTING_interpreter_lookup_command
- (ws->is, ws->reserve_reference);
-
- if (NULL == reserve_cmd)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_priv (reserve_cmd,
- 0,
- &reserve_priv))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_reserve_pub (reserve_cmd,
- 0,
- &reserve_pub))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (ws->is);
- return GNUNET_SYSERR;
- }
- if (NULL == ws->exchange_url)
- ws->exchange_url
- = GNUNET_strdup (TALER_EXCHANGE_get_base_url (ws->is->exchange));
- {
- struct TALER_TESTING_Trait traits[] = {
- TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
- &ws->ps.coin_priv),
- TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
- &ws->ps.blinding_key),
- TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
- ws->pk),
- TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
- &ws->sig),
- TALER_TESTING_make_trait_reserve_priv (0,
- reserve_priv),
- TALER_TESTING_make_trait_reserve_pub (0,
- reserve_pub),
- TALER_TESTING_make_trait_amount_obj (0,
- &ws->amount),
- TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
- ws->exchange_url),
- TALER_TESTING_trait_end ()
- };
-
- return TALER_TESTING_get_trait (traits,
- ret,
- trait,
- index);
- }
-}
-
-
-/**
- * Create a withdraw command, letting the caller specify
- * the desired amount as string.
- *
- * @param label command label.
- * @param reserve_reference command providing us with a reserve to withdraw from
- * @param amount how much we withdraw.
- * @param expected_response_code which HTTP response code
- * we expect from the exchange.
- * @return the withdraw command to be executed by the interpreter.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_withdraw_amount (const char *label,
- const char *reserve_reference,
- const char *amount,
- unsigned int expected_response_code)
-{
- struct WithdrawState *ws;
-
- ws = GNUNET_new (struct WithdrawState);
- ws->reserve_reference = reserve_reference;
- if (GNUNET_OK !=
- TALER_string_to_amount (amount,
- &ws->amount))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse amount `%s' at %s\n",
- amount,
- label);
- GNUNET_assert (0);
- }
- ws->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ws,
- .label = label,
- .run = &withdraw_run,
- .cleanup = &withdraw_cleanup,
- .traits = &withdraw_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Create withdraw command, letting the caller specify the
- * amount by a denomination key.
- *
- * @param label command label.
- * @param reserve_reference reference to the reserve to withdraw
- * from; will provide reserve priv to sign the request.
- * @param dk denomination public key.
- * @param expected_response_code expected HTTP response code.
- *
- * @return the command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_withdraw_denomination (const char *label,
- const char *reserve_reference,
- const struct
- TALER_EXCHANGE_DenomPublicKey *dk,
- unsigned int expected_response_code)
-{
- struct WithdrawState *ws;
-
- if (NULL == dk)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Denomination key not specified at %s\n",
- label);
- GNUNET_assert (0);
- }
- ws = GNUNET_new (struct WithdrawState);
- ws->reserve_reference = reserve_reference;
- ws->pk = TALER_EXCHANGE_copy_denomination_key (dk);
- ws->expected_response_code = expected_response_code;
- {
- struct TALER_TESTING_Command cmd = {
- .cls = ws,
- .label = label,
- .run = &withdraw_run,
- .cleanup = &withdraw_cleanup,
- .traits = &withdraw_traits
- };
-
- return cmd;
- }
-}
-
-
-/**
- * Modify a withdraw command to enable retries when the
- * reserve is not yet full or we get other transient
- * errors from the exchange.
- *
- * @param cmd a withdraw command
- * @return the command with retries enabled
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd)
-{
- struct WithdrawState *ws;
-
- GNUNET_assert (&withdraw_run == cmd.run);
- ws = cmd.cls;
- ws->do_retry = GNUNET_YES;
- return cmd;
-}
-
-
-/* end of testing_api_cmd_withdraw.c */
diff --git a/src/lib/testing_api_helpers_auditor.c b/src/lib/testing_api_helpers_auditor.c
@@ -1,229 +0,0 @@
-/*
- 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 lib/testing_api_helpers_auditor.c
- * @brief helper functions
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-#include "taler_auditor_service.h"
-
-
-/**
- * Closure for #cleanup_auditor.
- */
-struct CleanupContext
-{
- /**
- * Where we find the state to clean up.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Next cleanup routine to call, NULL for none.
- */
- GNUNET_SCHEDULER_TaskCallback fcb;
-
- /**
- * Closure for @e fcb
- */
- void *fcb_cls;
-};
-
-
-/**
- * Function to clean up the auditor connection.
- *
- * @param cls a `struct CleanupContext`
- */
-static void
-cleanup_auditor (void *cls)
-{
- struct CleanupContext *cc = cls;
- struct TALER_TESTING_Interpreter *is = cc->is;
-
- TALER_AUDITOR_disconnect (is->auditor);
- is->auditor = NULL;
- if (NULL != cc->fcb)
- cc->fcb (cc->fcb_cls);
- GNUNET_free (cc);
-}
-
-
-/**
- * Closure for #auditor_main_wrapper()
- */
-struct MainWrapperContext
-{
- /**
- * Main function to launch.
- */
- TALER_TESTING_Main main_cb;
-
- /**
- * Closure for @e main_cb.
- */
- void *main_cb_cls;
-
- /**
- * Configuration we use.
- */
- const struct GNUNET_CONFIGURATION_Handle *cfg;
-
- /**
- * Name of the configuration file.
- */
- const char *config_filename;
-
-};
-
-
-/**
- * Function called with information about the auditor.
- *
- * @param cls closure
- * @param vi basic information about the auditor
- * @param compat protocol compatibility information
- */
-static void
-auditor_version_cb (void *cls,
- const struct TALER_AUDITOR_VersionInformation *vi,
- enum TALER_AUDITOR_VersionCompatibility compat)
-{
- struct TALER_TESTING_Interpreter *is = cls;
-
- if (TALER_AUDITOR_VC_MATCH != compat)
- {
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- is->auditor_working = GNUNET_YES;
-}
-
-
-/**
- * Setup the @a is 'auditor' member before running the main test loop.
- *
- * @param cls must be a `struct MainWrapperContext *`
- * @param[in,out] is interpreter state to setup
- */
-static void
-auditor_main_wrapper (void *cls,
- struct TALER_TESTING_Interpreter *is)
-{
- struct MainWrapperContext *mwc = cls;
- struct CleanupContext *cc;
- char *auditor_base_url;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (mwc->cfg,
- "auditor",
- "BASE_URL",
- &auditor_base_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "BASE_URL");
- return;
- }
-
- is->auditor = TALER_AUDITOR_connect (is->ctx,
- auditor_base_url,
- &auditor_version_cb,
- is);
- GNUNET_free (auditor_base_url);
-
- if (NULL == is->auditor)
- {
- GNUNET_break (0);
- return;
- }
-
- cc = GNUNET_new (struct CleanupContext);
- cc->is = is;
- cc->fcb = is->final_cleanup_cb;
- cc->fcb_cls = is->final_cleanup_cb_cls;
- is->final_cleanup_cb = cleanup_auditor;
- is->final_cleanup_cb_cls = cc;
- mwc->main_cb (mwc->main_cb_cls,
- is);
-}
-
-
-/**
- * Install signal handlers plus schedules the main wrapper
- * around the "run" method.
- *
- * @param cls our `struct MainWrapperContext`
- * @param cfg configuration we use
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
- * times.
- */
-static int
-setup_with_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct MainWrapperContext *mwc = cls;
- struct TALER_TESTING_SetupContext setup_ctx = {
- .config_filename = mwc->config_filename,
- .main_cb = &auditor_main_wrapper,
- .main_cb_cls = mwc
- };
-
- mwc->cfg = cfg;
- return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx,
- cfg);
-}
-
-
-/**
- * Install signal handlers plus schedules the main wrapper
- * around the "run" method.
- *
- * @param main_cb the "run" method which contains all the
- * commands.
- * @param main_cb_cls a closure for "run", typically NULL.
- * @param config_filename configuration filename.
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
- * times.
- */
-int
-TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_filename)
-{
- struct MainWrapperContext mwc = {
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls,
- .config_filename = config_filename
- };
-
- return GNUNET_CONFIGURATION_parse_and_run (config_filename,
- &setup_with_cfg,
- &mwc);
-}
-
-
-/* end of testing_auditor_api_helpers.c */
diff --git a/src/lib/testing_api_helpers_bank.c b/src/lib/testing_api_helpers_bank.c
@@ -1,494 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_helpers_bank.c
- * @brief convenience functions for bank tests.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-
-#define BANK_FAIL() \
- do {GNUNET_break (0); return NULL; } while (0)
-
-
-/**
- * Runs the Fakebank by guessing / extracting the portnumber
- * from the base URL.
- *
- * @param bank_url bank's base URL.
- * @return the fakebank process handle, or NULL if any
- * error occurs.
- */
-struct TALER_FAKEBANK_Handle *
-TALER_TESTING_run_fakebank (const char *bank_url)
-{
- const char *port;
- long pnum;
- struct TALER_FAKEBANK_Handle *fakebankd;
-
- port = strrchr (bank_url,
- (unsigned char) ':');
- if (NULL == port)
- pnum = 80;
- else
- pnum = strtol (port + 1, NULL, 10);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting Fakebank on port %u (%s)\n",
- (unsigned int) pnum,
- bank_url);
- fakebankd = TALER_FAKEBANK_start ((uint16_t) pnum);
- if (NULL == fakebankd)
- {
- GNUNET_break (0);
- return NULL;
- }
- return fakebankd;
-}
-
-
-/**
- * Look for substring in a programs' name.
- *
- * @param prog program's name to look into
- * @param marker chunk to find in @a prog
- * @return #GNUNET_YES if @a marker is present, otherwise #GNUNET_NO
- */
-int
-TALER_TESTING_has_in_name (const char *prog,
- const char *marker)
-{
- size_t name_pos;
- size_t pos;
-
- if (! prog || ! marker)
- return GNUNET_NO;
-
- pos = 0;
- name_pos = 0;
- while (prog[pos])
- {
- if ('/' == prog[pos])
- name_pos = pos + 1;
- pos++;
- }
- if (name_pos == pos)
- return GNUNET_YES;
- return (NULL != strstr (prog + name_pos, marker));
-}
-
-
-/**
- * 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.
- * @param bank_url base URL of the bank, used by `wget' to check
- * that the bank was started right.
- * @return the process, or NULL if the process could not
- * be started.
- */
-struct GNUNET_OS_Process *
-TALER_TESTING_run_bank (const char *config_filename,
- const char *bank_url)
-{
- struct GNUNET_OS_Process *bank_proc;
- unsigned int iter;
- char *wget_cmd;
- char *database;
- char *serve_cfg;
- char *serve_arg;
- struct GNUNET_CONFIGURATION_Handle *cfg;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg,
- config_filename))
- {
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- exit (77);
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "bank",
- "database",
- &database))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "bank",
- "database");
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- exit (77);
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "bank",
- "serve",
- &serve_cfg))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "bank",
- "serve");
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_free (database);
- exit (77);
- }
- GNUNET_CONFIGURATION_destroy (cfg);
-
- serve_arg = "serve-http";
- if (0 != strcmp ("http", serve_cfg))
- serve_arg = "serve-uwsgi";
- GNUNET_free (serve_cfg);
- bank_proc = GNUNET_OS_start_process
- (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-bank-manage-testing",
- "taler-bank-manage-testing",
- config_filename,
- database,
- serve_arg, NULL);
- GNUNET_free (database);
- if (NULL == bank_proc)
- {
- BANK_FAIL ();
- }
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 2 -T 1 %s -o /dev/null -O /dev/null",
- bank_url);
-
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-bank-manage' to be ready (via %s)\n", wget_cmd);
- 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);
- GNUNET_free (wget_cmd);
- BANK_FAIL ();
- }
- fprintf (stderr, ".");
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- fprintf (stderr, "\n");
-
- return bank_proc;
-
-}
-
-
-/**
- * Prepare the bank execution. Check if the port is available
- * and reset database.
- *
- * @param config_filename configuration file name.
- * @param config_section section of the configuration with the exchange's account
- * @param[out] bc set to the bank's configuration data
- * @return the base url, or NULL upon errors. Must be freed
- * by the caller.
- */
-int
-TALER_TESTING_prepare_bank (const char *config_filename,
- const char *config_section,
- struct TALER_TESTING_BankConfiguration *bc)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- unsigned long long port;
- struct GNUNET_OS_Process *dbreset_proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
- char *database;
- char *exchange_payto_uri;
-
- cfg = GNUNET_CONFIGURATION_create ();
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_load (cfg, config_filename))
- {
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "bank",
- "DATABASE",
- &database))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "bank",
- "DATABASE");
- GNUNET_CONFIGURATION_destroy (cfg);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- config_section,
- "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */
- &exchange_payto_uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- config_section,
- "URL");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- 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);
- GNUNET_free (database);
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- fprintf (stderr,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_break (0);
- GNUNET_free (database);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
-
- /* 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", config_filename,
- "--with-db", database,
- "django",
- "flush",
- "--no-input", NULL)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to flush the bank db.\n");
- GNUNET_free (database);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- GNUNET_free (database);
-
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (dbreset_proc,
- &type,
- &code))
- {
- GNUNET_OS_process_destroy (dbreset_proc);
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- fprintf (stderr,
- "Failed to setup database\n");
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error running `taler-bank-manage django flush'!\n");
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_destroy (dbreset_proc);
- if (GNUNET_OK !=
- TALER_BANK_auth_parse_cfg (cfg,
- config_section,
- &bc->exchange_auth))
- {
- GNUNET_break (0);
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- GNUNET_CONFIGURATION_destroy (cfg);
- bc->exchange_payto = exchange_payto_uri;
- bc->user42_payto = "payto://x-taler-bank/localhost/42";
- bc->user43_payto = "payto://x-taler-bank/localhost/43";
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Using pybank %s on port %u\n",
- bc->exchange_auth.wire_gateway_url,
- (unsigned int) port);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n",
- bc->exchange_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user42_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user43_payto);
- return GNUNET_OK;
-}
-
-
-/**
- * Prepare launching a fakebank. Check that the configuration
- * file has the right option, and that the port is available.
- * If everything is OK, return the configuration data of the fakebank.
- *
- * @param config_filename configuration file to use
- * @param config_section which account to use (must match x-taler-bank)
- * @param[out] bc set to the bank's configuration data
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_prepare_fakebank (const char *config_filename,
- const char *config_section,
- struct TALER_TESTING_BankConfiguration *bc)
-{
- struct GNUNET_CONFIGURATION_Handle *cfg;
- unsigned long long fakebank_port;
- char *exchange_payto_uri;
-
- cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg,
- config_filename))
- return GNUNET_SYSERR;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "BANK",
- "HTTP_PORT",
- &fakebank_port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "BANK",
- "HTTP_PORT");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- config_section,
- "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */
- &exchange_payto_uri))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- config_section,
- "URL");
- GNUNET_CONFIGURATION_destroy (cfg);
- return GNUNET_SYSERR;
- }
- bc->exchange_auth.method = TALER_BANK_AUTH_NONE;
- {
- char *exchange_xtalerbank_account;
-
- exchange_xtalerbank_account
- = TALER_xtalerbank_account_from_payto (exchange_payto_uri);
- if (NULL == exchange_xtalerbank_account)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- GNUNET_asprintf (&bc->exchange_auth.wire_gateway_url,
- "http://localhost:%u/%s/",
- (unsigned int) fakebank_port,
- exchange_xtalerbank_account);
- GNUNET_free (exchange_xtalerbank_account);
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Using fakebank %s on port %u\n",
- bc->exchange_auth.wire_gateway_url,
- (unsigned int) fakebank_port);
-
- GNUNET_CONFIGURATION_destroy (cfg);
- if (GNUNET_OK !=
- TALER_TESTING_url_port_free (bc->exchange_auth.wire_gateway_url))
- {
- GNUNET_free (bc->exchange_auth.wire_gateway_url);
- bc->exchange_auth.wire_gateway_url = NULL;
- return GNUNET_SYSERR;
- }
- /* Now we know it's the fake bank, for purpose of authentication, we
- * don't have any auth. */
- bc->exchange_auth.method = TALER_BANK_AUTH_NONE;
- bc->exchange_payto = exchange_payto_uri;
- bc->user42_payto = "payto://x-taler-bank/localhost/42";
- bc->user43_payto = "payto://x-taler-bank/localhost/43";
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n",
- bc->exchange_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user42_payto);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
- bc->user43_payto);
- return GNUNET_OK;
-}
-
-
-/**
- * Allocate and return a piece of wire-details. Combines
- * a @a payto -URL and adds some salt to create the JSON.
- *
- * @param payto payto://-URL to encapsulate
- * @return JSON describing the account, including the
- * payto://-URL of the account, must be manually decref'd
- */
-json_t *
-TALER_TESTING_make_wire_details (const char *payto)
-{
- return json_pack ("{s:s, s:s}",
- "url", payto,
- "salt",
- "test-salt (must be constant for aggregation tests)");
-}
-
-
-/* end of testing_api_helpers_bank.c */
diff --git a/src/lib/testing_api_helpers_exchange.c b/src/lib/testing_api_helpers_exchange.c
@@ -1,976 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_helpers_exchange.c
- * @brief helper functions
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * Remove files from previous runs
- *
- * @param config_name configuration filename.
- */
-void
-TALER_TESTING_cleanup_files (const char *config_name)
-{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_parse_and_run (config_name,
- &TALER_TESTING_cleanup_files_cfg,
- NULL))
- exit (77);
-}
-
-
-/**
- * Remove files from previous runs
- *
- * @param cls NULL
- * @param cfg configuration
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_cleanup_files_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- char *dir;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "exchange",
- "KEYDIR",
- &dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "KEYDIR");
- return GNUNET_SYSERR;
- }
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (dir,
- GNUNET_NO))
- GNUNET_break (GNUNET_OK ==
- GNUNET_DISK_directory_remove (dir));
- GNUNET_free (dir);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "exchange",
- "REVOCATION_DIR",
- &dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "REVOCATION_DIR");
- return GNUNET_SYSERR;
- }
- if (GNUNET_YES ==
- GNUNET_DISK_directory_test (dir,
- GNUNET_NO))
- GNUNET_break (GNUNET_OK ==
- GNUNET_DISK_directory_remove (dir));
- GNUNET_free (dir);
- return GNUNET_OK;
-}
-
-
-/**
- * Run `taler-exchange-keyup`.
- *
- * @param config_filename configuration file to use
- * @param output_filename where to write the output for the auditor
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_run_keyup (const char *config_filename,
- const char *output_filename)
-{
- struct GNUNET_OS_Process *proc;
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-keyup",
- "taler-exchange-keyup",
- "-c", config_filename,
- "-o", output_filename,
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
- return GNUNET_OK;
-}
-
-
-/**
- * Run `taler-auditor-sign`.
- *
- * @param config_filename configuration file to use
- * @param exchange_master_pub master public key of the exchange
- * @param auditor_base_url what is the base URL of the auditor
- * @param signdata_in where is the information from taler-exchange-keyup
- * @param signdata_out where to write the output for the exchange
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_run_auditor_sign (const char *config_filename,
- const char *exchange_master_pub,
- const char *auditor_base_url,
- const char *signdata_in,
- const char *signdata_out)
-{
- struct GNUNET_OS_Process *proc;
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-sign",
- "taler-auditor-sign",
- "-c", config_filename,
- "-u", auditor_base_url,
- "-m", exchange_master_pub,
- "-r", signdata_in,
- "-o", signdata_out,
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-sign`, is your PATH correct?\n");
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_wait (proc);
- GNUNET_OS_process_destroy (proc);
- return GNUNET_OK;
-}
-
-
-/**
- * Run `taler-auditor-exchange`.
- *
- * @param config_filename configuration file to use
- * @param exchange_master_pub master public key of the exchange
- * @param exchange_base_url what is the base URL of the exchange
- * @param do_remove #GNUNET_NO to add exchange, #GNUNET_YES to remove
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_run_auditor_exchange (const char *config_filename,
- const char *exchange_master_pub,
- const char *exchange_base_url,
- int do_remove)
-{
- struct GNUNET_OS_Process *proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n",
- exchange_base_url,
- exchange_master_pub);
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-exchange",
- "taler-auditor-exchange",
- "-c", config_filename,
- "-u", exchange_base_url,
- "-m", exchange_master_pub,
- (GNUNET_YES == do_remove)
- ? "-r"
- : NULL,
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-exchange`, is your PATH correct?\n");
- return GNUNET_SYSERR;
- }
- GNUNET_assert (GNUNET_OK ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code));
- GNUNET_OS_process_destroy (proc);
- if ( (0 != code) ||
- (GNUNET_OS_PROCESS_EXITED != type) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "taler-auditor-exchange terminated with error (%d/%d)\n",
- (int) type,
- (int) code);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Run `taler-exchange-dbinit -r` (reset exchange database).
- *
- * @param config_filename configuration file to use
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_exchange_db_reset (const char *config_filename)
-{
- struct GNUNET_OS_Process *proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-dbinit",
- "taler-exchange-dbinit",
- "-c", config_filename,
- "-r",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n");
- return GNUNET_NO;
- }
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code))
- {
- GNUNET_break (0);
- GNUNET_OS_process_destroy (proc);
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_destroy (proc);
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to setup (exchange) database, exit code %d\n",
- (int) code);
- return GNUNET_NO;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n",
- (int) type,
- (int) code);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Run `taler-auditor-dbinit -r` (reset auditor database).
- *
- * @param config_filename configuration file to use
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_auditor_db_reset (const char *config_filename)
-{
- struct GNUNET_OS_Process *proc;
- enum GNUNET_OS_ProcessStatusType type;
- unsigned long code;
-
- proc = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-dbinit",
- "taler-auditor-dbinit",
- "-c", config_filename,
- "-r",
- NULL);
- if (NULL == proc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n");
- return GNUNET_NO;
- }
- if (GNUNET_SYSERR ==
- GNUNET_OS_process_wait_status (proc,
- &type,
- &code))
- {
- GNUNET_break (0);
- GNUNET_OS_process_destroy (proc);
- return GNUNET_SYSERR;
- }
- GNUNET_OS_process_destroy (proc);
- if ( (type == GNUNET_OS_PROCESS_EXITED) &&
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to setup (auditor) database, exit code %d\n",
- (int) code);
- return GNUNET_NO;
- }
- if ( (type != GNUNET_OS_PROCESS_EXITED) ||
- (0 != code) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n",
- (int) type,
- (int) code);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Type of closure for
- * #sign_keys_for_exchange.
- */
-struct SignInfo
-{
- /**
- * Members will be set to the exchange configuration.
- */
- struct TALER_TESTING_ExchangeConfiguration *ec;
-
- /**
- * Name of the configuration file to use.
- */
- const char *config_filename;
-
- /**
- * Must be set to input file with the data to be signed before
- * calling #TALER_TESTING_sign_keys_for_exchange.
- */
- const char *auditor_sign_input_filename;
-};
-
-
-/**
- * Sign the keys for an exchange given configuration @a cfg.
- * The information to be signed must be in a file "auditor.in".
- *
- * @param[in,out] cls a `struct SignInfo` with further paramters
- * @param cfg configuration to use
- * @return #GNUNET_OK on success
- */
-static int
-sign_keys_for_exchange (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct SignInfo *si = cls;
- char *test_home_dir;
- char *signed_keys_out;
- char *exchange_master_pub;
- int ret;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "BASE_URL",
- &si->ec->exchange_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "exchange",
- "BASE_URL");
- si->ec->exchange_url = NULL;
- return GNUNET_NO;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "auditor",
- "BASE_URL",
- &si->ec->auditor_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "auditor",
- "BASE_URL");
- GNUNET_free (si->ec->exchange_url);
- si->ec->exchange_url = NULL;
- si->ec->auditor_url = NULL;
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- "paths",
- "TALER_TEST_HOME",
- &test_home_dir))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "paths",
- "TALER_TEST_HOME");
- ret = GNUNET_SYSERR;
- goto fail;
- }
-
- GNUNET_asprintf (&signed_keys_out,
- "%s/.local/share/taler/auditors/auditor.out",
- test_home_dir);
- GNUNET_free (test_home_dir);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "MASTER_PUBLIC_KEY",
- &exchange_master_pub))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "MASTER_PUBLIC_KEY");
- GNUNET_free (signed_keys_out);
- ret = GNUNET_SYSERR;
- goto fail;
- }
- if (GNUNET_OK !=
- TALER_TESTING_run_auditor_exchange (si->config_filename,
- exchange_master_pub,
- si->ec->exchange_url,
- GNUNET_NO))
- {
- GNUNET_free (signed_keys_out);
- ret = GNUNET_NO;
- goto fail;
- }
-
- if (GNUNET_OK !=
- TALER_TESTING_run_auditor_sign (si->config_filename,
- exchange_master_pub,
- si->ec->auditor_url,
- si->auditor_sign_input_filename,
- signed_keys_out))
- {
- GNUNET_free (signed_keys_out);
- GNUNET_free (exchange_master_pub);
- ret = GNUNET_NO;
- goto fail;
- }
- GNUNET_free (signed_keys_out);
- GNUNET_free (exchange_master_pub);
- return GNUNET_OK;
-fail:
- GNUNET_free (si->ec->exchange_url);
- GNUNET_free (si->ec->auditor_url);
- si->ec->exchange_url = NULL;
- si->ec->auditor_url = NULL;
- return ret;
-}
-
-
-/**
- * Prepare launching an exchange. Checks that the configured
- * port is available, runs taler-exchange-keyup,
- * taler-auditor-sign and taler-exchange-dbinit. Does NOT
- * launch the exchange process itself.
- *
- * @param config_filename configuration file to use
- * @param[out] ec will be set to the exchange configuration data
- * @return #GNUNET_OK on success, #GNUNET_NO if test should be
- * skipped, #GNUNET_SYSERR on test failure
- */
-int
-TALER_TESTING_prepare_exchange (const char *config_filename,
- struct TALER_TESTING_ExchangeConfiguration *ec)
-{
- struct SignInfo si = {
- .config_filename = config_filename,
- .ec = ec,
- .auditor_sign_input_filename = "auditor.in"
- };
-
- if (GNUNET_OK !=
- TALER_TESTING_run_keyup (config_filename,
- si.auditor_sign_input_filename))
- return GNUNET_NO;
- if (GNUNET_OK !=
- TALER_TESTING_exchange_db_reset (config_filename))
- return GNUNET_NO;
- if (GNUNET_OK !=
- TALER_TESTING_auditor_db_reset (config_filename))
- return GNUNET_NO;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_parse_and_run (config_filename,
- &sign_keys_for_exchange,
- &si))
- return GNUNET_NO;
- return GNUNET_OK;
-}
-
-
-/**
- * Find denomination key matching the given amount.
- *
- * @param keys array of keys to search
- * @param amount coin value to look for
- * @return NULL if no matching key was found
- */
-const struct TALER_EXCHANGE_DenomPublicKey *
-TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
- const struct TALER_Amount *amount)
-{
- struct GNUNET_TIME_Absolute now;
- struct TALER_EXCHANGE_DenomPublicKey *pk;
- char *str;
-
- now = GNUNET_TIME_absolute_get ();
- for (unsigned int i = 0; i<keys->num_denom_keys; i++)
- {
- pk = &keys->denom_keys[i];
- if ( (0 == TALER_amount_cmp (amount,
- &pk->value)) &&
- (now.abs_value_us >= pk->valid_from.abs_value_us) &&
- (now.abs_value_us <
- pk->withdraw_valid_until.abs_value_us) )
- return pk;
- }
- /* do 2nd pass to check if expiration times are to blame for
- * failure */
- str = TALER_amount_to_string (amount);
- for (unsigned int i = 0; i<keys->num_denom_keys; i++)
- {
- pk = &keys->denom_keys[i];
- if ( (0 == TALER_amount_cmp (amount,
- &pk->value)) &&
- ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
- (now.abs_value_us >
- pk->withdraw_valid_until.abs_value_us) ) )
- {
- GNUNET_log
- (GNUNET_ERROR_TYPE_WARNING,
- "Have denomination key for `%s', but with wrong"
- " expiration range %llu vs [%llu,%llu)\n",
- str,
- (unsigned long long) now.abs_value_us,
- (unsigned long long) pk->valid_from.abs_value_us,
- (unsigned long long)
- pk->withdraw_valid_until.abs_value_us);
- GNUNET_free (str);
- return NULL;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "No denomination key for amount %s found\n",
- str);
- GNUNET_free (str);
- return NULL;
-}
-
-
-/**
- * Wait for the exchange to have started. Waits for at
- * most 10s, after that returns 77 to indicate an error.
- *
- * @param base_url what URL should we expect the exchange
- * to be running at
- * @return 0 on success
- */
-int
-TALER_TESTING_wait_exchange_ready (const char *base_url)
-{
- char *wget_cmd;
- unsigned int iter;
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 1 -T 1 %skeys -o /dev/null -O /dev/null",
- base_url); // make sure ends with '/'
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-exchange-httpd' to be ready (check with: %s)\n",
- wget_cmd);
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (stderr,
- "Failed to launch `taler-exchange-httpd' (or `wget')\n");
- GNUNET_free (wget_cmd);
- return 77;
- }
- fprintf (stderr, ".\n");
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- return 0;
-}
-
-
-/**
- * Wait for the auditor to have started. Waits for at
- * most 10s, after that returns 77 to indicate an error.
- *
- * @param base_url what URL should we expect the auditor
- * to be running at
- * @return 0 on success
- */
-int
-TALER_TESTING_wait_auditor_ready (const char *base_url)
-{
- char *wget_cmd;
- unsigned int iter;
-
- GNUNET_asprintf (&wget_cmd,
- "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null",
- base_url); // make sure ends with '/'
- /* give child time to start and bind against the socket */
- fprintf (stderr,
- "Waiting for `taler-auditor-httpd' to be ready\n");
- iter = 0;
- do
- {
- if (10 == iter)
- {
- fprintf (stderr,
- "Failed to launch `taler-auditor-httpd' (or `wget')\n");
- GNUNET_free (wget_cmd);
- return 77;
- }
- fprintf (stderr, ".\n");
- sleep (1);
- iter++;
- }
- while (0 != system (wget_cmd));
- GNUNET_free (wget_cmd);
- return 0;
-}
-
-
-/**
- * Initialize scheduler loop and curl context for the testcase
- * including starting and stopping the exchange using the given
- * configuration file.
- *
- * @param main_cb routine containing all the commands to run.
- * @param main_cb_cls closure for @a main_cb, typically NULL.
- * @param config_file configuration file for the test-suite.
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-#GNUNET_OK codes are #GNUNET_SYSERR most of the
- * time.
- */
-int
-TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_file)
-{
- struct TALER_TESTING_SetupContext setup_ctx = {
- .config_filename = config_file,
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls
- };
- int result;
-
- result =
- GNUNET_CONFIGURATION_parse_and_run (config_file,
- &TALER_TESTING_setup_with_exchange_cfg,
- &setup_ctx);
- if (GNUNET_OK != result)
- return result;
- return GNUNET_OK;
-}
-
-
-/**
- * Initialize scheduler loop and curl context for the test case
- * including starting and stopping the exchange using the given
- * configuration file.
- *
- * @param cls must be a `struct TALER_TESTING_SetupContext *`
- * @param cfg configuration to use.
- * @return #GNUNET_OK if no errors occurred.
- */
-int
-TALER_TESTING_setup_with_exchange_cfg (void *cls,
- const struct
- GNUNET_CONFIGURATION_Handle *cfg)
-{
- const struct TALER_TESTING_SetupContext *setup_ctx = cls;
- struct GNUNET_OS_Process *exchanged;
- unsigned long long port;
- char *serve;
- char *base_url;
- int result;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "SERVE",
- &serve))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "SERVE");
- return GNUNET_NO;
- }
-
- if (0 == strcmp ("tcp", serve))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "exchange",
- "PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "PORT");
- GNUNET_free (serve);
- return GNUNET_NO;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_free (serve);
- return GNUNET_NO;
- }
- }
- GNUNET_free (serve);
- exchanged = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-exchange-httpd",
- "taler-exchange-httpd",
- "-c", setup_ctx->config_filename,
- "-i",
- NULL);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "BASE_URL",
- &base_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "BASE_URL");
- return GNUNET_NO;
- }
-
- if (0 != TALER_TESTING_wait_exchange_ready (base_url))
- {
- GNUNET_free (base_url);
- return 77;
- }
- GNUNET_free (base_url);
-
- /* NOTE: this call blocks. */
- result = TALER_TESTING_setup (setup_ctx->main_cb,
- setup_ctx->main_cb_cls,
- setup_ctx->config_filename,
- exchanged,
- GNUNET_YES);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (exchanged,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (exchanged));
- GNUNET_OS_process_destroy (exchanged);
- return result;
-}
-
-
-/**
- * Initialize scheduler loop and curl context for the test case
- * including starting and stopping the auditor and exchange using the
- * given configuration file.
- *
- * @param cls must be a `struct TALER_TESTING_SetupContext *`
- * @param cfg configuration to use.
- * @return #GNUNET_OK if no errors occurred.
- */
-int
-TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls,
- const struct
- GNUNET_CONFIGURATION_Handle *
- cfg)
-{
- const struct TALER_TESTING_SetupContext *setup_ctx = cls;
- struct GNUNET_OS_Process *auditord;
- unsigned long long port;
- char *serve;
- char *base_url;
- int result;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "auditor",
- "SERVE",
- &serve))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "SERVE");
- return GNUNET_NO;
- }
-
- if (0 == strcmp ("tcp", serve))
- {
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "auditor",
- "PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "PORT");
- GNUNET_free (serve);
- return GNUNET_NO;
- }
-
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- (uint16_t) port))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Required port %llu not available, skipping.\n",
- port);
- GNUNET_free (serve);
- return GNUNET_NO;
- }
- }
- GNUNET_free (serve);
- auditord = GNUNET_OS_start_process (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_ALL,
- NULL, NULL, NULL,
- "taler-auditor-httpd",
- "taler-auditor-httpd",
- "-c", setup_ctx->config_filename,
- NULL);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "auditor",
- "BASE_URL",
- &base_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "auditor",
- "BASE_URL");
- return GNUNET_NO;
- }
-
- if (0 != TALER_TESTING_wait_auditor_ready (base_url))
- {
- GNUNET_free (base_url);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (auditord,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (auditord));
- GNUNET_OS_process_destroy (auditord);
- return 77;
- }
- GNUNET_free (base_url);
-
- /* NOTE: this call blocks. */
- result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx,
- cfg);
- GNUNET_break (0 ==
- GNUNET_OS_process_kill (auditord,
- SIGTERM));
- GNUNET_break (GNUNET_OK ==
- GNUNET_OS_process_wait (auditord));
- GNUNET_OS_process_destroy (auditord);
- return result;
-}
-
-
-/**
- * Initialize scheduler loop and curl context for the test case
- * including starting and stopping the auditor and exchange using the
- * given configuration file.
- *
- * @param main_cb main method.
- * @param main_cb_cls main method closure.
- * @param config_file configuration file name. Is is used
- * by both this function and the exchange itself. In the
- * first case it gives out the exchange port number and
- * the exchange base URL so as to check whether the port
- * is available and the exchange responds when requested
- * at its base URL.
- * @return #GNUNET_OK if no errors occurred.
- */
-int
-TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_file)
-{
- struct TALER_TESTING_SetupContext setup_ctx = {
- .config_filename = config_file,
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls
- };
-
- return GNUNET_CONFIGURATION_parse_and_run (config_file,
- &
- TALER_TESTING_setup_with_auditor_and_exchange_cfg,
- &setup_ctx);
-}
-
-
-/**
- * Test port in URL string for availability.
- *
- * @param url URL to extract port from, 80 is default
- * @return #GNUNET_OK if the port is free
- */
-int
-TALER_TESTING_url_port_free (const char *url)
-{
- const char *port;
- long pnum;
-
- port = strrchr (url,
- (unsigned char) ':');
- if (NULL == port)
- pnum = 80;
- else
- pnum = strtol (port + 1, NULL, 10);
- if (GNUNET_OK !=
- GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
- pnum))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Port %u not available.\n",
- (unsigned int) pnum);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/* end of testing_api_helpers_exchange.c */
diff --git a/src/lib/testing_api_loop.c b/src/lib/testing_api_loop.c
@@ -1,829 +0,0 @@
-/*
- 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 lib/testing_api_loop.c
- * @brief main interpreter loop for testcases
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-#include "taler_fakebank_lib.h"
-
-/**
- * Pipe used to communicate child death via signal.
- * Must be global, as used in signal handler!
- */
-static struct GNUNET_DISK_PipeHandle *sigpipe;
-
-/**
- * Lookup command by label.
- *
- * @param is interpreter state to search
- * @param label label to look for
- * @return NULL if command was not found
- */
-const struct TALER_TESTING_Command *
-TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
- const char *label)
-{
- if (NULL == label)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Attempt to lookup command for empty label\n");
- return NULL;
- }
- /* Search backwards as we most likely reference recent commands */
- for (int i = is->ip; i >= 0; i--)
- {
- const struct TALER_TESTING_Command *cmd = &is->commands[i];
-
- /* Give precedence to top-level commands. */
- if ( (NULL != cmd->label) &&
- (0 == strcmp (cmd->label,
- label)) )
- return cmd;
-
- if (TALER_TESTING_cmd_is_batch (cmd))
- {
-#define BATCH_INDEX 1
- struct TALER_TESTING_Command *batch;
-
- GNUNET_assert (GNUNET_OK ==
- TALER_TESTING_get_trait_cmd (cmd,
- BATCH_INDEX,
- &batch));
- for (unsigned int j = 0;
- NULL != (cmd = &batch[j])->label;
- j++)
- {
- if ( (NULL != cmd->label) &&
- (0 == strcmp (cmd->label,
- label)) )
- return cmd;
- }
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Command not found: %s\n",
- label);
- return NULL;
-
-}
-
-
-/**
- * Obtain main execution context for the main loop.
- */
-struct GNUNET_CURL_Context *
-TALER_TESTING_interpreter_get_context
- (struct TALER_TESTING_Interpreter *is)
-{
- return is->ctx;
-}
-
-
-struct TALER_FAKEBANK_Handle *
-TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is)
-{
- return is->fakebank;
-}
-
-
-/**
- * Run tests starting the "fakebank" first. The "fakebank"
- * is a C minimalist version of the human-oriented Python bank,
- * which is also part of the Taler project.
- *
- * @param is pointer to the interpreter state
- * @param commands the list of commands to execute
- * @param bank_url the url the fakebank is supposed to run on
- */
-void
-TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
- struct TALER_TESTING_Command *commands,
- const char *bank_url)
-{
- const char *port;
- long pnum;
-
- port = strrchr (bank_url,
- (unsigned char) ':');
- if (NULL == port)
- pnum = 80;
- else
- pnum = strtol (port + 1, NULL, 10);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Starting Fakebank on port %u (%s)\n",
- (unsigned int) pnum,
- bank_url);
- is->fakebank = TALER_FAKEBANK_start ((uint16_t) pnum);
- if (NULL == is->fakebank)
- {
- GNUNET_break (0);
- is->result = GNUNET_SYSERR;
- return;
- }
- TALER_TESTING_run (is,
- commands);
-}
-
-
-/**
- * Run the main interpreter loop that performs exchange operations.
- *
- * @param cls contains the `struct InterpreterState`
- */
-static void
-interpreter_run (void *cls);
-
-
-/**
- * Current command is done, run the next one.
- */
-void
-TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
-{
- static unsigned long long ipc;
- static struct GNUNET_TIME_Absolute last_report;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
-
- if (GNUNET_SYSERR == is->result)
- return; /* ignore, we already failled! */
- if (TALER_TESTING_cmd_is_batch (cmd))
- TALER_TESTING_cmd_batch_next (is);
- else
- is->ip++;
- if (0 == (ipc % 1000))
- {
- if (0 != ipc)
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "Interpreter executed 1000 instructions in %s\n",
- GNUNET_STRINGS_relative_time_to_string (
- GNUNET_TIME_absolute_get_duration (last_report),
- GNUNET_YES));
- last_report = GNUNET_TIME_absolute_get ();
- }
- ipc++;
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
- is);
-}
-
-
-/**
- * Current command failed, clean up and fail the test case.
- *
- * @param is interpreter of the test
- */
-void
-TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
-
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed at command `%s'\n",
- cmd->label);
- while (TALER_TESTING_cmd_is_batch (cmd))
- {
- cmd = TALER_TESTING_cmd_batch_get_current (cmd);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Batch is at command `%s'\n",
- cmd->label);
- }
- is->result = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Create command array terminator.
- *
- * @return a end-command.
- */
-struct TALER_TESTING_Command
-TALER_TESTING_cmd_end (void)
-{
- static struct TALER_TESTING_Command cmd;
- cmd.label = NULL;
-
- return cmd;
-}
-
-
-/**
- * Obtain current label.
- */
-const char *
-TALER_TESTING_interpreter_get_current_label (struct
- TALER_TESTING_Interpreter *is)
-{
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
-
- return cmd->label;
-}
-
-
-/**
- * Run the main interpreter loop that performs exchange operations.
- *
- * @param cls contains the `struct TALER_TESTING_Interpreter`
- */
-static void
-interpreter_run (void *cls)
-{
- struct TALER_TESTING_Interpreter *is = cls;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
-
- is->task = NULL;
-
- if (NULL == cmd->label)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Running command END\n");
- is->result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Running command `%s'\n",
- cmd->label);
-
- cmd->run (cmd->cls,
- cmd,
- is);
-}
-
-
-/**
- * Function run when the test terminates (good or bad).
- * Cleans up our state.
- *
- * @param cls the interpreter state.
- */
-static void
-do_shutdown (void *cls)
-{
- struct TALER_TESTING_Interpreter *is = cls;
- struct TALER_TESTING_Command *cmd;
- const char *label;
-
- label = is->commands[is->ip].label;
- if (NULL == label)
- label = "END";
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Executing shutdown at `%s'\n",
- label);
-
- for (unsigned int j = 0;
- NULL != (cmd = &is->commands[j])->label;
- j++)
- cmd->cleanup (cmd->cls,
- cmd);
-
- if (NULL != is->exchange)
- {
- TALER_LOG_DEBUG ("Disconnecting the exchange\n");
- TALER_EXCHANGE_disconnect (is->exchange);
- is->exchange = NULL;
- }
- if (NULL != is->task)
- {
- GNUNET_SCHEDULER_cancel (is->task);
- is->task = NULL;
- }
- if (NULL != is->ctx)
- {
- GNUNET_CURL_fini (is->ctx);
- is->ctx = NULL;
- }
- if (NULL != is->rc)
- {
- GNUNET_CURL_gnunet_rc_destroy (is->rc);
- is->rc = NULL;
- }
- if (NULL != is->timeout_task)
- {
- GNUNET_SCHEDULER_cancel (is->timeout_task);
- is->timeout_task = NULL;
- }
- if (NULL != is->child_death_task)
- {
- GNUNET_SCHEDULER_cancel (is->child_death_task);
- is->child_death_task = NULL;
- }
- if (NULL != is->fakebank)
- {
- TALER_FAKEBANK_stop (is->fakebank);
- is->fakebank = NULL;
- }
- GNUNET_free_non_null (is->commands);
-}
-
-
-/**
- * Function run when the test terminates (good or bad) with timeout.
- *
- * @param cls NULL
- */
-static void
-do_timeout (void *cls)
-{
- struct TALER_TESTING_Interpreter *is = cls;
-
- is->timeout_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Terminating test due to timeout\n");
- GNUNET_SCHEDULER_shutdown ();
-}
-
-
-/**
- * Task triggered whenever we receive a SIGCHLD (child
- * process died).
- *
- * @param cls closure
- */
-static void
-maint_child_death (void *cls)
-{
- struct TALER_TESTING_Interpreter *is = cls;
- struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
- const struct GNUNET_DISK_FileHandle *pr;
-
- struct GNUNET_OS_Process **processp;
- char c[16];
-
- if (TALER_TESTING_cmd_is_batch (cmd))
- {
- struct TALER_TESTING_Command *batch_cmd;
-
- GNUNET_assert
- (GNUNET_OK == TALER_TESTING_get_trait_cmd
- (cmd, 0, &batch_cmd)); /* bad? */
- cmd = batch_cmd;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got SIGCHLD for `%s'.\n",
- cmd->label);
-
- is->child_death_task = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- GNUNET_break (0 <
- GNUNET_DISK_file_read (pr,
- &c,
- sizeof (c)));
- if (GNUNET_OK !=
- TALER_TESTING_get_trait_process (cmd,
- 0,
- &processp))
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got the dead child process handle"
- ", waiting for termination ...\n");
-
- GNUNET_OS_process_wait (*processp);
- GNUNET_OS_process_destroy (*processp);
- *processp = NULL;
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "... definitively terminated\n");
-
- if (GNUNET_OK == is->reload_keys)
- {
- if (NULL == is->exchanged)
- {
- GNUNET_break (0);
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Triggering key state reload at exchange\n");
- GNUNET_break (0 == GNUNET_OS_process_kill
- (is->exchanged, SIGUSR1));
- sleep (5); /* make sure signal was received and processed */
- }
- }
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Dead child, go on with next command.\n");
- TALER_TESTING_interpreter_next (is);
-}
-
-
-/**
- * Wait until we receive SIGCHLD signal.
- * Then obtain the process trait of the current
- * command, wait on the the zombie and continue
- * with the next command.
- */
-void
-TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
-{
- const struct GNUNET_DISK_FileHandle *pr;
-
- GNUNET_assert (NULL == is->child_death_task);
- pr = GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_READ);
- is->child_death_task
- = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr,
- &maint_child_death,
- is);
-}
-
-
-/**
- * Run the testsuite. Note, CMDs are copied into
- * the interpreter state because they are _usually_
- * defined into the "run" method that returns after
- * having scheduled the test interpreter.
- *
- * @param is the interpreter state
- * @param commands the list of command to execute
- * @param timeout how long to wait
- */
-void
-TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
- struct TALER_TESTING_Command *commands,
- struct GNUNET_TIME_Relative timeout)
-{
- unsigned int i;
-
- if (NULL != is->timeout_task)
- {
- GNUNET_SCHEDULER_cancel (is->timeout_task);
- is->timeout_task = NULL;
- }
- /* get the number of commands */
- for (i = 0; NULL != commands[i].label; i++)
- ;
- is->commands = GNUNET_new_array (i + 1,
- struct TALER_TESTING_Command);
- memcpy (is->commands,
- commands,
- sizeof (struct TALER_TESTING_Command) * i);
- is->timeout_task = GNUNET_SCHEDULER_add_delayed
- (timeout,
- &do_timeout,
- is);
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
- is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is);
-}
-
-
-/**
- * Run the testsuite. Note, CMDs are copied into
- * the interpreter state because they are _usually_
- * defined into the "run" method that returns after
- * having scheduled the test interpreter.
- *
- * @param is the interpreter state
- * @param commands the list of command to execute
- */
-void
-TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
- struct TALER_TESTING_Command *commands)
-{
- TALER_TESTING_run2 (is,
- commands,
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
- 5));
-}
-
-
-/**
- * Information used by the wrapper around the main
- * "run" method.
- */
-struct MainContext
-{
- /**
- * Main "run" method.
- */
- TALER_TESTING_Main main_cb;
-
- /**
- * Closure for @e main_cb.
- */
- void *main_cb_cls;
-
- /**
- * Interpreter state.
- */
- struct TALER_TESTING_Interpreter *is;
-
- /**
- * Configuration filename. The wrapper uses it to fetch
- * the exchange port number; We could have passed the port
- * number here, but having the config filename seems more
- * generic.
- */
- const char *config_filename;
-
- /**
- * URL of the exchange.
- */
- char *exchange_url;
-
-};
-
-
-/**
- * Signal handler called for SIGCHLD. Triggers the
- * respective handler by writing to the trigger pipe.
- */
-static void
-sighandler_child_death ()
-{
- static char c;
- int old_errno = errno; /* back-up errno */
-
- GNUNET_break (1 == GNUNET_DISK_file_write
- (GNUNET_DISK_pipe_handle (sigpipe,
- GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno; /* restore errno */
-}
-
-
-/**
- * "Canonical" cert_cb used when we are connecting to the
- * Exchange.
- *
- * @param cls closure, typically, the "run" method containing
- * all the commands to be run, and a closure for it.
- * @param keys the exchange's keys.
- * @param compat protocol compatibility information.
- */
-void
-TALER_TESTING_cert_cb (void *cls,
- const struct TALER_EXCHANGE_Keys *keys,
- enum TALER_EXCHANGE_VersionCompatibility compat)
-{
- struct MainContext *main_ctx = cls;
- struct TALER_TESTING_Interpreter *is = main_ctx->is;
-
- if (NULL == keys)
- {
- if (GNUNET_NO == is->working)
- {
- GNUNET_log
- (GNUNET_ERROR_TYPE_WARNING,
- "Got NULL response for /keys"
- " during startup, retrying!\n");
- TALER_EXCHANGE_disconnect (is->exchange);
- GNUNET_assert
- (NULL != (is->exchange = TALER_EXCHANGE_connect
- (is->ctx,
- main_ctx->exchange_url,
- &TALER_TESTING_cert_cb,
- main_ctx,
- TALER_EXCHANGE_OPTION_END)));
- return;
- }
- else
- GNUNET_log
- (GNUNET_ERROR_TYPE_ERROR,
- "Got NULL response for /keys"
- " during execution!\n");
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got %d DK from /keys in generation %u\n",
- keys->num_denom_keys,
- is->key_generation + 1);
- }
- is->key_generation++;
- is->keys = keys;
-
- /* /keys has been called for some reason and
- * the interpreter is already running. */
- if (GNUNET_YES == is->working)
- return;
-
- is->working = GNUNET_YES;
-
- /* Very first start of tests, call "run()" */
- if (1 == is->key_generation)
- {
- main_ctx->main_cb (main_ctx->main_cb_cls,
- is);
- return;
- }
-
- /* Tests already started, just trigger the
- * next command. */
- TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
- is->ip);
- GNUNET_SCHEDULER_add_now (&interpreter_run,
- 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);
-}
-
-
-/**
- * Function run when the test is aborted before we launch the actual
- * interpreter. Cleans up our state.
- *
- * @param cls the main context
- */
-static void
-do_abort (void *cls)
-{
- struct MainContext *main_ctx = cls;
- struct TALER_TESTING_Interpreter *is = main_ctx->is;
-
- is->timeout_task = NULL;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Executing abort prior to interpreter launch\n");
- if (NULL != is->exchange)
- {
- TALER_EXCHANGE_disconnect (is->exchange);
- is->exchange = NULL;
- }
-}
-
-
-/**
- * Initialize scheduler loop and curl context for the testcase,
- * and responsible to run the "run" method.
- *
- * @param cls a `struct MainContext *`
- * @param cfg configuration to use
- */
-static int
-main_exchange_connect_with_cfg (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg)
-{
- struct MainContext *main_ctx = cls;
- struct TALER_TESTING_Interpreter *is = main_ctx->is;
- char *exchange_url;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange",
- "BASE_URL",
- &exchange_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange",
- "BASE_URL");
- return GNUNET_SYSERR;
- }
- main_ctx->exchange_url = exchange_url;
- is->cfg = cfg;
- is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
- main_ctx);
- GNUNET_break
- (NULL != (is->exchange = TALER_EXCHANGE_connect
- (is->ctx,
- exchange_url,
- &TALER_TESTING_cert_cb,
- main_ctx,
- TALER_EXCHANGE_OPTION_END)));
- is->cfg = NULL;
- return GNUNET_OK;
-}
-
-
-/**
- * Initialize scheduler loop and curl context for the testcase,
- * and responsible to run the "run" method.
- *
- * @param cls a `struct MainContext *`
- */
-static void
-main_wrapper_exchange_connect (void *cls)
-{
- struct MainContext *main_ctx = cls;
-
- GNUNET_break (GNUNET_OK ==
- GNUNET_CONFIGURATION_parse_and_run (main_ctx->config_filename,
- &
- main_exchange_connect_with_cfg,
- main_ctx));
-}
-
-
-/**
- * Install signal handlers plus schedules the main wrapper
- * around the "run" method.
- *
- * @param main_cb the "run" method which contains all the
- * commands.
- * @param main_cb_cls a closure for "run", typically NULL.
- * @param config_filename configuration filename.
- * @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.. if NULL, the interpreter will run without
- * trying to connect to the exchange first.
- * @param exchange_connect #GNUNET_YES if the test should connect
- * to the exchange, #GNUNET_NO otherwise
- * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
- * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
- * times.
- */
-int
-TALER_TESTING_setup (TALER_TESTING_Main main_cb,
- void *main_cb_cls,
- const char *config_filename,
- struct GNUNET_OS_Process *exchanged,
- int exchange_connect)
-{
- struct TALER_TESTING_Interpreter is;
- struct MainContext main_ctx = {
- .main_cb = main_cb,
- .main_cb_cls = main_cb_cls,
- /* needed to init the curl ctx */
- .is = &is,
- /* needed to read values like exchange port
- * number to construct the exchange url.*/
- .config_filename = config_filename
- };
- struct GNUNET_SIGNAL_Context *shc_chld;
-
- memset (&is,
- 0,
- sizeof (is));
- is.exchanged = exchanged;
- sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
- GNUNET_NO, GNUNET_NO);
- 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_CURL_enable_async_scope_header (is.ctx, "Taler-Correlation-Id");
- GNUNET_assert (NULL != is.ctx);
- is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
-
- /* Blocking */
-
- if (GNUNET_YES == exchange_connect)
- GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
- &main_ctx);
- else
- GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
- &main_ctx);
- if (NULL != is.final_cleanup_cb)
- is.final_cleanup_cb (is.final_cleanup_cb_cls);
- GNUNET_free_non_null (main_ctx.exchange_url);
- GNUNET_SIGNAL_handler_uninstall (shc_chld);
- GNUNET_DISK_pipe_close (sigpipe);
- sigpipe = NULL;
- return is.result;
-}
-
-
-/* end of testing_api_loop.c */
diff --git a/src/lib/testing_api_trait_amount.c b/src/lib/testing_api_trait_amount.c
@@ -1,77 +0,0 @@
-/*
- 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 lib/testing_api_trait_amount.c
- * @brief offer amounts as traits.
- * @author Marcello Stanisci
- */
-
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_AMOUNT "amount"
-
-/**
- * Obtain an amount from a @a cmd.
- *
- * @param cmd command to extract the amount from.
- * @param index which amount to pick if @a cmd has multiple
- * on offer
- * @param[out] amount set to the amount.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_amount_obj (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_Amount **amount)
-{
- return cmd->traits (cmd->cls,
- (const void **) amount,
- TALER_TESTING_TRAIT_AMOUNT,
- index);
-}
-
-
-/**
- * Offer amount.
- *
- * @param index which amount to offer, in case there are
- * multiple available.
- * @param amount the amount to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_amount_obj (unsigned int index,
- const struct TALER_Amount *amount)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_AMOUNT,
- .ptr = (const void *) amount
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_amount.c */
diff --git a/src/lib/testing_api_trait_blinding_key.c b/src/lib/testing_api_trait_blinding_key.c
@@ -1,78 +0,0 @@
-/*
- 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 lib/testing_api_trait_blinding_key.c
- * @brief offer blinding keys as traits.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_BLINDING_KEY "blinding-key"
-
-
-/**
- * Obtain a blinding key from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which coin to pick if @a cmd has multiple on offer.
- * @param[out] blinding_key set to the offered blinding key.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_blinding_key
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_DenominationBlindingKeyP **blinding_key)
-{
- return cmd->traits (cmd->cls,
- (const void **) blinding_key,
- TALER_TESTING_TRAIT_BLINDING_KEY,
- index);
-}
-
-
-/**
- * Offer blinding key.
- *
- * @param index index number to associate to the offered key.
- * @param blinding_key blinding key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_blinding_key
- (unsigned int index,
- const struct TALER_DenominationBlindingKeyP *blinding_key)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_BLINDING_KEY,
- .ptr = (const void *) blinding_key
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_blinding_key.c */
diff --git a/src/lib/testing_api_trait_cmd.c b/src/lib/testing_api_trait_cmd.c
@@ -1,81 +0,0 @@
-/*
- 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 lib/testing_api_trait_cmd.c
- * @brief offers CMDs as traits.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_CMD "cmd"
-
-
-/**
- * Obtain a command from @a cmd.
- *
- * @param cmd command to extract the command from.
- * @param index always zero. Commands offering this
- * kind of traits do not need this index. For
- * example, a "batch" CMD returns always the
- * CMD currently being executed.
- * @param[out] _cmd where to write the wire details.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_cmd (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- struct TALER_TESTING_Command **_cmd)
-{
- return cmd->traits (cmd->cls,
- (const void **) _cmd,
- TALER_TESTING_TRAIT_CMD,
- index);
-}
-
-
-/**
- * Offer a command in a trait.
- *
- * @param index always zero. Commands offering this
- * kind of traits do not need this index. For
- * example, a "meta" CMD returns always the
- * CMD currently being executed.
- * @param cmd wire details to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_cmd (unsigned int index,
- const struct TALER_TESTING_Command *cmd)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_CMD,
- .ptr = (const struct TALER_TESTING_Command *) cmd
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_cmd.c */
diff --git a/src/lib/testing_api_trait_coin_priv.c b/src/lib/testing_api_trait_coin_priv.c
@@ -1,79 +0,0 @@
-/*
- 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 lib/testing_api_trait_coin_priv.c
- * @brief coin priv traits.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_COIN_PRIVATE_KEY "coin-private-key"
-
-
-/**
- * Obtain a coin private key from a @a cmd.
- *
- * @param cmd command to extract trait from.
- * @param index index of the coin priv to obtain.
- * @param[out] coin_priv set to the private key of the coin.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_coin_priv
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_CoinSpendPrivateKeyP **coin_priv)
-{
- return cmd->traits (cmd->cls,
- (const void **) coin_priv,
- TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
- index);
-}
-
-
-/**
- * Offer coin private key.
- *
- * @param index index number to associate with offered coin priv.
- * @param coin_priv coin private key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_coin_priv
- (unsigned int index,
- const struct TALER_CoinSpendPrivateKeyP *coin_priv)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
- .ptr = (const void *) coin_priv
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_coin_priv.c */
diff --git a/src/lib/testing_api_trait_contract.c b/src/lib/testing_api_trait_contract.c
@@ -1,74 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_trait_contract.c
- * @brief offers contract term trait.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "taler_testing_lib.h"
-
-
-/**
- * Contains a contract terms object as a json_t.
- */
-#define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms"
-
-
-/**
- * Obtain contract terms from @a cmd.
- *
- * @param cmd command to extract the contract terms from.
- * @param index contract terms index number.
- * @param[out] contract_terms where to write the contract terms.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_contract_terms (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **contract_terms)
-{
- return cmd->traits (cmd->cls,
- (const void **) contract_terms,
- TALER_TESTING_TRAIT_CONTRACT_TERMS,
- index);
-}
-
-
-/**
- * Offer contract terms.
- *
- * @param index contract terms index number.
- * @param contract_terms contract terms to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_contract_terms (unsigned int index,
- const json_t *contract_terms)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_CONTRACT_TERMS,
- .ptr = (const void *) contract_terms
- };
- return ret;
-}
diff --git a/src/lib/testing_api_trait_denom_pub.c b/src/lib/testing_api_trait_denom_pub.c
@@ -1,78 +0,0 @@
-/*
- 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 lib/testing_api_trait_denom_pub.c
- * @brief denom pub traits.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_DENOM_PUB "denomination-public-key"
-
-
-/**
- * Obtain a denomination public key from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index index number of the denom to obtain.
- * @param[out] denom_pub set to the offered denom pub.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_denom_pub (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct
- TALER_EXCHANGE_DenomPublicKey **denom_pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) denom_pub,
- TALER_TESTING_TRAIT_DENOM_PUB,
- index);
-}
-
-
-/**
- * Make a trait for a denomination public key.
- *
- * @param index index number to associate to the offered denom pub.
- * @param denom_pub denom pub to offer with this trait.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_denom_pub (unsigned int index,
- const struct
- TALER_EXCHANGE_DenomPublicKey *denom_pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_DENOM_PUB,
- .ptr = (const void *) denom_pub
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_denom_pub.c */
diff --git a/src/lib/testing_api_trait_denom_sig.c b/src/lib/testing_api_trait_denom_sig.c
@@ -1,80 +0,0 @@
-/*
- 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 lib/testing_api_trait_denom_sig.c
- * @brief offer denomination signatures as traits
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_DENOM_SIG "denomination-signature"
-
-
-/**
- * Obtain a denomination signature from a @a cmd.
- *
- * @param cmd command to extract the denom sig from.
- * @param index index number associated with the denom sig.
- * @param[out] denom_sig set to the offered signature.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_denom_sig
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_DenominationSignature **denom_sig)
-{
- return cmd->traits (cmd->cls,
- (const void **) denom_sig,
- TALER_TESTING_TRAIT_DENOM_SIG,
- index);
-}
-
-
-/**
- * Offer denom sig.
- *
- * @param index index number to associate to the signature on
- * offer.
- * @param denom_sig the denom sig on offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_denom_sig
- (unsigned int index,
- const struct TALER_DenominationSignature *denom_sig)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_DENOM_SIG,
- .ptr = (const void *) denom_sig
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_denom_sig.c */
diff --git a/src/lib/testing_api_trait_exchange_pub.c b/src/lib/testing_api_trait_exchange_pub.c
@@ -1,78 +0,0 @@
-/*
- 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 lib/testing_api_trait_exchange_pub.c
- * @brief exchange pub traits.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_EXCHANGE_PUB "exchange-public-key"
-
-
-/**
- * Obtain a exchange public key from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index index number of the exchange to obtain.
- * @param[out] exchange_pub set to the offered exchange pub.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_exchange_pub
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ExchangePublicKeyP **exchange_pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) exchange_pub,
- TALER_TESTING_TRAIT_EXCHANGE_PUB,
- index);
-}
-
-
-/**
- * Make a trait for a exchange public key.
- *
- * @param index index number to associate to the offered exchange pub.
- * @param exchange_pub exchange pub to offer with this trait.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_exchange_pub
- (unsigned int index,
- const struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_EXCHANGE_PUB,
- .ptr = (const void *) exchange_pub
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_exchange_pub.c */
diff --git a/src/lib/testing_api_trait_exchange_sig.c b/src/lib/testing_api_trait_exchange_sig.c
@@ -1,78 +0,0 @@
-/*
- 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 lib/testing_api_trait_exchange_sig.c
- * @brief exchange pub traits.
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_EXCHANGE_SIG "exchange-online-signature"
-
-
-/**
- * Obtain a exchange signature (online sig) from a @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index index number of the exchange to obtain.
- * @param[out] exchange_sig set to the offered exchange signature.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_exchange_sig
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ExchangeSignatureP **exchange_sig)
-{
- return cmd->traits (cmd->cls,
- (const void **) exchange_sig,
- TALER_TESTING_TRAIT_EXCHANGE_SIG,
- index);
-}
-
-
-/**
- * Make a trait for a exchange signature.
- *
- * @param index index number to associate to the offered exchange pub.
- * @param exchange_sig exchange signature to offer with this trait.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_exchange_sig
- (unsigned int index,
- const struct TALER_ExchangeSignatureP *exchange_sig)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_EXCHANGE_SIG,
- .ptr = (const void *) exchange_sig
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_exchange_sig.c */
diff --git a/src/lib/testing_api_trait_fresh_coin.c b/src/lib/testing_api_trait_fresh_coin.c
@@ -1,78 +0,0 @@
-/*
- 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 lib/testing_api_trait_fresh_coin.c
- * @brief traits to offer fresh conins (after "melt" operations)
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_FRESH_COINS "fresh-coins"
-
-/**
- * Get a array of fresh coins.
- *
- * @param cmd command to extract the fresh coin from.
- * @param index which array to pick if @a cmd has multiple
- * on offer.
- * @param[out] fresh_coins will point to the offered array.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_fresh_coins
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_TESTING_FreshCoinData **fresh_coins)
-{
- return cmd->traits (cmd->cls,
- (const void **) fresh_coins,
- TALER_TESTING_TRAIT_FRESH_COINS,
- index);
-}
-
-
-/**
- * Offer a _array_ of fresh coins.
- *
- * @param index which array of fresh coins to offer,
- * if there are multiple on offer. Typically passed as
- * zero.
- * @param fresh_coins the array of fresh coins to offer
- * @return the trait,
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_fresh_coins
- (unsigned int index,
- const struct TALER_TESTING_FreshCoinData *fresh_coins)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_FRESH_COINS,
- .ptr = (const void *) fresh_coins
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_fresh_coin.c */
diff --git a/src/lib/testing_api_trait_json.c b/src/lib/testing_api_trait_json.c
@@ -1,124 +0,0 @@
-/*
- 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 lib/testing_api_trait_json.c
- * @brief offers JSON traits.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details"
-#define TALER_TESTING_TRAIT_EXCHANGE_KEYS "exchange-keys"
-
-/**
- * Obtain serialized exchange keys from @a cmd.
- *
- * @param cmd command to extract the keys from.
- * @param index index number associate with the keys on offer.
- * @param[out] keys where to write the serialized keys.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_exchange_keys
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **keys)
-{
- return cmd->traits (cmd->cls,
- (const void **) keys,
- TALER_TESTING_TRAIT_EXCHANGE_KEYS,
- index);
-}
-
-
-/**
- * Offer serialized keys in a trait.
- *
- * @param index index number associate with the serial keys
- * on offer.
- * @param keys serialized keys to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_exchange_keys
- (unsigned int index,
- const json_t *keys)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_EXCHANGE_KEYS,
- .ptr = (const json_t *) keys
- };
- return ret;
-}
-
-
-/**
- * Obtain wire details from @a cmd.
- *
- * @param cmd command to extract the wire details from.
- * @param index index number associate with the wire details
- * on offer; usually zero, as one command sticks to
- * one bank account.
- * @param[out] wire_details where to write the wire details.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_wire_details
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const json_t **wire_details)
-{
- return cmd->traits (cmd->cls,
- (const void **) wire_details,
- TALER_TESTING_TRAIT_WIRE_DETAILS,
- index);
-}
-
-
-/**
- * Offer wire details in a trait.
- *
- * @param index index number associate with the wire details
- * on offer; usually zero, as one command sticks to
- * one bank account.
- * @param wire_details wire details to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_wire_details
- (unsigned int index,
- const json_t *wire_details)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS,
- .ptr = (const json_t *) wire_details
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_json.c */
diff --git a/src/lib/testing_api_trait_merchant_key.c b/src/lib/testing_api_trait_merchant_key.c
@@ -1,128 +0,0 @@
-/*
- 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 lib/testing_api_trait_merchant_key.c
- * @brief traits to offer peer's (private) keys
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_MERCHANT_PRIV "merchant-priv"
-#define TALER_TESTING_TRAIT_MERCHANT_PUB "merchant-pub-pub"
-
-/**
- * Obtain a private key from a "peer". Used e.g. to obtain
- * a merchant's priv to sign a /track request.
- *
- * @param cmd command that is offering the key.
- * @param index (typically zero) which key to return if there
- * are multiple on offer.
- * @param[out] priv set to the key coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_merchant_priv
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_MerchantPrivateKeyP **priv)
-{
- return cmd->traits (cmd->cls,
- (const void **) priv,
- TALER_TESTING_TRAIT_MERCHANT_PRIV,
- index);
-}
-
-
-/**
- * Offer private key, typically done when CMD_1 needs it to
- * sign a request.
- *
- * @param index (typically zero) which key to return if there are
- * multiple on offer.
- * @param priv which object should be offered.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_merchant_priv (unsigned int index,
- const struct
- TALER_MerchantPrivateKeyP *priv)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_MERCHANT_PRIV,
- .ptr = (const void *) priv
- };
-
- return ret;
-}
-
-
-/**
- * Obtain a public key from a "peer". Used e.g. to obtain
- * a merchant's public key to use backend's API.
- *
- * @param cmd command offering the key.
- * @param index (typically zero) which key to return if there
- * are multiple on offer.
- * @param[out] pub set to the key coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_merchant_pub
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_MerchantPublicKeyP **pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) pub,
- TALER_TESTING_TRAIT_MERCHANT_PUB,
- index);
-}
-
-
-/**
- * Offer public key.
- *
- * @param index (typically zero) which key to return if there
- * are multiple on offer. NOTE: if one key is offered, it
- * is mandatory to set this as zero.
- * @param pub which object should be returned.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_merchant_pub (unsigned int index,
- const struct
- TALER_MerchantPublicKeyP *pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_MERCHANT_PUB,
- .ptr = (const void *) pub
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_merchant_key.c */
diff --git a/src/lib/testing_api_trait_number.c b/src/lib/testing_api_trait_number.c
@@ -1,150 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_trait_number.c
- * @brief traits to offer numbers
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_UINT "uint"
-#define TALER_TESTING_TRAIT_UINT64 "uint-64"
-#define TALER_TESTING_TRAIT_BANK_ROW "bank-transaction-row"
-
-
-/**
- * Obtain a number from @a cmd.
- *
- * @param cmd command to extract the number from.
- * @param index the number's index number.
- * @param[out] n set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_uint (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const unsigned int **n)
-{
- return cmd->traits (cmd->cls,
- (const void **) n,
- TALER_TESTING_TRAIT_UINT,
- index);
-}
-
-
-/**
- * Offer a number.
- *
- * @param index the number's index number.
- * @param n the number to offer.
- * @return #GNUNET_OK on success.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_uint (unsigned int index,
- const unsigned int *n)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_UINT,
- .ptr = (const void *) n
- };
- return ret;
-}
-
-
-/**
- * Obtain a "number" value from @a cmd, 64-bit version.
- *
- * @param cmd command to extract the number from.
- * @param index the number's index number.
- * @param[out] n 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,
- (const void **) n,
- TALER_TESTING_TRAIT_UINT64,
- index);
-}
-
-
-/**
- * Offer number trait, 64-bit version.
- *
- * @param index the number's index number.
- * @param n number to offer.
- */
-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;
-}
-
-
-/**
- * Obtain a bank transaction row value from @a cmd.
- *
- * @param cmd command to extract the number from.
- * @param[out] row set to the number coming from @a cmd.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_bank_row (const struct TALER_TESTING_Command *cmd,
- const uint64_t **row)
-{
- return cmd->traits (cmd->cls,
- (const void **) row,
- TALER_TESTING_TRAIT_BANK_ROW,
- 0);
-}
-
-
-/**
- * Offer bank transaction row trait.
- *
- * @param row number to offer.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_bank_row (const uint64_t *row)
-{
- struct TALER_TESTING_Trait ret = {
- .index = 0,
- .trait_name = TALER_TESTING_TRAIT_BANK_ROW,
- .ptr = (const void *) row
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_number.c */
diff --git a/src/lib/testing_api_trait_process.c b/src/lib/testing_api_trait_process.c
@@ -1,83 +0,0 @@
-/*
- 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 lib/testing_api_trait_process.c
- * @brief trait offering process handles.
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_PROCESS "process"
-
-
-/**
- * Obtain location where a command stores a pointer to a process.
- *
- * @param cmd command to extract trait from.
- * @param index which process to pick if @a cmd
- * has multiple on offer.
- * @param[out] processp set to the address of the pointer to the
- * process.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_process
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- struct GNUNET_OS_Process ***processp)
-{
- return cmd->traits (cmd->cls,
- (const void **) processp,
- TALER_TESTING_TRAIT_PROCESS,
- index);
-}
-
-
-/**
- * Offer location where a command stores a pointer to a process.
- *
- * @param index offered location index number, in case there are
- * multiple on offer.
- * @param processp process location to offer.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_process
- (unsigned int index,
- struct GNUNET_OS_Process **processp)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_PROCESS,
- .ptr = (const void *) processp
- };
-
- return ret;
-}
-
-
-/* end of testing_api_trait_process.c */
diff --git a/src/lib/testing_api_trait_reserve_priv.c b/src/lib/testing_api_trait_reserve_priv.c
@@ -1,77 +0,0 @@
-/*
- 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 lib/testing_api_trait_reserve_priv.c
- * @brief implements reserve private key trait
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY \
- "reserve-private-key"
-
-/**
- * Obtain a reserve private key from a @a cmd.
- *
- * @param cmd command to extract the reserve priv from.
- * @param index reserve priv's index number.
- * @param[out] reserve_priv set to the reserve priv.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_reserve_priv
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ReservePrivateKeyP **reserve_priv)
-{
- return cmd->traits (cmd->cls,
- (const void **) reserve_priv,
- TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
- index);
-}
-
-
-/**
- * Offer a reserve private key.
- *
- * @param index reserve priv's index number.
- * @param reserve_priv reserve private key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_reserve_priv
- (unsigned int index,
- const struct TALER_ReservePrivateKeyP *reserve_priv)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
- .ptr = (const void *) reserve_priv
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_reserve_priv.c */
diff --git a/src/lib/testing_api_trait_reserve_pub.c b/src/lib/testing_api_trait_reserve_pub.c
@@ -1,77 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_trait_reserve_pub.c
- * @brief implements reserve public key trait
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \
- "reserve-public-key"
-
-/**
- * Obtain a reserve public key from a @a cmd.
- *
- * @param cmd command to extract the reserve pub from.
- * @param index reserve pub's index number.
- * @param[out] reserve_pub set to the reserve pub.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_reserve_pub
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_ReservePublicKeyP **reserve_pub)
-{
- return cmd->traits (cmd->cls,
- (const void **) reserve_pub,
- TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
- index);
-}
-
-
-/**
- * Offer a reserve public key.
- *
- * @param index reserve pub's index number.
- * @param reserve_pub reserve public key to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_reserve_pub
- (unsigned int index,
- const struct TALER_ReservePublicKeyP *reserve_pub)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
- .ptr = (const void *) reserve_pub
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_reserve_pub.c */
diff --git a/src/lib/testing_api_trait_string.c b/src/lib/testing_api_trait_string.c
@@ -1,232 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2018-2020 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 lib/testing_api_trait_string.c
- * @brief offers strings traits.
- * @author Marcello Stanisci
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-/**
- * Some string. Avoid, use something more precise!
- */
-#define TALER_TESTING_TRAIT_STRING "string"
-
-/**
- * An HTTP-URL.
- */
-#define TALER_TESTING_TRAIT_URL "url"
-
-/**
- * A PAYTO-URL.
- */
-#define TALER_TESTING_TRAIT_PAYTO "payto"
-
-/**
- * String identifying an order.
- */
-#define TALER_TESTING_TRAIT_ORDER_ID "order-id"
-
-
-/**
- * Obtain a string from @a cmd.
- *
- * @param cmd command to extract the subject from.
- * @param index index number associated with the transfer
- * subject to offer.
- * @param[out] s where to write the offered
- * string
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_string (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **s)
-{
- return cmd->traits (cmd->cls,
- (const void **) s,
- TALER_TESTING_TRAIT_STRING,
- index);
-}
-
-
-/**
- * Offer string.
- *
- * @param index index number associated with the transfer
- * subject being offered.
- * @param s transfer subject to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_string (unsigned int index,
- const char *s)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_STRING,
- .ptr = (const void *) s
- };
- return ret;
-}
-
-
-/**
- * Obtain a HTTP url from @a cmd.
- *
- * @param cmd command to extract the url from.
- * @param index which url is to be picked, in case
- * multiple are offered.
- * @param[out] url where to write the url.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_url (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **url)
-{
- return cmd->traits (cmd->cls,
- (const void **) url,
- TALER_TESTING_TRAIT_URL,
- index);
-}
-
-
-/**
- * Offer HTTP url in a trait.
- *
- * @param index which url is to be picked,
- * in case multiple are offered.
- * @param url the url to offer.
- *
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_url (unsigned int index,
- const char *url)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_URL,
- .ptr = (const void *) url
- };
-
- GNUNET_assert (0 != strncasecmp (url,
- "payto://",
- strlen ("payto://")));
-
- return ret;
-}
-
-
-/**
- * Obtain a order id from @a cmd.
- *
- * @param cmd command to extract the order id from.
- * @param index which order id is to be picked, in case
- * multiple are offered.
- * @param[out] order_id where to write the order id.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_order_id (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **order_id)
-{
- return cmd->traits (cmd->cls,
- (const void **) order_id,
- TALER_TESTING_TRAIT_ORDER_ID,
- index);
-}
-
-
-/**
- * Offer order id in a trait.
- *
- * @param index which order id is to be offered,
- * in case multiple are offered.
- * @param order_id the order id to offer.
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_order_id (unsigned int index,
- const char *order_id)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_ORDER_ID,
- .ptr = (const void *) order_id
- };
- return ret;
-}
-
-
-/**
- * Obtain a PAYTO-url from @a cmd.
- *
- * @param cmd command to extract the url from.
- * @param pt which url is to be picked, in case
- * multiple are offered.
- * @param[out] url where to write the url.
- * @return #GNUNET_OK on success.
- */
-int
-TALER_TESTING_get_trait_payto (const struct TALER_TESTING_Command *cmd,
- enum TALER_TESTING_PaytoType pt,
- const char **url)
-{
- return cmd->traits (cmd->cls,
- (const void **) url,
- TALER_TESTING_TRAIT_PAYTO,
- (unsigned int) pt);
-}
-
-
-/**
- * Offer a "payto" URL reference.
- *
- * @param pt which reference is to be offered,
- * in case multiple are offered.
- * @param payto_uri the payto URI
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_payto (enum TALER_TESTING_PaytoType pt,
- const char *payto_uri)
-{
- struct TALER_TESTING_Trait ret = {
- .index = (unsigned int) pt,
- .trait_name = TALER_TESTING_TRAIT_PAYTO,
- .ptr = (const void *) payto_uri,
- };
-
- GNUNET_assert (0 == strncasecmp (payto_uri,
- "payto://",
- strlen ("payto://")));
- return ret;
-}
-
-
-/* end of testing_api_trait_string.c */
diff --git a/src/lib/testing_api_trait_time.c b/src/lib/testing_api_trait_time.c
@@ -1,77 +0,0 @@
-/*
- 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 lib/testing_api_trait_time.c
- * @brief traits to offer time stamps.
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_TIME_ABS "time-abs"
-
-/**
- * Obtain a absolute time from @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which time stamp to pick if
- * @a cmd has multiple on offer.
- * @param[out] time set to the wanted WTID.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_absolute_time
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct GNUNET_TIME_Absolute **time)
-{
- return cmd->traits (cmd->cls,
- (const void **) time,
- TALER_TESTING_TRAIT_TIME_ABS,
- index);
-}
-
-
-/**
- * Offer a absolute time.
- *
- * @param index associate the object with this index
- * @param time which object should be returned
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_absolute_time
- (unsigned int index,
- const struct GNUNET_TIME_Absolute *time)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_TIME_ABS,
- .ptr = (const void *) time
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_time.c */
diff --git a/src/lib/testing_api_trait_wtid.c b/src/lib/testing_api_trait_wtid.c
@@ -1,77 +0,0 @@
-/*
- 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 lib/testing_api_trait_number.c
- * @brief traits to offer numbers
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-#define TALER_TESTING_TRAIT_WTID "wtid"
-
-/**
- * Obtain a WTID value from @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index which WTID to pick if @a cmd has multiple on
- * offer
- * @param[out] wtid set to the wanted WTID.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_wtid
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const struct TALER_WireTransferIdentifierRawP **wtid)
-{
- return cmd->traits (cmd->cls,
- (const void **) wtid,
- TALER_TESTING_TRAIT_WTID,
- index);
-}
-
-
-/**
- * Offer a WTID.
- *
- * @param index associate the object with this index
- * @param wtid which object should be returned
- * @return the trait.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_wtid
- (unsigned int index,
- const struct TALER_WireTransferIdentifierRawP *wtid)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_WTID,
- .ptr = (const void *) wtid
- };
- return ret;
-}
-
-
-/* end of testing_api_trait_number.c */
diff --git a/src/lib/testing_api_traits.c b/src/lib/testing_api_traits.c
@@ -1,82 +0,0 @@
-/*
- 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 lib/testing_api_traits.c
- * @brief loop for trait resolution
- * @author Christian Grothoff
- * @author Marcello Stanisci
- */
-#include "platform.h"
-#include "taler_json_lib.h"
-#include <gnunet/gnunet_curl_lib.h>
-#include "exchange_api_handle.h"
-#include "taler_signatures.h"
-#include "taler_testing_lib.h"
-
-
-/**
- * End a trait array. Usually, commands offer several traits,
- * and put them in arrays.
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_trait_end ()
-{
- struct TALER_TESTING_Trait end = {
- .index = 0,
- .trait_name = NULL,
- .ptr = NULL
- };
-
- return end;
-}
-
-
-/**
- * Pick the chosen trait from the traits array.
- *
- * @param traits the traits array.
- * @param ret where to store the result.
- * @param trait type of the trait to extract.
- * @param index index number of the object to extract.
- * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
- */
-int
-TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
- const void **ret,
- const char *trait,
- unsigned int index)
-{
- for (unsigned int i = 0; NULL != traits[i].trait_name; i++)
- {
- if ( (0 == strcmp (trait, traits[i].trait_name)) &&
- (index == traits[i].index) )
- {
- *ret = (void *) traits[i].ptr;
- return GNUNET_OK;
- }
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Trait %s/%u not found.\n",
- trait, index);
-
- return GNUNET_SYSERR;
-}
-
-
-/* end of testing_api_traits.c */
diff --git a/src/lib/.gitignore b/src/testing/.gitignore
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
@@ -0,0 +1,308 @@
+# This Makefile.am is in the public domain
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/include \
+ $(LIBGCRYPT_CFLAGS) \
+ $(POSTGRESQL_CPPFLAGS)
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+
+# Libraries
+
+lib_LTLIBRARIES = \
+ libtalertesting.la
+
+libtalertesting_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+libtalertesting_la_SOURCES = \
+ testing_api_cmd_auditor_deposit_confirmation.c \
+ testing_api_cmd_auditor_exchanges.c \
+ testing_api_cmd_auditor_exec_auditor.c \
+ testing_api_cmd_auditor_exec_auditor_dbinit.c \
+ testing_api_cmd_auditor_exec_wire_auditor.c \
+ testing_api_cmd_bank_admin_add_incoming.c \
+ testing_api_cmd_bank_check.c \
+ testing_api_cmd_bank_admin_check.c \
+ testing_api_cmd_bank_check_empty.c \
+ testing_api_cmd_bank_history_credit.c \
+ testing_api_cmd_bank_history_debit.c \
+ testing_api_cmd_bank_transfer.c \
+ testing_api_cmd_batch.c \
+ testing_api_cmd_check_keys.c \
+ testing_api_cmd_deposit.c \
+ testing_api_cmd_exec_aggregator.c \
+ testing_api_cmd_exec_wirewatch.c \
+ testing_api_cmd_exec_keyup.c \
+ testing_api_cmd_exec_auditor-sign.c \
+ testing_api_cmd_recoup.c \
+ testing_api_cmd_refund.c \
+ testing_api_cmd_refresh.c \
+ testing_api_cmd_serialize_keys.c \
+ testing_api_cmd_signal.c \
+ testing_api_cmd_sleep.c \
+ testing_api_cmd_status.c \
+ testing_api_cmd_track.c \
+ testing_api_cmd_wait.c \
+ testing_api_cmd_wire.c \
+ testing_api_cmd_withdraw.c \
+ testing_api_cmd_insert_deposit.c \
+ testing_api_helpers_auditor.c \
+ testing_api_helpers_bank.c \
+ testing_api_helpers_exchange.c \
+ testing_api_loop.c \
+ testing_api_traits.c \
+ testing_api_trait_amount.c \
+ testing_api_trait_blinding_key.c \
+ testing_api_trait_cmd.c \
+ testing_api_trait_coin_priv.c \
+ testing_api_trait_contract.c \
+ testing_api_trait_denom_pub.c \
+ testing_api_trait_denom_sig.c \
+ testing_api_trait_exchange_pub.c \
+ testing_api_trait_exchange_sig.c \
+ testing_api_trait_fresh_coin.c \
+ testing_api_trait_json.c \
+ testing_api_trait_merchant_key.c \
+ testing_api_trait_number.c \
+ testing_api_trait_process.c \
+ testing_api_trait_reserve_pub.c \
+ testing_api_trait_reserve_priv.c \
+ testing_api_trait_string.c \
+ testing_api_trait_time.c \
+ testing_api_trait_wtid.c
+libtalertesting_la_LIBADD = \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ -lgnunetcurl \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ $(XLIB)
+
+
+# Test cases
+
+AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
+
+check_PROGRAMS = \
+ test_auditor_api \
+ test_auditor_api_version \
+ test_bank_api_with_fakebank \
+ test_bank_api_with_pybank \
+ test_exchange_api \
+ test_exchange_api_keys_cherry_picking \
+ test_exchange_api_revocation \
+ test_exchange_api_overlapping_keys_bug \
+ test_taler_exchange_aggregator-postgres \
+ test_taler_exchange_wirewatch-postgres
+if HAVE_TWISTER
+ check_PROGRAMS += \
+ test_exchange_api_twisted \
+ test_bank_api_with_fakebank_twisted \
+ test_bank_api_with_pybank_twisted
+endif
+
+TESTS = \
+ $(check_PROGRAMS)
+
+test_auditor_api_SOURCES = \
+ test_auditor_api.c
+test_auditor_api_LDADD = \
+ libtalerauditor.la \
+ libtalertesting.la \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_auditor_api_version_SOURCES = \
+ test_auditor_api_version.c
+test_auditor_api_version_LDADD = \
+ libtalerauditor.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_bank_api_with_fakebank_SOURCES = \
+ test_bank_api.c
+test_bank_api_with_fakebank_LDADD = \
+ $(top_builddir)/src/lib/libtalertesting.la \
+ -ltalerexchange \
+ -lgnunetutil \
+ $(top_builddir)/src/bank-lib/libtalerbank.la
+
+test_bank_api_with_pybank_SOURCES = \
+ test_bank_api.c
+test_bank_api_with_pybank_LDADD = \
+ libtalertesting.la \
+ libtalerexchange.la \
+ -lgnunetutil \
+ $(top_builddir)/src/bank-lib/libtalerbank.la
+
+test_exchange_api_SOURCES = \
+ test_exchange_api.c
+test_exchange_api_LDADD = \
+ libtalertesting.la \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_exchange_api_revocation_SOURCES = \
+ test_exchange_api_revocation.c
+test_exchange_api_revocation_LDADD = \
+ libtalertesting.la \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_exchange_api_keys_cherry_picking_SOURCES = \
+ test_exchange_api_keys_cherry_picking.c
+test_exchange_api_keys_cherry_picking_LDADD = \
+ libtalertesting.la \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_exchange_api_overlapping_keys_bug_SOURCES = \
+ test_exchange_api_overlapping_keys_bug.c
+test_exchange_api_overlapping_keys_bug_LDADD = \
+ libtalertesting.la \
+ libtalerexchange.la \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_taler_exchange_aggregator_postgres_SOURCES = \
+ test_taler_exchange_aggregator.c
+test_taler_exchange_aggregator_postgres_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/lib/libtalertesting.la \
+ -lmicrohttpd \
+ -lgnunetutil \
+ -lgnunetjson \
+ -ljansson \
+ -lpthread
+
+test_taler_exchange_wirewatch_postgres_SOURCES = \
+ test_taler_exchange_wirewatch.c
+test_taler_exchange_wirewatch_postgres_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ $(top_builddir)/src/lib/libtalertesting.la \
+ -lmicrohttpd \
+ -lgnunetutil \
+ -lgnunetjson \
+ -lgnunetpq \
+ -ljansson \
+ -lpthread
+
+test_exchange_api_twisted_SOURCES = \
+ test_exchange_api_twisted.c
+test_exchange_api_twisted_LDADD = \
+ $(LIBGCRYPT_LIBS) \
+ libtalertesting.la \
+ libtalerexchange.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -ltalertwistertesting \
+ -lgnunetjson \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_bank_api_with_fakebank_twisted_SOURCES = \
+ test_bank_api_twisted.c
+test_bank_api_with_fakebank_twisted_LDADD = \
+ $(top_builddir)/src/lib/libtalertesting.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ -ltalertwistertesting \
+ -lgnunetjson \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+test_bank_api_with_pybank_twisted_SOURCES = \
+ test_bank_api_twisted.c
+test_bank_api_with_pybank_twisted_LDADD = \
+ $(top_builddir)/src/lib/libtalertesting.la \
+ $(top_builddir)/src/bank-lib/libtalerbank.la \
+ $(top_builddir)/src/bank-lib/libtalerfakebank.la \
+ $(top_builddir)/src/lib/libtalerexchange.la \
+ $(top_builddir)/src/json/libtalerjson.la \
+ -ltalertwistertesting \
+ -lgnunetjson \
+ -lgnunetcurl \
+ -lgnunetutil \
+ -ljansson
+
+
+# Distribution
+
+EXTRA_DIST = \
+ test_bank_api.conf \
+ test_bank_api_bank_twisted.conf \
+ test_auditor_api.conf \
+ test_auditor_api_expire_reserve_now.conf \
+ test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv \
+ test_exchange_api_home/.config/taler/account-2.json \
+ test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json \
+ test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \
+ test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \
+ test_exchange_api_home/.config/taler/test.json \
+ test_exchange_api_home/.config/taler/sepa.json \
+ test_exchange_api.conf \
+ test_exchange_api_twisted.conf \
+ test_exchange_api_keys_cherry_picking.conf \
+ test_exchange_api_keys_cherry_picking_extended.conf \
+ test_exchange_api_keys_cherry_picking_extended_2.conf \
+ test_exchange_api_expire_reserve_now.conf \
+ test-taler-exchange-aggregator-postgres.conf \
+ test-taler-exchange-wirewatch-postgres.conf
diff --git a/src/lib/afl-generate.sh b/src/testing/afl-generate.sh
diff --git a/src/lib/baseline/admin_add_incoming.req b/src/testing/baseline/admin_add_incoming.req
diff --git a/src/lib/baseline/deposit.req b/src/testing/baseline/deposit.req
diff --git a/src/lib/baseline/keys.req b/src/testing/baseline/keys.req
diff --git a/src/lib/baseline/refresh_link.req b/src/testing/baseline/refresh_link.req
diff --git a/src/lib/baseline/refresh_melt.req b/src/testing/baseline/refresh_melt.req
diff --git a/src/lib/baseline/refresh_reveal.req b/src/testing/baseline/refresh_reveal.req
diff --git a/src/lib/baseline/reserve_status.req b/src/testing/baseline/reserve_status.req
diff --git a/src/lib/baseline/reserve_withdraw.req b/src/testing/baseline/reserve_withdraw.req
diff --git a/src/lib/baseline/wire.req b/src/testing/baseline/wire.req
diff --git a/src/lib/baseline/wire_sepa.req b/src/testing/baseline/wire_sepa.req
diff --git a/src/lib/baseline/wire_test.req b/src/testing/baseline/wire_test.req
diff --git a/src/lib/test-taler-exchange-aggregator-postgres.conf b/src/testing/test-taler-exchange-aggregator-postgres.conf
diff --git a/src/lib/test-taler-exchange-wirewatch-postgres.conf b/src/testing/test-taler-exchange-wirewatch-postgres.conf
diff --git a/src/testing/test_auditor_api.c b/src/testing/test_auditor_api.c
@@ -0,0 +1,710 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 testing/test_auditor_api.c
+ * @brief testcase to test auditor's HTTP API interface
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_auditor_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_auditor_api.conf"
+
+#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
+ "test_auditor_api_expire_reserve_now.conf"
+
+/**
+ * Exchange configuration data.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
+
+/**
+ * Execute the taler-exchange-aggregator command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE)
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &bc.exchange_auth, \
+ bc.user42_payto)
+
+/**
+ * Run the taler-auditor.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_RUN_AUDITOR(label) \
+ TALER_TESTING_cmd_exec_auditor (label, CONFIG_FILE)
+
+/**
+ * Run the taler-wire-auditor.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_RUN_WIRE_AUDITOR(label) \
+ TALER_TESTING_cmd_exec_wire_auditor (label, CONFIG_FILE)
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ /**
+ * Test withdraw.
+ */
+ struct TALER_TESTING_Command withdraw[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer
+ ("check-create-reserve-1",
+ "EUR:5.01", bc.user42_payto, bc.exchange_payto,
+ "create-reserve-1"),
+ /**
+ * Make a reserve exist, according to the previous transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-1"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-simple",
+ "withdraw-coin-1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command refresh[] = {
+ /* Fill reserve with EUR:5, 1ct is for fees. NOTE: the old
+ * test-suite gave a account number of _424_ to the user at
+ * this step; to type less, here the _42_ number is reused.
+ * Does this change the tests semantics? *///
+ CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer
+ ("check-refresh-create-reserve-1",
+ "EUR:5.01", bc.user42_payto, bc.exchange_payto,
+ "refresh-create-reserve-1"),
+ /**
+ * Make previous command effective.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-2"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
+ "refresh-create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in
+ * full) Merchant receives EUR:0.99 due to 1 ct deposit fee.
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
+ "refresh-withdraw-coin-1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x
+ * EUR:0.13) */
+ TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1",
+ "refresh-withdraw-coin-1",
+ MHD_HTTP_OK,
+ NULL),
+ /**
+ * Complete (successful) melt operation, and withdraw the coins
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1",
+ "refresh-melt-1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:0.1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b",
+ "refresh-reveal-1",
+ 3,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command track[] = {
+ /**
+ * Run transfers. Note that _actual_ aggregation will NOT
+ * happen here, as each deposit operation is run with a
+ * fresh merchant public key! NOTE: this comment comes
+ * "verbatim" from the old test-suite, and IMO does not explain
+ * a lot!*///
+ CMD_EXEC_AGGREGATOR ("run-aggregator"),
+
+ /**
+ * Check all the transfers took place.
+ */
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check_bank_transfer-499c", ec.exchange_url,
+ "EUR:4.98", bc.exchange_payto, bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check_bank_transfer-99c1", ec.exchange_url,
+ "EUR:0.98", bc.exchange_payto, bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check_bank_transfer-99c", ec.exchange_url,
+ "EUR:0.08", bc.exchange_payto, bc.user43_payto),
+
+ /* The following transactions got originated within
+ * the "massive deposit confirms" batch. */
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-1",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-2",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-3",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-4",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-5",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-6",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-7",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-8",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-9",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_transfer
+ ("check-massive-transfer-10",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto, bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ /**
+ * This block checks whether a wire deadline
+ * very far in the future does NOT get aggregated now.
+ */
+ struct TALER_TESTING_Command unaggregation[] = {
+ TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"),
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated",
+ "EUR:5.01"),
+ CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"),
+ /* "consume" reserve creation transfer. */
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check_bank_transfer-unaggregated",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "create-reserve-unaggregated"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
+ "create-reserve-unaggregated",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-unaggregated",
+ "withdraw-coin-unaggregated",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_YEARS,
+ 3000),
+ "EUR:5",
+ MHD_HTTP_OK),
+ CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
+ TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-b"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command refund[] = {
+ /**
+ * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per config.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1",
+ "EUR:5.01"),
+ /**
+ * Run wire-watch to trigger the reserve creation.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-3"),
+ /**
+ * Withdraw a 5 EUR coin, at fee of 1 ct
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
+ "create-reserve-r1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Spend 5 EUR of the 5 EUR coin (in full). Merchant would
+ * receive EUR:4.99 due to 1 ct deposit fee.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-refund-1",
+ "withdraw-coin-r1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_MINUTES,
+ "EUR:5",
+ MHD_HTTP_OK),
+
+ TALER_TESTING_cmd_refund ("refund-ok",
+ MHD_HTTP_OK,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-1"),
+ /**
+ * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone
+ * due to refund) (merchant would receive EUR:4.98 due to
+ * 1 ct deposit fee) */
+ TALER_TESTING_cmd_deposit ("deposit-refund-2",
+ "withdraw-coin-r1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"more\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:4.99",
+ MHD_HTTP_OK),
+ /**
+ * Run transfers. This will do the transfer as refund deadline was
+ * 0.
+ */
+ CMD_EXEC_AGGREGATOR ("run-aggregator-3"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command recoup[] = {
+ /**
+ * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
+ * config.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1",
+ "EUR:5.01"),
+ /**
+ * Run wire-watch to trigger the reserve creation.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-4"),
+ /**
+ * Withdraw a 5 EUR coin, at fee of 1 ct
+ */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
+ "recoup-create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_revoke ("revoke-1",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-1",
+ CONFIG_FILE),
+ TALER_TESTING_cmd_recoup ("recoup-1",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-1",
+ "EUR:5",
+ NULL),
+ /**
+ * Re-withdraw from this reserve
+ */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
+ "recoup-create-reserve-1",
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * These commands should close the reserve because the aggregator
+ * is given a config file that ovverrides the reserve expiration
+ * time (making it now-ish)
+ */CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
+ CONFIG_FILE_EXPIRE_RESERVE_NOW),
+ TALER_TESTING_cmd_exec_aggregator ("close-reserves",
+ CONFIG_FILE_EXPIRE_RESERVE_NOW),
+ /**
+ * Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
+ * config, then withdraw two coin, partially spend one, and
+ * then have the rest paid back. Check deposit of other coin
+ * fails. (Do not use EUR:5 here as the EUR:5 coin was
+ * revoked and we did not bother to create a new one...)
+ */CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2",
+ "EUR:2.02"),
+ /**
+ * Make previous command effective.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-5"),
+ /**
+ * Withdraw a 1 EUR coin, at fee of 1 ct
+ */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
+ "recoup-create-reserve-2",
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Withdraw a 1 EUR coin, at fee of 1 ct
+ */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
+ "recoup-create-reserve-2",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
+ "recoup-withdraw-coin-2a",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_revoke ("revoke-2",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-2a",
+ CONFIG_FILE),
+ TALER_TESTING_cmd_recoup ("recoup-2",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-2a",
+ "EUR:0.5",
+ NULL),
+ TALER_TESTING_cmd_end ()
+ };
+
+
+ struct TALER_TESTING_Command massive_deposit_confirms[] = {
+
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("massive-reserve",
+ "EUR:10.10"),
+ TALER_TESTING_cmd_check_bank_admin_transfer
+ ("check-massive-transfer",
+ "EUR:10.10",
+ bc.user42_payto, bc.exchange_payto,
+ "massive-reserve"),
+ CMD_EXEC_WIREWATCH ("massive-wirewatch"),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-1",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-2",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-3",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-4",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-5",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-6",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-7",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-8",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-9",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("massive-withdraw-10",
+ "massive-reserve",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-1",
+ "massive-withdraw-1",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-2",
+ "massive-withdraw-2",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-3",
+ "massive-withdraw-3",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-4",
+ "massive-withdraw-4",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-5",
+ "massive-withdraw-5",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-6",
+ "massive-withdraw-6",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-7",
+ "massive-withdraw-7",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-8",
+ "massive-withdraw-8",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-9",
+ "massive-withdraw-9",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("massive-deposit-10",
+ "massive-withdraw-10",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit_confirmation ("deposit-confirmation",
+ is->auditor,
+ "massive-deposit-10",
+ 0,
+ "EUR:0.99",
+ MHD_HTTP_OK),
+ CMD_RUN_AUDITOR ("massive-auditor"),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command commands[] = {
+ CMD_RUN_AUDITOR ("virgin-auditor"),
+ CMD_RUN_WIRE_AUDITOR ("virgin-wire-auditor"),
+ TALER_TESTING_cmd_exchanges_with_url ("check-exchange",
+ MHD_HTTP_OK,
+ "http://localhost:8081/"),
+ TALER_TESTING_cmd_batch ("massive-deposit-confirms",
+ massive_deposit_confirms),
+ TALER_TESTING_cmd_batch ("withdraw",
+ withdraw),
+ TALER_TESTING_cmd_batch ("spend",
+ spend),
+ TALER_TESTING_cmd_batch ("refresh",
+ refresh),
+ TALER_TESTING_cmd_batch ("track",
+ track),
+ TALER_TESTING_cmd_batch ("unaggregation",
+ unaggregation),
+ TALER_TESTING_cmd_batch ("refund",
+ refund),
+ TALER_TESTING_cmd_batch ("recoup",
+ recoup),
+ CMD_RUN_AUDITOR ("normal-auditor"),
+ CMD_RUN_WIRE_AUDITOR ("normal-wire-auditor"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_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-auditor-api",
+ "INFO",
+ NULL);
+ /* Check fakebank port is available and get configuration data. */
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "account-2",
+ &bc))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+ /* @helpers. Run keyup, create tables, ... Note: it
+ * fetches the port number from config in order to see
+ * if it's available. */
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (GNUNET_OK !=
+ /* Set up event loop and reschedule context, plus
+ * start/stop the exchange. It calls TALER_TESTING_setup
+ * which creates the 'is' object.
+ */
+ TALER_TESTING_auditor_setup (&run,
+ NULL,
+ CONFIG_FILE))
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_auditor_api.c */
diff --git a/src/lib/test_auditor_api.conf b/src/testing/test_auditor_api.conf
diff --git a/src/lib/test_auditor_api_expire_reserve_now.conf b/src/testing/test_auditor_api_expire_reserve_now.conf
diff --git a/src/testing/test_auditor_api_version.c b/src/testing/test_auditor_api_version.c
@@ -0,0 +1,163 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 testing/test_auditor_api_version.c
+ * @brief testcase to test auditor's HTTP API interface to fetch /version
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_auditor_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_auditor_api.conf"
+
+static struct TALER_AUDITOR_Handle *ah;
+
+static struct GNUNET_CURL_Context *ctx;
+
+static struct GNUNET_CURL_RescheduleContext *rc;
+
+static int global_ret;
+
+static struct GNUNET_SCHEDULER_Task *tt;
+
+static void
+do_shutdown (void *cls)
+{
+ (void) cls;
+
+ if (NULL != tt)
+ {
+ GNUNET_SCHEDULER_cancel (tt);
+ tt = NULL;
+ }
+ TALER_AUDITOR_disconnect (ah);
+ GNUNET_CURL_fini (ctx);
+ GNUNET_CURL_gnunet_rc_destroy (rc);
+}
+
+
+static void
+do_timeout (void *cls)
+{
+ (void) cls;
+ tt = NULL;
+ global_ret = 3;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Function called with information about the auditor.
+ *
+ * @param cls closure
+ * @param vi basic information about the auditor
+ * @param compat protocol compatibility information
+ */
+static void
+version_cb (void *cls,
+ const struct TALER_AUDITOR_VersionInformation *vi,
+ enum TALER_AUDITOR_VersionCompatibility compat)
+{
+ if ( (NULL != vi) &&
+ (TALER_AUDITOR_VC_MATCH == compat) )
+ global_ret = 0;
+ else
+ global_ret = 2;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls)
+{
+ const char *auditor_url = "http://localhost:8083/";
+
+ (void) cls;
+ ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+ &rc);
+ rc = GNUNET_CURL_gnunet_rc_create (ctx);
+ ah = TALER_AUDITOR_connect (ctx,
+ auditor_url,
+ &version_cb,
+ NULL);
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+ NULL);
+ tt = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &do_timeout,
+ NULL);
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ struct GNUNET_OS_Process *proc;
+
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test-auditor-api-version",
+ "INFO",
+ NULL);
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-httpd",
+ "taler-auditor-httpd",
+ "-c", CONFIG_FILE,
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-auditor-httpd`,"
+ " is your PATH correct?\n");
+ return 77;
+ }
+ GNUNET_SCHEDULER_run (&run,
+ NULL);
+ GNUNET_OS_process_kill (proc, SIGTERM);
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_destroy (proc);
+ return global_ret;
+}
+
+
+/* end of test_auditor_api_version.c */
diff --git a/src/testing/test_bank_api.c b/src/testing/test_bank_api.c
@@ -0,0 +1,186 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2016-2020 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 testing/test_bank_api.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 "taler_testing_lib.h"
+
+#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank.conf"
+#define CONFIG_FILE_PYBANK "test_bank_api_pybank.conf"
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Handle to the Py-bank daemon.
+ */
+static struct GNUNET_OS_Process *bankd;
+
+/**
+ * Flag indicating whether the test is running against the
+ * Fakebank. Set up at runtime.
+ */
+static int with_fakebank;
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ memset (&wtid, 42, sizeof (wtid));
+
+ {
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_bank_credits ("history-0",
+ &bc.exchange_auth,
+ NULL,
+ 1),
+ TALER_TESTING_cmd_admin_add_incoming ("credit-1",
+ "KUDOS:5.01",
+ &bc.exchange_auth,
+ bc.user42_payto),
+ TALER_TESTING_cmd_bank_credits ("history-1c",
+ &bc.exchange_auth,
+ NULL,
+ 5),
+ TALER_TESTING_cmd_bank_debits ("history-1d",
+ &bc.exchange_auth,
+ NULL,
+ 5),
+ TALER_TESTING_cmd_admin_add_incoming ("credit-2",
+ "KUDOS:3.21",
+ &bc.exchange_auth,
+ bc.user42_payto),
+ TALER_TESTING_cmd_transfer ("debit-1",
+ "KUDOS:3.22",
+ &bc.exchange_auth,
+ bc.exchange_payto,
+ bc.user42_payto,
+ &wtid,
+ "http://exchange.example.com/"),
+ TALER_TESTING_cmd_bank_debits ("history-2b",
+ &bc.exchange_auth,
+ NULL,
+ 5),
+ TALER_TESTING_cmd_end ()
+ };
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Bank serves at `%s'\n",
+ bc.exchange_auth.wire_gateway_url);
+ if (GNUNET_YES == with_fakebank)
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_url);
+ else
+ TALER_TESTING_run (is,
+ commands);
+ }
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ int rv;
+ const char *cfgfilename;
+
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test-bank-api",
+ "DEBUG",
+ NULL);
+ with_fakebank = TALER_TESTING_has_in_name (argv[0],
+ "_with_fakebank");
+ if (GNUNET_YES == with_fakebank)
+ {
+ TALER_LOG_DEBUG ("Running against the Fakebank.\n");
+ cfgfilename = CONFIG_FILE_FAKEBANK;
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE_FAKEBANK,
+ "account-2",
+ &bc))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+ }
+ else
+ {
+ TALER_LOG_DEBUG ("Running against the Pybank.\n");
+ cfgfilename = CONFIG_FILE_PYBANK;
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_bank (CONFIG_FILE_PYBANK,
+ "account-2",
+ &bc))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+
+ if (NULL == (bankd = TALER_TESTING_run_bank (CONFIG_FILE_PYBANK,
+ bc.exchange_auth.
+ wire_gateway_url)))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+ }
+
+ rv = (GNUNET_OK == TALER_TESTING_setup (&run,
+ NULL,
+ cfgfilename,
+ NULL,
+ GNUNET_NO)) ? 0 : 1;
+ if (GNUNET_NO == with_fakebank)
+ {
+
+ GNUNET_OS_process_kill (bankd,
+ SIGKILL);
+ GNUNET_OS_process_wait (bankd);
+ GNUNET_OS_process_destroy (bankd);
+ }
+ return rv;
+}
+
+
+/* end of test_bank_api.c */
diff --git a/src/lib/test_bank_api_fakebank.conf b/src/testing/test_bank_api_fakebank.conf
diff --git a/src/lib/test_bank_api_fakebank_twisted.conf b/src/testing/test_bank_api_fakebank_twisted.conf
diff --git a/src/lib/test_bank_api_pybank.conf b/src/testing/test_bank_api_pybank.conf
diff --git a/src/lib/test_bank_api_pybank_twisted.conf b/src/testing/test_bank_api_pybank_twisted.conf
diff --git a/src/testing/test_bank_api_twisted.c b/src/testing/test_bank_api_twisted.c
@@ -0,0 +1,221 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 testing/test_bank_api_with_fakebank_twisted.c
+ * @author Marcello Stanisci
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+#include <taler/taler_twister_testing_lib.h>
+#include <taler/taler_twister_service.h>
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE_FAKEBANK "test_bank_api_fakebank_twisted.conf"
+
+/**
+ * Separate config file for running with the pybank.
+ */
+#define CONFIG_FILE_PYBANK "test_bank_api_pybank_twisted.conf"
+
+/**
+ * True when the test runs against Fakebank.
+ */
+static int with_fakebank;
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * (real) Twister URL. Used at startup time to check if it runs.
+ */
+static char *twister_url;
+
+/**
+ * Twister process.
+ */
+static struct GNUNET_OS_Process *twisterd;
+
+/**
+ * Python bank process handle.
+ */
+static struct GNUNET_OS_Process *bankd;
+
+
+/**
+ * Main function that will tell
+ * the interpreter what commands to run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+
+ struct TALER_TESTING_Command commands[] = {
+ /**
+ * Can't use the "wait service" CMD here because the
+ * fakebank runs inside the same process of the test.
+ */
+ TALER_TESTING_cmd_wait_service ("wait-service",
+ twister_url),
+ TALER_TESTING_cmd_bank_credits ("history-0",
+ &bc.exchange_auth,
+ NULL,
+ 5),
+ TALER_TESTING_cmd_end ()
+ };
+
+ if (GNUNET_YES == with_fakebank)
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_url);
+ else
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+/**
+ * Kill, wait, and destroy convenience function.
+ *
+ * @param process process to purge.
+ */
+static void
+purge_process (struct GNUNET_OS_Process *process)
+{
+ GNUNET_OS_process_kill (process, SIGINT);
+ GNUNET_OS_process_wait (process);
+ GNUNET_OS_process_destroy (process);
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ unsigned int ret;
+ const char *cfgfilename;
+
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test-bank-api-with-(fake)bank-twisted",
+ "DEBUG",
+ NULL);
+
+ with_fakebank = TALER_TESTING_has_in_name (argv[0],
+ "_with_fakebank");
+
+ if (with_fakebank)
+ cfgfilename = CONFIG_FILE_FAKEBANK;
+ else
+ cfgfilename = CONFIG_FILE_PYBANK;
+
+ if (NULL == (twister_url = TALER_TESTING_prepare_twister
+ (cfgfilename)))
+ {
+ GNUNET_break (0);
+ return 77;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "twister_url is %s\n",
+ twister_url);
+ if (NULL == (twisterd = TALER_TESTING_run_twister (cfgfilename)))
+ {
+ GNUNET_break (0);
+ GNUNET_free (twister_url);
+ return 77;
+ }
+
+ if (GNUNET_YES == with_fakebank)
+ {
+ TALER_LOG_DEBUG ("Running against the Fakebank.\n");
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (cfgfilename,
+ "account-2",
+ &bc))
+ {
+ GNUNET_break (0);
+ GNUNET_free (twister_url);
+ return 77;
+ }
+ }
+ else
+ {
+ TALER_LOG_DEBUG ("Running against the Pybank.\n");
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_bank (cfgfilename,
+ "account-2",
+ &bc))
+ {
+ GNUNET_break (0);
+ GNUNET_free (twister_url);
+ return 77;
+ }
+
+ if (NULL == (bankd = TALER_TESTING_run_bank (cfgfilename,
+ bc.exchange_auth.
+ wire_gateway_url)))
+ {
+ GNUNET_break (0);
+ GNUNET_free (twister_url);
+ return 77;
+ }
+ }
+
+ ret = TALER_TESTING_setup (&run,
+ NULL,
+ cfgfilename,
+ NULL,
+ GNUNET_NO);
+ purge_process (twisterd);
+
+ if (GNUNET_NO == with_fakebank)
+ {
+ GNUNET_OS_process_kill (bankd,
+ SIGKILL);
+ GNUNET_OS_process_wait (bankd);
+ GNUNET_OS_process_destroy (bankd);
+ }
+
+ GNUNET_free (twister_url);
+ if (GNUNET_OK == ret)
+ return 0;
+
+ return 1;
+}
+
+
+/* end of test_bank_api_twisted.c */
diff --git a/src/testing/test_exchange_api.c b/src/testing/test_exchange_api.c
@@ -0,0 +1,832 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014--2020 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 testing/test_exchange_api.c
+ * @brief testcase to test exchange's HTTP API interface
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_exchange_api.conf"
+
+#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
+ "test_exchange_api_expire_reserve_now.conf"
+
+
+/**
+ * Exchange configuration data.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_WIREWATCH(label) \
+ TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
+
+/**
+ * Execute the taler-exchange-aggregator command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+#define CMD_EXEC_AGGREGATOR(label) \
+ TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE)
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ */
+#define CMD_TRANSFER_TO_EXCHANGE(label,amount) \
+ TALER_TESTING_cmd_admin_add_incoming (label, amount, \
+ &bc.exchange_auth, \
+ bc.user42_payto)
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ * @param is interpreter we use to run commands
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ /**
+ * Checks made against /wire response.
+ */
+ struct TALER_TESTING_Command wire[] = {
+ /**
+ * Check if 'x-taler-bank' wire method is offered
+ * by the exchange.
+ */
+ TALER_TESTING_cmd_wire ("wire-taler-bank-1",
+ "x-taler-bank",
+ NULL,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ /**
+ * Test withdrawal plus spending.
+ */
+ struct TALER_TESTING_Command withdraw[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "create-reserve-1"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-1"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Check the reserve is depleted.
+ */
+ TALER_TESTING_cmd_status ("status-1",
+ "create-reserve-1",
+ "EUR:0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command spend[] = {
+ /**
+ * Spend the coin.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-simple",
+ "withdraw-coin-1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Try to overdraw.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_CONFLICT),
+ /**
+ * Try to double spend using different wire details.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-double-1",
+ "withdraw-coin-1",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_CONFLICT),
+ /* Try to double spend using a different transaction id.
+ * The test needs the contract terms to differ. This
+ * is currently the case because of the "timestamp" field,
+ * which is set automatically by #TALER_TESTING_cmd_deposit().
+ * This could theoretically fail if at some point a deposit
+ * command executs in less than 1 ms. *///
+ TALER_TESTING_cmd_deposit ("deposit-double-1",
+ "withdraw-coin-1",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_CONFLICT),
+ /**
+ * Try to double spend with different proposal.
+ */
+ TALER_TESTING_cmd_deposit ("deposit-double-2",
+ "withdraw-coin-1",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command refresh[] = {
+ /* Fill reserve with EUR:5, 1ct is for fees. */
+ CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("ck-refresh-create-reserve-1",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "refresh-create-reserve-1"),
+ /**
+ * Make previous command effective.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-2"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("refresh-withdraw-coin-1",
+ "refresh-create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin
+ * (in full) (merchant would receive EUR:0.99 due to 1 ct
+ * deposit fee) *///
+ TALER_TESTING_cmd_deposit ("refresh-deposit-partial",
+ "refresh-withdraw-coin-1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Melt the rest of the coin's value
+ * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
+ TALER_TESTING_cmd_refresh_melt_double ("refresh-melt-1",
+ "refresh-withdraw-coin-1",
+ MHD_HTTP_OK,
+ NULL),
+ /**
+ * Complete (successful) melt operation, and
+ * withdraw the coins
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1",
+ "refresh-melt-1",
+ MHD_HTTP_OK),
+ /**
+ * Do it again to check idempotency
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1-idempotency",
+ "refresh-melt-1",
+ MHD_HTTP_OK),
+ /**
+ * Test that /refresh/link works
+ */
+ TALER_TESTING_cmd_refresh_link ("refresh-link-1",
+ "refresh-reveal-1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1a",
+ "refresh-reveal-1-idempotency",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Try to spend a refreshed EUR:0.1 coin
+ */
+ TALER_TESTING_cmd_deposit ("refresh-deposit-refreshed-1b",
+ "refresh-reveal-1",
+ 3,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":3}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.1",
+ MHD_HTTP_OK),
+ /* Test running a failing melt operation (same operation
+ * again must fail) */
+ TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing",
+ "refresh-withdraw-coin-1",
+ MHD_HTTP_CONFLICT,
+ NULL),
+ /* Test running a failing melt operation (on a coin that
+ was itself revealed and subsequently deposited) */
+ TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing-2",
+ "refresh-reveal-1",
+ MHD_HTTP_CONFLICT,
+ NULL),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command track[] = {
+ /* Try resolving a deposit's WTID, as we never triggered
+ * execution of transactions, the answer should be that
+ * the exchange knows about the deposit, but has no WTID yet.
+ *///
+ TALER_TESTING_cmd_track_transaction ("deposit-wtid-found",
+ "deposit-simple",
+ 0,
+ MHD_HTTP_ACCEPTED,
+ NULL),
+ /* Try resolving a deposit's WTID for a failed deposit.
+ * As the deposit failed, the answer should be that the
+ * exchange does NOT know about the deposit.
+ *///
+ TALER_TESTING_cmd_track_transaction ("deposit-wtid-failing",
+ "deposit-double-2",
+ 0,
+ MHD_HTTP_NOT_FOUND,
+ NULL),
+ /* Try resolving an undefined (all zeros) WTID; this
+ * should fail as obviously the exchange didn't use that
+ * WTID value for any transaction.
+ *///
+ TALER_TESTING_cmd_track_transfer_empty ("wire-deposit-failing",
+ NULL,
+ 0,
+ MHD_HTTP_NOT_FOUND),
+ /* Run transfers. Note that _actual_ aggregation will NOT
+ * happen here, as each deposit operation is run with a
+ * fresh merchant public key, so the aggregator will treat
+ * them as "different" merchants and do the wire transfers
+ * individually. *///
+ CMD_EXEC_AGGREGATOR ("run-aggregator"),
+ /**
+ * Check all the transfers took place.
+ */
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-499c",
+ ec.exchange_url,
+ "EUR:4.98",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c1",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c2",
+ ec.exchange_url,
+ "EUR:0.98",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-99c",
+ ec.exchange_url,
+ "EUR:0.08",
+ bc.exchange_payto,
+ bc.user43_payto),
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
+ TALER_TESTING_cmd_track_transaction ("deposit-wtid-ok",
+ "deposit-simple",
+ 0,
+ MHD_HTTP_OK,
+ "check_bank_transfer-499c"),
+ TALER_TESTING_cmd_track_transfer ("wire-deposit-success-bank",
+ "check_bank_transfer-99c1",
+ 0,
+ MHD_HTTP_OK,
+ "EUR:0.98",
+ "EUR:0.01"),
+ TALER_TESTING_cmd_track_transfer ("wire-deposits-success-wtid",
+ "deposit-wtid-ok",
+ 0,
+ MHD_HTTP_OK,
+ "EUR:4.98",
+ "EUR:0.01"),
+ TALER_TESTING_cmd_end ()
+ };
+
+
+ /**
+ * This block checks whether a wire deadline
+ * very far in the future does NOT get aggregated now.
+ */
+ struct TALER_TESTING_Command unaggregation[] = {
+ TALER_TESTING_cmd_check_bank_empty ("far-future-aggregation-a"),
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-unaggregated",
+ "EUR:5.01"),
+ /* "consume" reserve creation transfer. */
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check-create-reserve-unaggregated",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "create-reserve-unaggregated"),
+ CMD_EXEC_WIREWATCH ("wirewatch-unaggregated"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-unaggregated",
+ "create-reserve-unaggregated",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-unaggregated",
+ "withdraw-coin-unaggregated",
+ 0,
+ bc.user43_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_YEARS,
+ 3000),
+ "EUR:5",
+ MHD_HTTP_OK),
+ CMD_EXEC_AGGREGATOR ("aggregation-attempt"),
+
+ TALER_TESTING_cmd_check_bank_empty
+ ("far-future-aggregation-b"),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command refund[] = {
+ /**
+ * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
+ * config.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-r1",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-r1",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "create-reserve-r1"),
+ /**
+ * Run wire-watch to trigger the reserve creation.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-3"),
+ /* Withdraw a 5 EUR coin, at fee of 1 ct */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-r1",
+ "create-reserve-r1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Spend 5 EUR of the 5 EUR coin (in full) (merchant would
+ * receive EUR:4.99 due to 1 ct deposit fee)
+ */
+ TALER_TESTING_cmd_deposit ("deposit-refund-1",
+ "withdraw-coin-r1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_MINUTES,
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Run transfers. Should do nothing as refund deadline blocks it
+ */
+ CMD_EXEC_AGGREGATOR ("run-aggregator-refund"),
+ /* Check that aggregator didn't do anything, as expected.
+ * Note, this operation takes two commands: one to "flush"
+ * the preliminary transfer (used to withdraw) from the
+ * fakebank and the second to actually check there are not
+ * other transfers around. *///
+ TALER_TESTING_cmd_check_bank_empty ("check_bank_transfer-pre-refund"),
+ TALER_TESTING_cmd_refund ("refund-ok",
+ MHD_HTTP_OK,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-1"),
+ TALER_TESTING_cmd_refund ("refund-ok-double",
+ MHD_HTTP_OK,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-1"),
+ /* Previous /refund(s) had id == 0. */
+ TALER_TESTING_cmd_refund_with_id ("refund-conflicting",
+ MHD_HTTP_CONFLICT,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-1",
+ 1),
+ /**
+ * Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone
+ * due to refund) (merchant would receive EUR:4.98 due to
+ * 1 ct deposit fee) */
+ TALER_TESTING_cmd_deposit ("deposit-refund-2",
+ "withdraw-coin-r1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"more ice cream\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:4.99",
+ MHD_HTTP_OK),
+ /**
+ * Run transfers. This will do the transfer as refund deadline
+ * was 0
+ */
+ CMD_EXEC_AGGREGATOR ("run-aggregator-3"),
+ /**
+ * Check that deposit did run.
+ */
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_transfer-pre-refund",
+ ec.exchange_url,
+ "EUR:4.97",
+ bc.exchange_payto,
+ bc.user42_payto),
+ /**
+ * Run failing refund, as past deadline & aggregation.
+ */
+ TALER_TESTING_cmd_refund ("refund-fail",
+ MHD_HTTP_GONE,
+ "EUR:4.99",
+ "EUR:0.01",
+ "deposit-refund-2"),
+ TALER_TESTING_cmd_check_bank_empty ("check-empty-after-refund"),
+ /**
+ * Test refunded coins are never executed, even past
+ * refund deadline
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("create-reserve-rb",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-rb",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "create-reserve-rb"),
+ CMD_EXEC_WIREWATCH ("wirewatch-rb"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb",
+ "create-reserve-rb",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("deposit-refund-1b",
+ "withdraw-coin-rb",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Trigger refund (before aggregator had a chance to execute
+ * deposit, even though refund deadline was zero).
+ */
+ TALER_TESTING_cmd_refund ("refund-ok-fast",
+ MHD_HTTP_OK,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-1b"),
+ /**
+ * Run transfers. This will do the transfer as refund deadline
+ * was 0, except of course because the refund succeeded, the
+ * transfer should no longer be done.
+ */CMD_EXEC_AGGREGATOR ("run-aggregator-3b"),
+ /* check that aggregator didn't do anything, as expected */
+ TALER_TESTING_cmd_check_bank_empty ("check-refund-fast-not-run"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command recoup[] = {
+ /**
+ * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
+ * config.
+ */
+ CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-1",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("recoup-create-reserve-1",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "recoup-create-reserve-1"),
+ /**
+ * Run wire-watch to trigger the reserve creation.
+ */
+ CMD_EXEC_WIREWATCH ("wirewatch-4"),
+ /* Withdraw a 5 EUR coin, at fee of 1 ct */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-1",
+ "recoup-create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /* Make coin invalid */
+ TALER_TESTING_cmd_revoke ("revoke-0-EUR:5",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-1",
+ CONFIG_FILE),
+ /* Refund coin to bank account */
+ TALER_TESTING_cmd_recoup ("recoup-1",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-1",
+ "EUR:5",
+ NULL),
+ /* Check the money is back with the reserve */
+ TALER_TESTING_cmd_status ("recoup-reserve-status-1",
+ "recoup-create-reserve-1",
+ "EUR:5.0",
+ MHD_HTTP_OK),
+ /* Re-withdraw from this reserve */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2",
+ "recoup-create-reserve-1",
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * This withdrawal will test the logic to create a "recoup"
+ * element to insert into the reserve's history.
+ */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2-over",
+ "recoup-create-reserve-1",
+ "EUR:10",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_status ("recoup-reserve-status-2",
+ "recoup-create-reserve-1",
+ "EUR:3.99",
+ MHD_HTTP_OK),
+
+ /* These commands should close the reserve because
+ * the aggregator is given a config file that ovverrides
+ * the reserve expiration time (making it now-ish) */
+ CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
+ "EUR:5.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-short-lived-reserve",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "short-lived-reserve"),
+ TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
+ CONFIG_FILE_EXPIRE_RESERVE_NOW),
+
+ TALER_TESTING_cmd_exec_aggregator ("close-reserves",
+ CONFIG_FILE_EXPIRE_RESERVE_NOW),
+
+ TALER_TESTING_cmd_status ("short-lived-status",
+ "short-lived-reserve",
+ "EUR:0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("expired-withdraw",
+ "short-lived-reserve",
+ "EUR:1",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_reimburse",
+ ec.exchange_url,
+ "EUR:5",
+ bc.exchange_payto,
+ bc.user42_payto),
+ /* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
+ * config, then withdraw two coin, partially spend one, and
+ * then have the rest paid back. Check deposit of other coin
+ * fails. Do not use EUR:5 here as the EUR:5 coin was
+ * revoked and we did not bother to create a new one... *///
+ CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-2",
+ "EUR:2.02"),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("ck-recoup-create-reserve-2",
+ "EUR:2.02",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "recoup-create-reserve-2"),
+ /* Make previous command effective. */
+ CMD_EXEC_WIREWATCH ("wirewatch-5"),
+ /* Withdraw a 1 EUR coin, at fee of 1 ct */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2a",
+ "recoup-create-reserve-2",
+ "EUR:1",
+ MHD_HTTP_OK),
+ /* Withdraw a 1 EUR coin, at fee of 1 ct */
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-2b",
+ "recoup-create-reserve-2",
+ "EUR:1",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit ("recoup-deposit-partial",
+ "recoup-withdraw-coin-2a",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_revoke ("revoke-1-EUR:1",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-2a",
+ CONFIG_FILE),
+ TALER_TESTING_cmd_recoup ("recoup-2",
+ MHD_HTTP_OK,
+ "recoup-withdraw-coin-2a",
+ "EUR:0.5",
+ NULL),
+ TALER_TESTING_cmd_recoup ("recoup-2b",
+ MHD_HTTP_CONFLICT,
+ "recoup-withdraw-coin-2a",
+ "EUR:0.5",
+ NULL),
+ TALER_TESTING_cmd_deposit ("recoup-deposit-revoked",
+ "recoup-withdraw-coin-2b",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_NOT_FOUND),
+ /* Test deposit fails after recoup, with proof in recoup */
+
+ /* Note that, the exchange will never return the coin's transaction
+ * history with recoup data, as we get a 404 on the DK! */
+ TALER_TESTING_cmd_deposit ("recoup-deposit-partial-after-recoup",
+ "recoup-withdraw-coin-2a",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.5",
+ MHD_HTTP_NOT_FOUND),
+ /* Test that revoked coins cannot be withdrawn */
+ CMD_TRANSFER_TO_EXCHANGE ("recoup-create-reserve-3",
+ "EUR:1.01"),
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "check-recoup-create-reserve-3",
+ "EUR:1.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "recoup-create-reserve-3"),
+ CMD_EXEC_WIREWATCH ("wirewatch-6"),
+ TALER_TESTING_cmd_withdraw_amount ("recoup-withdraw-coin-3-revoked",
+ "recoup-create-reserve-3",
+ "EUR:1",
+ MHD_HTTP_NOT_FOUND),
+ /* check that we are empty before the rejection test */
+ TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
+
+ TALER_TESTING_cmd_end ()
+ };
+
+#define RESERVE_OPEN_CLOSE_CHUNK 4
+#define RESERVE_OPEN_CLOSE_ITERATIONS 3
+
+ struct TALER_TESTING_Command reserve_open_close[(RESERVE_OPEN_CLOSE_ITERATIONS
+ * RESERVE_OPEN_CLOSE_CHUNK)
+ + 1];
+ for (unsigned int i = 0;
+ i < RESERVE_OPEN_CLOSE_ITERATIONS;
+ i++)
+ {
+ reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 0]
+ = CMD_TRANSFER_TO_EXCHANGE ("reserve-open-close-key",
+ "EUR:20");
+ reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1]
+ = TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch",
+ CONFIG_FILE_EXPIRE_RESERVE_NOW);
+ reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2]
+ = TALER_TESTING_cmd_exec_aggregator ("reserve-open-close-aggregation",
+ CONFIG_FILE_EXPIRE_RESERVE_NOW);
+ reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 3]
+ = TALER_TESTING_cmd_status ("reserve-open-close-status",
+ "reserve-open-close-key",
+ "EUR:0",
+ MHD_HTTP_OK);
+ }
+ reserve_open_close[RESERVE_OPEN_CLOSE_ITERATIONS * RESERVE_OPEN_CLOSE_CHUNK]
+ = TALER_TESTING_cmd_end ();
+
+ {
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_batch ("wire",
+ wire),
+ TALER_TESTING_cmd_batch ("withdraw",
+ withdraw),
+ TALER_TESTING_cmd_batch ("spend",
+ spend),
+ TALER_TESTING_cmd_batch ("refresh",
+ refresh),
+ TALER_TESTING_cmd_batch ("track",
+ track),
+ TALER_TESTING_cmd_batch ("unaggregation",
+ unaggregation),
+ TALER_TESTING_cmd_batch ("refund",
+ refund),
+ TALER_TESTING_cmd_batch ("recoup",
+ recoup),
+ TALER_TESTING_cmd_batch ("reserve-open-close",
+ reserve_open_close),
+ /* End the suite. */
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_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-exchange-api",
+ "INFO",
+ NULL);
+ /* Check fakebank port is available and get config */
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "account-2",
+ &bc))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+ /* @helpers. Run keyup, create tables, ... Note: it
+ * fetches the port number from config in order to see
+ * if it's available. */
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (GNUNET_OK !=
+ /* Set up event loop and reschedule context, plus
+ * start/stop the exchange. It calls TALER_TESTING_setup
+ * which creates the 'is' object.
+ */
+ TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE))
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_exchange_api.c */
diff --git a/src/lib/test_exchange_api.conf b/src/testing/test_exchange_api.conf
diff --git a/src/lib/test_exchange_api_expire_reserve_now.conf b/src/testing/test_exchange_api_expire_reserve_now.conf
diff --git a/src/lib/test_exchange_api_home/.config/taler/account-1.json b/src/testing/test_exchange_api_home/.config/taler/account-1.json
diff --git a/src/lib/test_exchange_api_home/.config/taler/account-2.json b/src/testing/test_exchange_api_home/.config/taler/account-2.json
diff --git a/src/lib/test_exchange_api_home/.config/taler/sepa.json b/src/testing/test_exchange_api_home/.config/taler/sepa.json
diff --git a/src/lib/test_exchange_api_home/.config/taler/test.json b/src/testing/test_exchange_api_home/.config/taler/test.json
diff --git a/src/lib/test_exchange_api_home/.config/taler/x-taler-bank.json b/src/testing/test_exchange_api_home/.config/taler/x-taler-bank.json
diff --git a/src/lib/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_exchange_api_home/.local/share/taler/exchange/offline-keys/master.priv
diff --git a/src/testing/test_exchange_api_interpreter_on-off.c b/src/testing/test_exchange_api_interpreter_on-off.c
@@ -0,0 +1,128 @@
+/*
+ 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 testing/test_exchange_api_keys_cherry_picking_new.c
+ * @brief testcase to test exchange's /keys cherry picking ability
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+/**
+ * XXX:
+ *
+ * This test helps in finding a way to use/modify the "normal"
+ * cert_cb to handle reconnections from serialized states as well.
+ *
+ * 1st step: simply turn the interpreter off and on again.
+ * 2nd step: turn the interpreter off and give a serial state
+ * to reconnect.
+ */
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
+
+/**
+ * Exchange base URL; mainly purpose is to make the compiler happy.
+ */
+static char *exchange_url;
+
+/**
+ * Auditor base URL; mainly purpose is to make the compiler happy.
+ */
+static char *auditor_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)
+{
+
+ struct TALER_TESTING_Command commands[] = {
+
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+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-exchange-api-cherry-picking-new",
+ "DEBUG", NULL);
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+ /* @helpers. Run keyup, create tables, ... Note: it
+ * fetches the port number from config in order to see
+ * if it's available. */
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &auditor_url,
+ &exchange_url))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (GNUNET_OK !=
+ /* Set up event loop and reschedule context, plus
+ * start/stop the exchange. It calls TALER_TESTING_setup
+ * which creates the 'is' object.
+ */
+ TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE))
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_exchange_api_keys_cherry_picking_new.c */
diff --git a/src/testing/test_exchange_api_keys_cherry_picking.c b/src/testing/test_exchange_api_keys_cherry_picking.c
@@ -0,0 +1,263 @@
+/*
+ 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 testing/test_exchange_api_keys_cherry_picking.c
+ * @brief testcase to test exchange's /keys cherry picking ability
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
+
+/**
+ * Used to increase the number of denomination keys.
+ */
+#define CONFIG_FILE_EXTENDED \
+ "test_exchange_api_keys_cherry_picking_extended.conf"
+
+/**
+ * Used to increase the number of denomination keys.
+ */
+#define CONFIG_FILE_EXTENDED_2 \
+ "test_exchange_api_keys_cherry_picking_extended_2.conf"
+
+
+#define NDKS_RIGHT_BEFORE_SERIALIZATION 46
+
+/**
+ * Add seconds.
+ *
+ * @param base absolute time to add seconds to.
+ * @param relative number of seconds to add.
+ * @return a new absolute time, modified according to @e relative.
+ */
+#define ADDSECS(base, secs) \
+ GNUNET_TIME_absolute_add \
+ (base, \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+ secs))
+
+/**
+ * Subtract seconds.
+ *
+ * @param base absolute time to subtract seconds to.
+ * @param secs relative number of _seconds_ to subtract.
+ * @return a new absolute time, modified according to @e relative.
+ */
+#define SUBSECS(base, secs) \
+ GNUNET_TIME_absolute_subtract \
+ (base, \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
+ secs))
+#define JAN1971 "1971-01-01"
+#define JAN2030 "2030-01-01"
+
+/**
+ * Exchange configuration data.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+
+/**
+ * Wrapper around the time parser.
+ *
+ * @param str human-readable time string.
+ * @return the parsed time from @a str.
+ */
+static struct GNUNET_TIME_Absolute
+TTH_parse_time (const char *str)
+{
+ struct GNUNET_TIME_Absolute ret;
+
+ GNUNET_assert
+ (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_absolute (str,
+ &ret));
+ return ret;
+}
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ * @param is[in,out] interpreter state
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command keys_serialization[] = {
+ TALER_TESTING_cmd_serialize_keys
+ ("serialize-keys"),
+ TALER_TESTING_cmd_connect_with_state
+ ("reconnect-with-state",
+ "serialize-keys"),
+ /**
+ * Make sure we have the same keys situation as
+ * it was before the serialization.
+ */
+ TALER_TESTING_cmd_check_keys_with_now
+ ("check-keys-after-deserialization",
+ 4,
+ NDKS_RIGHT_BEFORE_SERIALIZATION,
+ /**
+ * Pretend 5 seconds passed.
+ */
+ ADDSECS (TTH_parse_time (JAN2030),
+ 5)),
+ /**
+ * Use one of the deserialized keys.
+ */
+ TALER_TESTING_cmd_wire
+ ("verify-/wire-with-serialized-keys",
+ "x-taler-bank",
+ NULL,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end (),
+ };
+
+ struct TALER_TESTING_Command ordinary_cherry_pick[] = {
+ /**
+ * 1 DK with 80s withdraw duration, lookahead_sign is 60s
+ * => expect 1 DK.
+ */
+ TALER_TESTING_cmd_check_keys ("check-keys-1",
+ 1, /* generation */
+ 1),
+ /**
+ * The far-future now will cause "keyup" to start a fresh
+ * key set. The new KS will have only one key, because the
+ * current lookahead_sign == 60 seconds and the key's withdraw
+ * duration is 80 seconds.
+ */TALER_TESTING_cmd_exec_keyup_with_now
+ ("keyup-1",
+ CONFIG_FILE,
+ TTH_parse_time (JAN2030)),
+ /**
+ * Should return 1 new key, + the original one. NOTE: the
+ * original DK will never be 'cancelled' as for the current
+ * libtalerexchange logic, so it must always be counted.
+ */TALER_TESTING_cmd_check_keys_with_now
+ ("check-keys-2",
+ 2, /* generation */
+ 2,
+ TTH_parse_time (JAN2030)),
+ TALER_TESTING_cmd_exec_keyup_with_now
+ ("keyup-3",
+ CONFIG_FILE_EXTENDED_2,
+ /* Taking care of not using a 'now' that equals the
+ * last DK timestamp, otherwise it would get silently
+ * overridden. */
+ ADDSECS (TTH_parse_time (JAN2030),
+ 10)),
+
+ /**
+ * Expected number of DK:
+ *
+ * 3500 (the lookahead_sign time frame, in seconds)
+ * - 69 (how many seconds are covered by the latest DK)
+ * ----
+ * 3431
+ * / 79 (how many seconds each DK will cover)
+ * ----
+ * 44 (rounded up)
+ * + 2 (old DKs already stored locally: 1 from the
+ * very initial setup, and 1 from the 'keyup-1' CMD)
+ * ----
+ * 46
+ */TALER_TESTING_cmd_check_keys_with_now
+ ("check-keys-3",
+ 3,
+ NDKS_RIGHT_BEFORE_SERIALIZATION,
+ TTH_parse_time (JAN2030)),
+
+ TALER_TESTING_cmd_end ()
+ };
+ struct TALER_TESTING_Command commands[] = {
+
+ TALER_TESTING_cmd_batch ("ordinary-cherry-pick",
+ ordinary_cherry_pick),
+ TALER_TESTING_cmd_batch ("keys-serialization",
+ keys_serialization),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+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-exchange-api-cherry-picking",
+ "DEBUG",
+ NULL);
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+ /* @helpers. Run keyup, create tables, ... Note: it
+ * fetches the port number from config in order to see
+ * if it's available. */
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (GNUNET_OK !=
+ /* Set up event loop and reschedule context, plus
+ * start/stop the exchange. It calls TALER_TESTING_setup
+ * which creates the 'is' object.
+ */
+ TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE))
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_exchange_api_keys_cherry_picking.c */
diff --git a/src/lib/test_exchange_api_keys_cherry_picking.conf b/src/testing/test_exchange_api_keys_cherry_picking.conf
diff --git a/src/lib/test_exchange_api_keys_cherry_picking_extended.conf b/src/testing/test_exchange_api_keys_cherry_picking_extended.conf
diff --git a/src/lib/test_exchange_api_keys_cherry_picking_extended_2.conf b/src/testing/test_exchange_api_keys_cherry_picking_extended_2.conf
diff --git a/src/lib/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json b/src/testing/test_exchange_api_keys_cherry_picking_home/.config/taler/x-taler-bank.json
diff --git a/src/lib/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv
diff --git a/src/testing/test_exchange_api_overlapping_keys_bug.c b/src/testing/test_exchange_api_overlapping_keys_bug.c
@@ -0,0 +1,130 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018, 2019 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 testing/test_exchange_api_overlapping_keys_bug.c
+ * @brief testcase to test exchange's /keys cherry picking ability and
+ * other /keys related operations
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
+
+/**
+ * Used to increase the number of denomination keys.
+ */
+#define CONFIG_FILE_EXTENDED \
+ "test_exchange_api_keys_cherry_picking_extended.conf"
+
+/**
+ * Used to increase the number of denomination keys.
+ */
+#define CONFIG_FILE_EXTENDED_2 \
+ "test_exchange_api_keys_cherry_picking_extended_2.conf"
+
+/**
+ * Exchange configuration data.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_check_keys ("first-download",
+ 1,
+ 1),
+ /* Causes GET /keys?last_denom_issue=0 */
+ TALER_TESTING_cmd_check_keys_with_last_denom ("second-download",
+ 3,
+ 1,
+ GNUNET_TIME_UNIT_ZERO_ABS),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+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-exchange-api-overlapping-keys-bug",
+ "DEBUG", NULL);
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+ /* @helpers. Run keyup, create tables, ... Note: it
+ * fetches the port number from config in order to see
+ * if it's available. */
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (GNUNET_OK !=
+ /* Set up event loop and reschedule context, plus
+ * start/stop the exchange. It calls TALER_TESTING_setup
+ * which creates the 'is' object.
+ */
+ TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE))
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_exchange_api_overlapping_keys_bug.c */
diff --git a/src/testing/test_exchange_api_revocation.c b/src/testing/test_exchange_api_revocation.c
@@ -0,0 +1,231 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014--2020 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 testing/test_exchange_api_revocation.c
+ * @brief testcase to test key revocation handling via the exchange's HTTP API interface
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_exchange_api.conf"
+
+/**
+ * Exchange configuration data.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command revocation[] = {
+ /**
+ * Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
+ * config.
+ */
+ TALER_TESTING_cmd_admin_add_incoming ("create-reserve-1",
+ "EUR:5.01",
+ &bc.exchange_auth,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_admin_transfer ("check-create-reserve-1",
+ "EUR:5.01",
+ bc.user42_payto,
+ bc.exchange_payto,
+ "create-reserve-1"),
+ /**
+ * Run wire-watch to trigger the reserve creation.
+ */
+ TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4",
+ CONFIG_FILE),
+ /* Withdraw a 5 EUR coin, at fee of 1 ct */
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /* Try to partially spend (deposit) 1 EUR of the 5 EUR coin (in full)
+ * (merchant would receive EUR:0.99 due to 1 ct deposit fee) *///
+ TALER_TESTING_cmd_deposit ("deposit-partial",
+ "withdraw-revocation-coin-1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+ /**
+ * Melt SOME of the rest of the coin's value
+ * (EUR:3.17 = 3x EUR:1.03 + 7x EUR:0.13) */
+ TALER_TESTING_cmd_refresh_melt ("refresh-melt-1",
+ "withdraw-revocation-coin-1",
+ MHD_HTTP_OK,
+ NULL),
+ /**
+ * Complete (successful) melt operation, and withdraw the coins
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-1",
+ "refresh-melt-1",
+ MHD_HTTP_OK),
+ /* Make refreshed coin invalid */
+ TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
+ MHD_HTTP_OK,
+ "refresh-melt-1",
+ CONFIG_FILE),
+ /* Refund coin to original coin */
+ TALER_TESTING_cmd_recoup ("recoup-1a",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#0",
+ "EUR:1",
+ "refresh-melt-1"),
+ TALER_TESTING_cmd_recoup ("recoup-1b",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#1",
+ "EUR:1",
+ "refresh-melt-1"),
+ TALER_TESTING_cmd_recoup ("recoup-1c",
+ MHD_HTTP_OK,
+ "refresh-reveal-1#2",
+ "EUR:1",
+ "refresh-melt-1"),
+ /* Now we have EUR:3.83 EUR back after 3x EUR:1 in recoups */
+ /* Melt original coin AGAIN, but only create one 0.1 EUR coin;
+ This costs EUR:0.03 in refresh and EUR:01 in withdraw fees,
+ leaving EUR:3.69. */
+ TALER_TESTING_cmd_refresh_melt ("refresh-melt-2",
+ "withdraw-revocation-coin-1",
+ MHD_HTTP_OK,
+ "EUR:0.1",
+ NULL),
+ /**
+ * Complete (successful) melt operation, and withdraw the coins
+ */
+ TALER_TESTING_cmd_refresh_reveal ("refresh-reveal-2",
+ "refresh-melt-2",
+ MHD_HTTP_OK),
+ /* Revokes refreshed EUR:0.1 coin */
+ TALER_TESTING_cmd_revoke ("revoke-3-EUR:0.1",
+ MHD_HTTP_OK,
+ "refresh-reveal-2",
+ CONFIG_FILE),
+ /* Revoke also original coin denomination */
+ TALER_TESTING_cmd_revoke ("revoke-4-EUR:5",
+ MHD_HTTP_OK,
+ "withdraw-revocation-coin-1",
+ CONFIG_FILE),
+ /* Refund coin EUR:0.1 to original coin, creating zombie! */
+ TALER_TESTING_cmd_recoup ("recoup-2",
+ MHD_HTTP_OK,
+ "refresh-reveal-2",
+ "EUR:0.1",
+ "refresh-melt-2"),
+ /* Due to recoup, original coin is now at EUR:3.79 */
+ /* Refund original (now zombie) coin to reserve */
+ TALER_TESTING_cmd_recoup ("recoup-3",
+ MHD_HTTP_OK,
+ "withdraw-revocation-coin-1",
+ "EUR:3.79",
+ NULL),
+ /* Check the money is back with the reserve */
+ TALER_TESTING_cmd_status ("recoup-reserve-status-1",
+ "create-reserve-1",
+ "EUR:3.79",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ revocation,
+ bc.exchange_auth.wire_gateway_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-exchange-api-revocation",
+ "INFO",
+ NULL);
+ /* Check fakebank port is available and get config */
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "account-2",
+ &bc))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+ /* @helpers. Run keyup, create tables, ... Note: it
+ * fetches the port number from config in order to see
+ * if it's available. */
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (GNUNET_OK !=
+ /* Set up event loop and reschedule context, plus
+ * start/stop the exchange. It calls TALER_TESTING_setup
+ * which creates the 'is' object.
+ */
+ TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE))
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_exchange_api_revocation.c */
diff --git a/src/testing/test_exchange_api_twisted.c b/src/testing/test_exchange_api_twisted.c
@@ -0,0 +1,332 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2020 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 testing/test_exchange_api_twisted.c
+ * @brief testcase to test exchange's HTTP API interface
+ * @author Marcello Stanisci
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_signatures.h"
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <microhttpd.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+#include <taler/taler_twister_testing_lib.h>
+#include <taler/taler_twister_service.h>
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_exchange_api_twisted.conf"
+
+/**
+ * (real) Twister URL. Used at startup time to check if it runs.
+ */
+static char *twister_url;
+
+/**
+ * Exchange configuration data.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Twister process.
+ */
+static struct GNUNET_OS_Process *twisterd;
+
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+static struct TALER_TESTING_Command
+CMD_EXEC_WIREWATCH (char *label)
+{
+ return TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE);
+}
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ * @param url exchange_url
+ */
+static struct TALER_TESTING_Command
+CMD_TRANSFER_TO_EXCHANGE (char *label, char *amount)
+{
+ return TALER_TESTING_cmd_admin_add_incoming (label,
+ amount,
+ &bc.exchange_auth,
+ bc.user42_payto);
+}
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ /**
+ * This batch aims to trigger the 409 Conflict
+ * response from a refresh-reveal operation.
+ */
+ struct TALER_TESTING_Command refresh_409_conflict[] = {
+ CMD_TRANSFER_TO_EXCHANGE
+ ("refresh-create-reserve",
+ "EUR:5.01"),
+ /**
+ * Make previous command effective.
+ */
+ CMD_EXEC_WIREWATCH
+ ("wirewatch"),
+ /**
+ * Withdraw EUR:5.
+ */
+ TALER_TESTING_cmd_withdraw_amount
+ ("refresh-withdraw-coin",
+ "refresh-create-reserve",
+ "EUR:5",
+ MHD_HTTP_OK),
+
+ TALER_TESTING_cmd_deposit
+ ("refresh-deposit-partial",
+ "refresh-withdraw-coin",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\",\
+ \"value\":\"EUR:1\"}]}",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ MHD_HTTP_OK),
+
+ /**
+ * Melt the rest of the coin's value
+ * (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
+ TALER_TESTING_cmd_refresh_melt
+ ("refresh-melt",
+ "refresh-withdraw-coin",
+ MHD_HTTP_OK,
+ NULL),
+ /* Trigger 409 Conflict. */
+ TALER_TESTING_cmd_flip_upload
+ ("flip-upload",
+ CONFIG_FILE,
+ "transfer_privs.0"),
+ TALER_TESTING_cmd_refresh_reveal
+ ("refresh-(flipped-)reveal",
+ "refresh-melt",
+ MHD_HTTP_CONFLICT),
+
+ TALER_TESTING_cmd_end ()
+
+ };
+
+
+ /**
+ * NOTE: not all CMDs actually need the twister,
+ * so it may be better to move those into the "main"
+ * lib test suite.
+ */struct TALER_TESTING_Command refund[] = {
+
+ CMD_TRANSFER_TO_EXCHANGE
+ ("create-reserve-r1",
+ "EUR:5.01"),
+ CMD_EXEC_WIREWATCH
+ ("wirewatch-r1"),
+ TALER_TESTING_cmd_withdraw_amount
+ ("withdraw-coin-r1",
+ "create-reserve-r1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_deposit
+ ("deposit-refund-1",
+ "withdraw-coin-r1",
+ 0,
+ bc.user42_payto,
+ "{\"items\":[{\"name\":\"ice cream\","
+ "\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_MINUTES,
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_refund
+ ("refund-currency-missmatch",
+ MHD_HTTP_PRECONDITION_FAILED,
+ "USD:5",
+ "USD:0.01",
+ "deposit-refund-1"),
+ TALER_TESTING_cmd_refund
+ ("refund-fee-above-amount",
+ MHD_HTTP_BAD_REQUEST,
+ "EUR:5",
+ "EUR:10",
+ "deposit-refund-1"),
+ TALER_TESTING_cmd_flip_upload
+ ("flip-upload",
+ CONFIG_FILE,
+ "merchant_sig"),
+ TALER_TESTING_cmd_refund
+ ("refund-bad-sig",
+ MHD_HTTP_FORBIDDEN,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-1"),
+
+ /* This next deposit CMD is only used to provide a
+ * good merchant signature to the next (failing) refund
+ * operations. */
+
+ TALER_TESTING_cmd_deposit
+ ("deposit-refund-to-fail",
+ "withdraw-coin-r1",
+ 0, /* coin index. */
+ bc.user42_payto,
+ /* This parameter will make any comparison about
+ h_contract_terms fail, when /refund will be handled.
+ So in other words, this is h_contract missmatch. */
+ "{\"items\":[{\"name\":\"ice skate\","
+ "\"value\":\"EUR:5\"}]}",
+ GNUNET_TIME_UNIT_MINUTES,
+ "EUR:5",
+ MHD_HTTP_CONFLICT),
+ TALER_TESTING_cmd_refund
+ ("refund-deposit-not-found",
+ MHD_HTTP_NOT_FOUND,
+ "EUR:5",
+ "EUR:0.01",
+ "deposit-refund-to-fail"),
+ TALER_TESTING_cmd_refund
+ ("refund-insufficient-funds",
+ MHD_HTTP_PRECONDITION_FAILED,
+ "EUR:50",
+ "EUR:0.01",
+ "deposit-refund-1"),
+ TALER_TESTING_cmd_refund
+ ("refund-fee-too-low",
+ MHD_HTTP_BAD_REQUEST,
+ "EUR:5",
+ "EUR:0.000001",
+ "deposit-refund-1"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command commands[] = {
+ TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict",
+ refresh_409_conflict),
+ TALER_TESTING_cmd_batch ("refund",
+ refund),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_url);
+}
+
+
+/**
+ * Kill, wait, and destroy convenience function.
+ *
+ * @param process process to purge.
+ */
+static void
+purge_process (struct GNUNET_OS_Process *process)
+{
+ GNUNET_OS_process_kill (process, SIGINT);
+ GNUNET_OS_process_wait (process);
+ GNUNET_OS_process_destroy (process);
+}
+
+
+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-exchange-api-twisted",
+ "DEBUG", NULL);
+
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "account-2",
+ &bc))
+ return 77;
+
+ if (NULL == (twister_url = TALER_TESTING_prepare_twister
+ (CONFIG_FILE)))
+ return 77;
+
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+
+ case GNUNET_OK:
+
+ if (NULL == (twisterd = TALER_TESTING_run_twister (CONFIG_FILE)))
+ return 77;
+
+ ret = TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE);
+ purge_process (twisterd);
+ GNUNET_free (twister_url);
+
+ if (GNUNET_OK != ret)
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_exchange_api_twisted.c */
diff --git a/src/lib/test_exchange_api_twisted.conf b/src/testing/test_exchange_api_twisted.conf
diff --git a/src/testing/test_taler_exchange_aggregator.c b/src/testing/test_taler_exchange_aggregator.c
@@ -0,0 +1,524 @@
+/*
+ This file is part of TALER
+ (C) 2016-2020 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 testing/test_taler_exchange_aggregator.c
+ * @brief Tests for taler-exchange-aggregator logic
+ * @author Christian Grothoff <christian@grothoff.org>
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_exchangedb_lib.h"
+#include <microhttpd.h>
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * Helper structure to keep exchange configuration values.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Contains plugin and session.
+ */
+static struct TALER_TESTING_DatabaseConnection dbc;
+
+/**
+ * Return value from main().
+ */
+static int result;
+
+/**
+ * Name of the configuration file to use.
+ */
+static char *config_filename;
+
+#define USER42_ACCOUNT "42"
+
+/**
+ * @return GNUNET_NO if database could not be prepared,
+ * otherwise GNUNET_OK
+ */
+static int
+prepare_database (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ dbc.plugin = TALER_EXCHANGEDB_plugin_load (cfg);
+ if (NULL == dbc.plugin)
+ {
+ GNUNET_break (0);
+ result = 77;
+ return GNUNET_NO;
+ }
+ if (GNUNET_OK !=
+ dbc.plugin->create_tables (dbc.plugin->cls))
+ {
+ GNUNET_break (0);
+ TALER_EXCHANGEDB_plugin_unload (dbc.plugin);
+ dbc.plugin = NULL;
+ result = 77;
+ return GNUNET_NO;
+ }
+ dbc.session = dbc.plugin->get_session (dbc.plugin->cls);
+ GNUNET_assert (NULL != dbc.session);
+
+ return GNUNET_OK;
+}
+
+
+/**
+ * Collects all the tests.
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command all[] = {
+
+ // check no aggregation happens on a empty database
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty-db",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
+
+ /* check aggregation happens on the simplest case:
+ one deposit into the database. */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-1",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-deposit-1",
+ config_filename),
+
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1",
+ ec.exchange_url,
+ "EUR:0.89",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-1"),
+
+ /* check aggregation accumulates well. */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-2a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ "EUR:0.1"),
+
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-2b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ "EUR:0.1"),
+
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-2",
+ config_filename),
+
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-2",
+ ec.exchange_url,
+ "EUR:1.79",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-2"),
+
+ /* check that different merchants stem different aggregations. */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-3a",
+ &dbc,
+ "bob",
+ "4",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-3b",
+ &dbc,
+ "bob",
+ "5",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-3c",
+ &dbc,
+ "alice",
+ "4",
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:1",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-3",
+ config_filename),
+
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3a",
+ ec.exchange_url,
+ "EUR:0.89",
+ bc.exchange_payto,
+ "payto://x-taler-bank/localhost/4"),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3b",
+ ec.exchange_url,
+ "EUR:0.89",
+ bc.exchange_payto,
+ "payto://x-taler-bank/localhost/4"),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-3c",
+ ec.exchange_url,
+ "EUR:0.89",
+ bc.exchange_payto,
+ "payto://x-taler-bank/localhost/5"),
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-after-3"),
+
+ /* checking that aggregator waits for the deadline. */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-4a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.2",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-4b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.2",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-early",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-4-fast"),
+
+ TALER_TESTING_cmd_sleep ("wait (5s)", 5),
+
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-4-delayed",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-4",
+ ec.exchange_url,
+ "EUR:0.19",
+ bc.exchange_payto,
+ bc.user42_payto),
+
+ // test picking all deposits at earliest deadline
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-5a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 10),
+ "EUR:0.2",
+ "EUR:0.1"),
+
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-5b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.2",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-early",
+ config_filename),
+
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-5-early"),
+ TALER_TESTING_cmd_sleep ("wait (5s)", 5),
+
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-5-delayed",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-5",
+ ec.exchange_url,
+ "EUR:0.19",
+ bc.exchange_payto,
+ bc.user42_payto),
+ /* Test NEVER running 'tiny' unless they make up minimum unit */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-6a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.102",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6a-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-6a-tiny"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-6b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.102",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-6c",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.102",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6c-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-6c-tiny"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-6d",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.102",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6d-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-6d-tiny"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-6e",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.112",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-6e",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-6",
+ ec.exchange_url,
+ "EUR:0.01",
+ bc.exchange_payto,
+ bc.user42_payto),
+
+ /* Test profiteering if wire deadline is short */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-7a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.109",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7a-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-7a-tiny"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-7b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.119",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-profit",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7",
+ ec.exchange_url,
+ "EUR:0.01",
+ bc.exchange_payto,
+ bc.user42_payto),
+
+ /* Now check profit was actually taken */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-7c",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.122",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-7-loss",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-7",
+ ec.exchange_url,
+ "EUR:0.01",
+ bc.exchange_payto,
+ bc.user42_payto),
+
+ /* Test that aggregation would happen fully if wire deadline is long */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-8a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.109",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8a-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-8a-tiny"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-8b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.109",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8b-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-8b-tiny"),
+
+ /* now trigger aggregate with large transaction and short deadline */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-8c",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.122",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-8",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-8",
+ ec.exchange_url,
+ "EUR:0.03",
+ bc.exchange_payto,
+ bc.user42_payto),
+
+ /* Test aggregation with fees and rounding profits. */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-9a",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.104",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9a-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-9a-tiny"),
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-9b",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 5),
+ "EUR:0.105",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9b-tiny",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty (
+ "expect-empty-transactions-after-9b-tiny"),
+
+ /* now trigger aggregate with large transaction and short deadline */
+ TALER_TESTING_cmd_insert_deposit ("do-deposit-9c",
+ &dbc,
+ "bob",
+ USER42_ACCOUNT,
+ GNUNET_TIME_UNIT_ZERO,
+ "EUR:0.112",
+ "EUR:0.1"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-deposit-9",
+ config_filename),
+ /* 0.009 + 0.009 + 0.022 - 0.001 - 0.002 - 0.008 = 0.029 => 0.02 */
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-9",
+ ec.exchange_url,
+ "EUR:0.01",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ all,
+ bc.exchange_auth.wire_gateway_url);
+}
+
+
+int
+main (int argc,
+ char *const argv[])
+{
+ const char *plugin_name;
+ char *testname;
+
+ if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ plugin_name++;
+ (void) GNUNET_asprintf (&testname,
+ "test-taler-exchange-aggregator-%s",
+ plugin_name);
+ (void) GNUNET_asprintf (&config_filename,
+ "%s.conf",
+ testname);
+
+ GNUNET_log_setup ("test_taler_exchange_aggregator",
+ "DEBUG",
+ NULL);
+
+ /* these might get in the way */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+
+ TALER_TESTING_cleanup_files (config_filename);
+
+ if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename,
+ &ec))
+ {
+ TALER_LOG_WARNING ("Could not prepare the exchange.\n");
+ return 77;
+ }
+
+ if (GNUNET_OK != TALER_TESTING_prepare_fakebank (config_filename,
+ "account-1",
+ &bc))
+ {
+ TALER_LOG_WARNING ("Could not prepare the fakebank\n");
+ return 77;
+ }
+
+ if (GNUNET_OK != GNUNET_CONFIGURATION_parse_and_run (config_filename,
+ &prepare_database,
+ NULL))
+ {
+ TALER_LOG_WARNING ("Could not prepare database for tests.\n");
+ return result;
+ }
+
+ result = TALER_TESTING_setup (&run,
+ NULL,
+ config_filename,
+ NULL, // no exchange process handle.
+ GNUNET_NO); // do not try to connect to the exchange
+
+ GNUNET_free (config_filename);
+ GNUNET_free (testname);
+ dbc.plugin->drop_tables (dbc.plugin->cls);
+ TALER_EXCHANGEDB_plugin_unload (dbc.plugin);
+ return GNUNET_OK == result ? 0 : 1;
+}
+
+
+/* end of test_taler_exchange_aggregator.c */
diff --git a/src/lib/test_taler_exchange_httpd_home/.config/taler/account-1.json b/src/testing/test_taler_exchange_httpd_home/.config/taler/account-1.json
diff --git a/src/lib/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_taler_exchange_httpd_home/.local/share/taler/exchange/offline-keys/master.priv
diff --git a/src/testing/test_taler_exchange_wirewatch.c b/src/testing/test_taler_exchange_wirewatch.c
@@ -0,0 +1,182 @@
+/*
+ This file is part of TALER
+ (C) 2016, 2017, 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 testing/test_taler_exchange_wirewatch.c
+ * @brief Tests for taler-exchange-wirewatch and taler-exchange-aggregator logic;
+ * Performs an invalid wire transfer to the exchange, and then checks that
+ * wirewatch immediately sends the money back.
+ * Then performs a valid wire transfer, waits for the reserve to expire,
+ * and then checks that the aggregator sends the money back.
+ * @author Christian Grothoff <christian@grothoff.org>
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include <gnunet/gnunet_json_lib.h>
+#include <gnunet/gnunet_pq_lib.h>
+#include "taler_json_lib.h"
+#include <microhttpd.h>
+#include "taler_fakebank_lib.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * Bank configuration data.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Helper structure to keep exchange configuration values.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Name of the configuration file to use.
+ */
+static char *config_filename;
+
+static struct TALER_TESTING_Command
+transfer_to_exchange (const char *label,
+ const char *amount)
+{
+ return TALER_TESTING_cmd_admin_add_incoming (label,
+ amount,
+ &bc.exchange_auth,
+ bc.user42_payto);
+}
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command all[] = {
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-on-start"),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-empty",
+ config_filename),
+ TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-empty",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_empty ("expect-transfers-empty-after-dry-run"),
+
+ transfer_to_exchange ("run-transfer-good-to-exchange",
+ "EUR:5"),
+ TALER_TESTING_cmd_exec_wirewatch ("run-wirewatch-on-good-transfer",
+ config_filename),
+
+ TALER_TESTING_cmd_check_bank_admin_transfer (
+ "clear-good-transfer-to-the-exchange",
+ "EUR:5",
+ bc.user42_payto, // debit
+ bc.exchange_payto, // credit
+ "run-transfer-good-to-exchange"),
+
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-non-expired-reserve",
+ config_filename),
+
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-1"),
+ TALER_TESTING_cmd_sleep ("wait (5s)",
+ 5),
+ TALER_TESTING_cmd_exec_aggregator ("run-aggregator-on-expired-reserve",
+ config_filename),
+ TALER_TESTING_cmd_check_bank_transfer ("expect-deposit-1",
+ ec.exchange_url,
+ "EUR:4.99",
+ bc.exchange_payto,
+ bc.user42_payto),
+ TALER_TESTING_cmd_check_bank_empty ("expect-empty-transactions-2"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ all,
+ bc.exchange_auth.wire_gateway_url);
+}
+
+
+int
+main (int argc,
+ char *const argv[])
+{
+ const char *plugin_name;
+
+ /* these might get in the way */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test_taler_exchange_wirewatch",
+ "DEBUG",
+ NULL);
+
+ if (NULL == (plugin_name = strrchr (argv[0], (int) '-')))
+ {
+ GNUNET_break (0);
+ return -1;
+ }
+ plugin_name++;
+ {
+ char *testname;
+
+ GNUNET_asprintf (&testname,
+ "test-taler-exchange-wirewatch-%s",
+ plugin_name);
+ GNUNET_asprintf (&config_filename,
+ "%s.conf",
+ testname);
+ GNUNET_free (testname);
+ }
+ /* check database is working */
+ {
+ struct GNUNET_PQ_Context *conn;
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+
+ conn = GNUNET_PQ_connect ("postgres:///talercheck",
+ NULL,
+ es,
+ NULL);
+ if (NULL == conn)
+ return 77;
+ GNUNET_PQ_disconnect (conn);
+ }
+
+ TALER_TESTING_cleanup_files (config_filename);
+ if (GNUNET_OK != TALER_TESTING_prepare_exchange (config_filename,
+ &ec))
+ {
+ TALER_LOG_INFO ("Could not prepare the exchange\n");
+ return 77;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (config_filename,
+ "account-1",
+ &bc))
+ return 77;
+
+ return
+ (GNUNET_OK == TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ config_filename)) ? 0 : 1;
+}
+
+
+/* end of test_taler_exchange_wirewatch.c */
diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c
@@ -0,0 +1,444 @@
+/*
+ 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 testing/testing_api_cmd_auditor_deposit_confirmation.c
+ * @brief command for testing /deposit_confirmation.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_auditor_service.h"
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "deposit confirmation" CMD.
+ */
+struct DepositConfirmationState
+{
+
+ /**
+ * Reference to any command that is able to provide a deposit.
+ */
+ const char *deposit_reference;
+
+ /**
+ * What is the deposited amount without the fee (i.e. the
+ * amount we expect in the deposit confirmation)?
+ */
+ const char *amount_without_fee;
+
+ /**
+ * Which coin of the @e deposit_reference should we confirm.
+ */
+ unsigned int coin_index;
+
+ /**
+ * DepositConfirmation handle while operation is running.
+ */
+ struct TALER_AUDITOR_DepositConfirmationHandle *dc;
+
+ /**
+ * Auditor connection.
+ */
+ struct TALER_AUDITOR_Handle *auditor;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Should we retry on (transient) failures?
+ */
+ int do_retry;
+
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+deposit_confirmation_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #deposit_confirmation_run.
+ *
+ * @param cls a `struct DepositConfirmationState`
+ */
+static void
+do_retry (void *cls)
+{
+ struct DepositConfirmationState *dcs = cls;
+
+ dcs->retry_task = NULL;
+ deposit_confirmation_run (dcs,
+ NULL,
+ dcs->is);
+}
+
+
+/**
+ * Callback to analyze the /deposit-confirmation response, just used
+ * to check if the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param obj raw response from the auditor.
+ */
+static void
+deposit_confirmation_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const json_t *obj)
+{
+ struct DepositConfirmationState *dcs = cls;
+
+ dcs->dc = NULL;
+ if (dcs->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == dcs->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying deposit confirmation failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ dcs->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ dcs->backoff = EXCHANGE_LIB_BACKOFF (dcs->backoff);
+ dcs->retry_task = GNUNET_SCHEDULER_add_delayed (dcs->backoff,
+ &do_retry,
+ dcs);
+ return;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ dcs->is->commands[dcs->is->ip].label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (obj, stderr, 0);
+ TALER_TESTING_interpreter_fail (dcs->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (dcs->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+deposit_confirmation_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct DepositConfirmationState *dcs = cls;
+ const struct TALER_TESTING_Command *deposit_cmd;
+ struct GNUNET_HashCode h_wire;
+ struct GNUNET_HashCode h_contract_terms;
+ struct GNUNET_TIME_Absolute timestamp;
+ struct GNUNET_TIME_Absolute refund_deadline;
+ struct TALER_Amount amount_without_fee;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ const struct TALER_MerchantPrivateKeyP *merchant_priv;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ const struct TALER_ExchangePublicKeyP *exchange_pub;
+ const struct TALER_ExchangeSignatureP *exchange_sig;
+ const json_t *wire_details;
+ const json_t *contract_terms;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_EXCHANGE_Keys *keys;
+ const struct TALER_EXCHANGE_SigningPublicKey *spk;
+
+ dcs->is = is;
+ GNUNET_assert (NULL != dcs->deposit_reference);
+ deposit_cmd
+ = TALER_TESTING_interpreter_lookup_command (is,
+ dcs->deposit_reference);
+ if (NULL == deposit_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_pub (deposit_cmd,
+ dcs->coin_index,
+ &exchange_pub));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_sig (deposit_cmd,
+ dcs->coin_index,
+ &exchange_sig));
+ keys = TALER_EXCHANGE_get_keys (dcs->is->exchange);
+ GNUNET_assert (NULL != keys);
+ spk = TALER_EXCHANGE_get_exchange_signing_key_info (keys,
+ exchange_pub);
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_contract_terms (deposit_cmd,
+ dcs->coin_index,
+ &contract_terms));
+ /* Very unlikely to fail */
+ GNUNET_assert (NULL != contract_terms);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_hash (contract_terms,
+ &h_contract_terms));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_wire_details (deposit_cmd,
+ dcs->coin_index,
+ &wire_details));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_merchant_wire_signature_hash (wire_details,
+ &h_wire));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_coin_priv (deposit_cmd,
+ dcs->coin_index,
+ &coin_priv));
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pub.eddsa_pub);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_merchant_priv (deposit_cmd,
+ dcs->coin_index,
+ &merchant_priv));
+ GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
+ &merchant_pub.eddsa_pub);
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (dcs->amount_without_fee,
+ &amount_without_fee));
+ /* timestamp is mandatory */
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_absolute_time ("timestamp", ×tamp),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (contract_terms,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ /* refund deadline is optional, defaults to zero */
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_absolute_time ("refund_deadline", &refund_deadline),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (contract_terms,
+ spec,
+ NULL, NULL))
+ {
+ refund_deadline = timestamp;
+ }
+ }
+ dcs->dc = TALER_AUDITOR_deposit_confirmation
+ (dcs->auditor,
+ &h_wire,
+ &h_contract_terms,
+ timestamp,
+ refund_deadline,
+ &amount_without_fee,
+ &coin_pub,
+ &merchant_pub,
+ exchange_pub,
+ exchange_sig,
+ &keys->master_pub,
+ spk->valid_from,
+ spk->valid_until,
+ spk->valid_legal,
+ &spk->master_sig,
+ &deposit_confirmation_cb,
+ dcs);
+
+ if (NULL == dcs->dc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ return;
+}
+
+
+/**
+ * Free the state of a "deposit_confirmation" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, a `struct DepositConfirmationState`
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+deposit_confirmation_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct DepositConfirmationState *dcs = cls;
+
+ if (NULL != dcs->dc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ dcs->is->ip,
+ cmd->label);
+ TALER_AUDITOR_deposit_confirmation_cancel (dcs->dc);
+ dcs->dc = NULL;
+ }
+ if (NULL != dcs->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (dcs->retry_task);
+ dcs->retry_task = NULL;
+ }
+ GNUNET_free (dcs);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret set to the wanted data.
+ * @param trait name of the trait.
+ * @param index index number of the traits to be returned.
+ *
+ * @return #GNUNET_OK on success
+ */
+static int
+deposit_confirmation_traits (void *cls,
+ const 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;
+}
+
+
+/**
+ * Create a "deposit-confirmation" command.
+ *
+ * @param label command label.
+ * @param auditor auditor connection.
+ * @param deposit_reference reference to any operation that can
+ * provide a coin.
+ * @param coin_index if @a deposit_reference offers an array of
+ * coins, this parameter selects which one in that array.
+ * This value is currently ignored, as only one-coin
+ * deposits are implemented.
+ * @param amount_without_fee deposited amount without the fee
+ * @param expected_response_code expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_deposit_confirmation (const char *label,
+ struct TALER_AUDITOR_Handle *auditor,
+ const char *deposit_reference,
+ unsigned int coin_index,
+ const char *amount_without_fee,
+ unsigned int expected_response_code)
+{
+ struct DepositConfirmationState *dcs;
+
+ dcs = GNUNET_new (struct DepositConfirmationState);
+ dcs->auditor = auditor;
+ dcs->deposit_reference = deposit_reference;
+ dcs->coin_index = coin_index;
+ dcs->amount_without_fee = amount_without_fee;
+ dcs->expected_response_code = expected_response_code;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = dcs,
+ .label = label,
+ .run = &deposit_confirmation_run,
+ .cleanup = &deposit_confirmation_cleanup,
+ .traits = &deposit_confirmation_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a deposit confirmation command to enable retries when we get
+ * transient errors from the auditor.
+ *
+ * @param cmd a deposit confirmation command
+ * @return the command with retries enabled
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_deposit_confirmation_with_retry (struct TALER_TESTING_Command
+ cmd)
+{
+ struct DepositConfirmationState *dcs;
+
+ GNUNET_assert (&deposit_confirmation_run == cmd.run);
+ dcs = cmd.cls;
+ dcs->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/* end of testing_auditor_api_cmd_deposit_confirmation.c */
diff --git a/src/testing/testing_api_cmd_auditor_exchanges.c b/src/testing/testing_api_cmd_auditor_exchanges.c
@@ -0,0 +1,361 @@
+/*
+ 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 testing/testing_api_cmd_auditor_exchanges.c
+ * @brief command for testing /exchanges of the auditor
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_auditor_service.h"
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "deposit confirmation" CMD.
+ */
+struct ExchangesState
+{
+
+ /**
+ * Exchanges handle while operation is running.
+ */
+ struct TALER_AUDITOR_ListExchangesHandle *leh;
+
+ /**
+ * Auditor connection.
+ */
+ struct TALER_AUDITOR_Handle *auditor;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * URL of the exchange expected to be included in the response.
+ */
+ const char *exchange_url;
+
+ /**
+ * Should we retry on (transient) failures?
+ */
+ int do_retry;
+
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+exchanges_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #exchanges_run.
+ *
+ * @param cls a `struct ExchangesState`
+ */
+static void
+do_retry (void *cls)
+{
+ struct ExchangesState *es = cls;
+
+ es->retry_task = NULL;
+ exchanges_run (es,
+ NULL,
+ es->is);
+}
+
+
+/**
+ * Callback to analyze the /exchanges response.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param num_exchanges length of the @a ei array
+ * @param ei array with information about the exchanges
+ * @param raw_response raw response from the auditor.
+ */
+static void
+exchanges_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ unsigned int num_exchanges,
+ const struct TALER_AUDITOR_ExchangeInfo *ei,
+ const json_t *raw_response)
+{
+ struct ExchangesState *es = cls;
+
+ es->leh = NULL;
+ if (es->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == es->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying list exchanges failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ es->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ es->backoff = EXCHANGE_LIB_BACKOFF (es->backoff);
+ es->retry_task = GNUNET_SCHEDULER_add_delayed (es->backoff,
+ &do_retry,
+ es);
+ return;
+ }
+ }
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ es->is->commands[es->is->ip].label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (raw_response, stderr, 0);
+ TALER_TESTING_interpreter_fail (es->is);
+ return;
+ }
+ if (NULL != es->exchange_url)
+ {
+ unsigned int found = GNUNET_NO;
+
+ for (unsigned int i = 0;
+ i<num_exchanges;
+ i++)
+ if (0 == strcmp (es->exchange_url,
+ ei[i].exchange_url))
+ found = GNUNET_YES;
+ if (GNUNET_NO == found)
+ {
+ TALER_LOG_ERROR
+ ("Exchange '%s' doesn't exist at this auditor\n",
+ es->exchange_url);
+ TALER_TESTING_interpreter_fail (es->is);
+ return;
+ }
+
+ TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n",
+ es->exchange_url);
+ }
+ TALER_TESTING_interpreter_next (es->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+exchanges_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ExchangesState *es = cls;
+
+ es->is = is;
+ es->leh = TALER_AUDITOR_list_exchanges
+ (is->auditor,
+ &exchanges_cb,
+ es);
+
+ if (NULL == es->leh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ return;
+}
+
+
+/**
+ * Free the state of a "exchanges" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, a `struct ExchangesState`
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+exchanges_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ExchangesState *es = cls;
+
+ if (NULL != es->leh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ es->is->ip,
+ cmd->label);
+ TALER_AUDITOR_list_exchanges_cancel (es->leh);
+ es->leh = NULL;
+ }
+ if (NULL != es->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (es->retry_task);
+ es->retry_task = NULL;
+ }
+ GNUNET_free (es);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret set to the wanted data.
+ * @param trait name of the trait.
+ * @param index index number of the traits to be returned.
+ * @return #GNUNET_OK on success
+ */
+static int
+exchanges_traits (void *cls,
+ const 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;
+}
+
+
+/**
+ * Create a "list exchanges" command.
+ *
+ * @param label command label.
+ * @param auditor auditor connection.
+ * @param expected_response_code expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exchanges (const char *label,
+ struct TALER_AUDITOR_Handle *auditor,
+ unsigned int expected_response_code)
+{
+ struct ExchangesState *es;
+
+ es = GNUNET_new (struct ExchangesState);
+ es->auditor = auditor;
+ es->expected_response_code = expected_response_code;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = es,
+ .label = label,
+ .run = &exchanges_run,
+ .cleanup = &exchanges_cleanup,
+ .traits = &exchanges_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Create a "list exchanges" command and check whether
+ * a particular exchange belongs to the returned bundle.
+ *
+ * @param label command label.
+ * @param expected_response_code expected HTTP response code.
+ * @param exchange_url URL of the exchange supposed to
+ * be included in the response.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exchanges_with_url (const char *label,
+ unsigned int expected_response_code,
+ const char *exchange_url)
+{
+ struct ExchangesState *es;
+
+ es = GNUNET_new (struct ExchangesState);
+ es->expected_response_code = expected_response_code;
+ es->exchange_url = exchange_url;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = es,
+ .label = label,
+ .run = &exchanges_run,
+ .cleanup = &exchanges_cleanup,
+ .traits = &exchanges_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify an exchanges command to enable retries when we get
+ * transient errors from the auditor.
+ *
+ * @param cmd a deposit confirmation command
+ * @return the command with retries enabled
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exchanges_with_retry (struct TALER_TESTING_Command cmd)
+{
+ struct ExchangesState *es;
+
+ GNUNET_assert (&exchanges_run == cmd.run);
+ es = cmd.cls;
+ es->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/* end of testing_auditor_api_cmd_exchanges.c */
diff --git a/src/testing/testing_api_cmd_auditor_exec_auditor.c b/src/testing/testing_api_cmd_auditor_exec_auditor.c
@@ -0,0 +1,165 @@
+/*
+ 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 testing/testing_api_cmd_auditor_exec_auditor.c
+ * @brief run the taler-auditor command
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "auditor" CMD.
+ */
+struct AuditorState
+{
+
+ /**
+ * Process for the "auditor" command.
+ */
+ struct GNUNET_OS_Process *auditor_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+};
+
+
+/**
+ * Run the command; calls the `taler-auditor' program.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+auditor_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AuditorState *ks = cls;
+
+ ks->auditor_proc
+ = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor",
+ "taler-auditor",
+ "-c", ks->config_filename,
+ NULL);
+ if (NULL == ks->auditor_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "auditor" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+auditor_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AuditorState *ks = cls;
+
+ if (NULL != ks->auditor_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ks->auditor_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ks->auditor_proc);
+ GNUNET_OS_process_destroy (ks->auditor_proc);
+ ks->auditor_proc = NULL;
+ }
+ GNUNET_free (ks);
+}
+
+
+/**
+ * Offer "auditor" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+auditor_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AuditorState *ks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0, &ks->auditor_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make the "exec-auditor" CMD.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_auditor (const char *label,
+ const char *config_filename)
+{
+ struct AuditorState *ks;
+
+ ks = GNUNET_new (struct AuditorState);
+ ks->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &auditor_run,
+ .cleanup = &auditor_cleanup,
+ .traits = &auditor_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_auditor_api_cmd_exec_auditor.c */
diff --git a/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c b/src/testing/testing_api_cmd_auditor_exec_auditor_dbinit.c
@@ -0,0 +1,166 @@
+/*
+ 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 testing/testing_api_cmd_auditor_exec_auditor_dbinit.c
+ * @brief run the taler-auditor-dbinit "-r" command
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "auditor-dbinit" CMD.
+ */
+struct AuditorDbinitState
+{
+
+ /**
+ * Process for the "auditor-dbinit" command.
+ */
+ struct GNUNET_OS_Process *auditor_dbinit_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+};
+
+
+/**
+ * Run the command; calls the `taler-auditor-dbinit' program.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+auditor_dbinit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AuditorDbinitState *ks = cls;
+
+ ks->auditor_dbinit_proc
+ = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-dbinit",
+ "taler-auditor-dbinit",
+ "-c", ks->config_filename,
+ "-r",
+ NULL);
+ if (NULL == ks->auditor_dbinit_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "auditor-dbinit" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+auditor_dbinit_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AuditorDbinitState *ks = cls;
+
+ if (NULL != ks->auditor_dbinit_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ks->auditor_dbinit_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ks->auditor_dbinit_proc);
+ GNUNET_OS_process_destroy (ks->auditor_dbinit_proc);
+ ks->auditor_dbinit_proc = NULL;
+ }
+ GNUNET_free (ks);
+}
+
+
+/**
+ * Offer "auditor-dbinit" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+auditor_dbinit_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AuditorDbinitState *ks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0, &ks->auditor_dbinit_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make the "exec-auditor-dbinit" CMD.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_auditor_dbinit (const char *label,
+ const char *config_filename)
+{
+ struct AuditorDbinitState *ks;
+
+ ks = GNUNET_new (struct AuditorDbinitState);
+ ks->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &auditor_dbinit_run,
+ .cleanup = &auditor_dbinit_cleanup,
+ .traits = &auditor_dbinit_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_auditor_api_cmd_exec_auditor_dbinit.c */
diff --git a/src/testing/testing_api_cmd_auditor_exec_wire_auditor.c b/src/testing/testing_api_cmd_auditor_exec_wire_auditor.c
@@ -0,0 +1,165 @@
+/*
+ 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 testing/testing_api_cmd_auditor_exec_wire_auditor.c
+ * @brief run the taler-wire-auditor command
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "wire-auditor" CMD.
+ */
+struct WireAuditorState
+{
+
+ /**
+ * Process for the "wire-auditor" command.
+ */
+ struct GNUNET_OS_Process *wire_auditor_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+};
+
+
+/**
+ * Run the command; calls the `taler-wire-auditor' program.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+wire_auditor_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct WireAuditorState *ks = cls;
+
+ ks->wire_auditor_proc
+ = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-wire-auditor",
+ "taler-wire-auditor",
+ "-c", ks->config_filename,
+ NULL);
+ if (NULL == ks->wire_auditor_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "wire-auditor" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+wire_auditor_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct WireAuditorState *ks = cls;
+
+ if (NULL != ks->wire_auditor_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ks->wire_auditor_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ks->wire_auditor_proc);
+ GNUNET_OS_process_destroy (ks->wire_auditor_proc);
+ ks->wire_auditor_proc = NULL;
+ }
+ GNUNET_free (ks);
+}
+
+
+/**
+ * Offer "wire-auditor" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+wire_auditor_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct WireAuditorState *ks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0, &ks->wire_auditor_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make the "exec wire-auditor" CMD.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_wire_auditor (const char *label,
+ const char *config_filename)
+{
+ struct WireAuditorState *ks;
+
+ ks = GNUNET_new (struct WireAuditorState);
+ ks->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &wire_auditor_run,
+ .cleanup = &wire_auditor_cleanup,
+ .traits = &wire_auditor_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_auditor_api_cmd_exec_wire_auditor.c */
diff --git a/src/testing/testing_api_cmd_bank_admin_add_incoming.c b/src/testing/testing_api_cmd_bank_admin_add_incoming.c
@@ -0,0 +1,596 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_admin_add_incoming.c
+ * @brief implementation of a bank /admin/add-incoming command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "backoff.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "fakebank transfer" CMD.
+ */
+struct AdminAddIncomingState
+{
+
+ /**
+ * Label of any command that can trait-offer a reserve priv.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Wire transfer amount.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Base URL of the credited account.
+ */
+ const char *exchange_credit_url;
+
+ /**
+ * Money sender payto URL.
+ */
+ const char *payto_debit_account;
+
+ /**
+ * Username to use for authentication.
+ */
+ struct TALER_BANK_AuthenticationData auth;
+
+ /**
+ * Set (by the interpreter) to the reserve's private key
+ * we used to make a wire transfer subject line with.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Reserve public key matching @e reserve_priv.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Handle to the pending request at the fakebank.
+ */
+ struct TALER_BANK_AdminAddIncomingHandle *aih;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Set to the wire transfer's unique ID.
+ */
+ uint64_t serial_id;
+
+ /**
+ * Timestamp of the transaction (as returned from the bank).
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Merchant instance. Sometimes used to get the tip reserve
+ * private key by reading the appropriate config section.
+ */
+ const char *instance;
+
+ /**
+ * Configuration filename. Used to get the tip reserve key
+ * filename (used to obtain a public key to write in the
+ * transfer subject).
+ */
+ const char *config_filename;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Was this command modified via
+ * #TALER_TESTING_cmd_admin_add_incoming_with_retry to
+ * enable retries?
+ */
+ int do_retry;
+};
+
+
+/**
+ * Run the "fakebank transfer" CMD.
+ *
+ * @param cls closure.
+ * @param cmd CMD being run.
+ * @param is interpreter state.
+ */
+static void
+admin_add_incoming_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #admin_add_incoming_run.
+ *
+ * @param cls a `struct AdminAddIncomingState`
+ */
+static void
+do_retry (void *cls)
+{
+ struct AdminAddIncomingState *fts = cls;
+
+ fts->retry_task = NULL;
+ admin_add_incoming_run (fts,
+ NULL,
+ fts->is);
+}
+
+
+/**
+ * This callback will process the fakebank response to the wire
+ * transfer. It just checks whether the HTTP response code is
+ * acceptable.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
+ * successful status request; 0 if the exchange's reply is
+ * bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
+ * @param serial_id unique ID of the wire transfer
+ * @param timestamp time stamp of the transaction made.
+ * @param json raw response
+ */
+static void
+confirmation_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ uint64_t serial_id,
+ struct GNUNET_TIME_Absolute timestamp,
+ const json_t *json)
+{
+ struct AdminAddIncomingState *fts = cls;
+ struct TALER_TESTING_Interpreter *is = fts->is;
+
+ fts->aih = NULL;
+ if (MHD_HTTP_OK != http_status)
+ {
+ if (GNUNET_YES == fts->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_INFO,
+ "Retrying fakebank transfer failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ fts->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
+ fts->retry_task = GNUNET_SCHEDULER_add_delayed
+ (fts->backoff,
+ &do_retry,
+ fts);
+ return;
+ }
+ }
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fakebank returned HTTP status %u/%d\n",
+ http_status,
+ (int) ec);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ fts->serial_id = serial_id;
+ fts->timestamp = timestamp;
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the "fakebank transfer" CMD.
+ *
+ * @param cls closure.
+ * @param cmd CMD being run.
+ * @param is interpreter state.
+ */
+static void
+admin_add_incoming_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AdminAddIncomingState *fts = cls;
+
+ /* Use reserve public key as subject */
+ if (NULL != fts->reserve_reference)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+
+ ref = TALER_TESTING_interpreter_lookup_command
+ (is, fts->reserve_reference);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (ref,
+ 0,
+ &reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv;
+ }
+ else
+ {
+ if (NULL != fts->instance)
+ {
+ char *section;
+ char *keys;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ GNUNET_assert (NULL != fts->config_filename);
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_load (cfg,
+ fts->config_filename))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_asprintf (§ion,
+ "instance-%s",
+ fts->instance);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename
+ (cfg,
+ section,
+ "TIP_RESERVE_PRIV_FILENAME",
+ &keys))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Configuration fails to specify reserve"
+ " private key filename in section %s\n",
+ section);
+ GNUNET_free (section);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys);
+ GNUNET_free (keys);
+ if (NULL == priv)
+ {
+ GNUNET_log_config_invalid
+ (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "TIP_RESERVE_PRIV_FILENAME",
+ "Failed to read private key");
+ GNUNET_free (section);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ fts->reserve_priv.eddsa_priv = *priv;
+ GNUNET_free (section);
+ GNUNET_free (priv);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ }
+ else
+ {
+ /* No referenced reserve, no instance to take priv
+ * from, no explicit subject given: create new key! */
+ struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
+
+ priv = GNUNET_CRYPTO_eddsa_key_create ();
+ fts->reserve_priv.eddsa_priv = *priv;
+ GNUNET_free (priv);
+ }
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv,
+ &fts->reserve_pub.eddsa_pub);
+ fts->is = is;
+ fts->aih
+ = TALER_BANK_admin_add_incoming
+ (TALER_TESTING_interpreter_get_context (is),
+ &fts->auth,
+ &fts->reserve_pub,
+ &fts->amount,
+ fts->payto_debit_account,
+ &confirmation_cb,
+ fts);
+ if (NULL == fts->aih)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "/admin/add-incoming" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure
+ * @param cmd current CMD being cleaned up.
+ */
+static void
+admin_add_incoming_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AdminAddIncomingState *fts = cls;
+
+ if (NULL != fts->aih)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %s did not complete\n",
+ cmd->label);
+ TALER_BANK_admin_add_incoming_cancel (fts->aih);
+ fts->aih = NULL;
+ }
+ if (NULL != fts->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (fts->retry_task);
+ fts->retry_task = NULL;
+ }
+ GNUNET_free (fts);
+}
+
+
+/**
+ * Offer internal data from a "/admin/add-incoming" CMD to other
+ * commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+admin_add_incoming_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AdminAddIncomingState *fts = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_bank_row (&fts->serial_id),
+ TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
+ fts->payto_debit_account),
+ /* Used as a marker, content does not matter */
+ TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
+ "payto://void/the-exchange"),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
+ fts->exchange_credit_url),
+ TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
+ TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
+ TALER_TESTING_make_trait_reserve_priv (0,
+ &fts->reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (0,
+ &fts->reserve_pub),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Create internal state for "/admin/add-incoming" CMD.
+ *
+ * @param amount the amount to transfer.
+ * @param payto_debit_account which account sends money
+ * @param auth authentication data
+ * @return the internal state
+ */
+static struct AdminAddIncomingState *
+make_fts (const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account)
+{
+ struct AdminAddIncomingState *fts;
+
+ fts = GNUNET_new (struct AdminAddIncomingState);
+ fts->exchange_credit_url = auth->wire_gateway_url;
+ fts->payto_debit_account = payto_debit_account;
+ fts->auth = *auth;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &fts->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s'\n",
+ amount);
+ GNUNET_assert (0);
+ }
+ return fts;
+}
+
+
+/**
+ * Helper function to create admin/add-incoming command.
+ *
+ * @param label command label.
+ * @param fts internal state to use
+ * @return the command.
+ */
+static struct TALER_TESTING_Command
+make_command (const char *label,
+ struct AdminAddIncomingState *fts)
+{
+ struct TALER_TESTING_Command cmd = {
+ .cls = fts,
+ .label = label,
+ .run = &admin_add_incoming_run,
+ .cleanup = &admin_add_incoming_cleanup,
+ .traits = &admin_add_incoming_traits
+ };
+
+ return cmd;
+}
+
+
+/**
+ * Create admin/add-incoming command.
+ *
+ * @param label command label.
+ * @param amount amount to transfer.
+ * @param payto_debit_account which account sends money.
+ * @param auth authentication data
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_admin_add_incoming (const char *label,
+ const char *amount,
+ const struct
+ TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account)
+{
+ return make_command (label,
+ make_fts (amount,
+ auth,
+ payto_debit_account));
+}
+
+
+/**
+ * Create "/admin/add-incoming" CMD, letting the caller specify
+ * a reference to a command that can offer a reserve private key.
+ * This private key will then be used to construct the subject line
+ * of the wire transfer.
+ *
+ * @param label command label.
+ * @param amount the amount to transfer.
+ * @param payto_debit_account which account sends money
+ * @param auth authentication data
+ * @param ref reference to a command that can offer a reserve
+ * private key.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_admin_add_incoming_with_ref
+ (const char *label,
+ const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account,
+ const char *ref)
+{
+ struct AdminAddIncomingState *fts;
+
+ fts = make_fts (amount,
+ auth,
+ payto_debit_account);
+ fts->reserve_reference = ref;
+ return make_command (label,
+ fts);
+}
+
+
+/**
+ * Create "/admin/add-incoming" CMD, letting the caller specifying
+ * the merchant instance. This version is useful when a tip
+ * reserve should be topped up, in fact the interpreter will need
+ * the "tipping instance" in order to get the instance public key
+ * and make a wire transfer subject out of it.
+ *
+ * @param label command label.
+ * @param amount amount to transfer.
+ * @param payto_debit_account which account (expressed as a number)
+ * gives money
+ * @param auth authentication data
+ * @param instance the instance that runs the tipping. Under this
+ * instance, the configuration file will provide the private
+ * key of the tipping reserve. This data will then used to
+ * construct the wire transfer subject line.
+ * @param config_filename configuration file to use.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_admin_add_incoming_with_instance
+ (const char *label,
+ const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account,
+ const char *instance,
+ const char *config_filename)
+{
+ struct AdminAddIncomingState *fts;
+
+ fts = make_fts (amount,
+ auth,
+ payto_debit_account);
+ fts->instance = instance;
+ fts->config_filename = config_filename;
+
+ return make_command (label,
+ fts);
+}
+
+
+/**
+ * Modify a fakebank transfer command to enable retries when the
+ * reserve is not yet full or we get other transient errors from the
+ * fakebank.
+ *
+ * @param cmd a fakebank transfer command
+ * @return the command with retries enabled
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_admin_add_incoming_retry (struct TALER_TESTING_Command cmd)
+{
+ struct AdminAddIncomingState *fts;
+
+ GNUNET_assert (&admin_add_incoming_run == cmd.run);
+ fts = cmd.cls;
+ fts->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_bank_admin_add_incoming.c */
diff --git a/src/testing/testing_api_cmd_bank_admin_check.c b/src/testing/testing_api_cmd_bank_admin_check.c
@@ -0,0 +1,224 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_admin_check.c
+ * @brief command to check if a particular admin/add-incoming transfer took
+ * place.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+
+
+/**
+ * State for a "bank check" CMD.
+ */
+struct BankAdminCheckState
+{
+
+ /**
+ * Expected transferred amount.
+ */
+ const char *amount;
+
+ /**
+ * Expected debit bank account.
+ */
+ const char *debit_payto;
+
+ /**
+ * Expected credit bank account.
+ */
+ const char *credit_payto;
+
+ /**
+ * Command providing the reserve public key trait to use.
+ */
+ const char *reserve_pub_ref;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+};
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+check_bank_admin_transfer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct BankAdminCheckState *bcs = cls;
+ struct TALER_Amount amount;
+ char *debit_account;
+ char *credit_account;
+ const char *debit_payto;
+ const char *credit_payto;
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+ const struct TALER_TESTING_Command *cmd_ref;
+
+ cmd_ref
+ = TALER_TESTING_interpreter_lookup_command (is,
+ bcs->reserve_pub_ref);
+ if (NULL == cmd_ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (cmd_ref,
+ 0,
+ &reserve_pub))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Command reference fails to provide reserve public key\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_LOG_INFO ("Deposit reference NOT given\n");
+ debit_payto = bcs->debit_payto;
+ credit_payto = bcs->credit_payto;
+ 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;
+ }
+ debit_account = TALER_xtalerbank_account_from_payto (debit_payto);
+ credit_account = TALER_xtalerbank_account_from_payto (credit_payto);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "converted debit_payto (%s) to debit_account (%s)\n",
+ debit_payto,
+ debit_account);
+ if (GNUNET_OK !=
+ TALER_FAKEBANK_check_credit (is->fakebank,
+ &amount,
+ debit_account,
+ credit_account,
+ reserve_pub))
+ {
+ GNUNET_break (0);
+ GNUNET_free (credit_account);
+ GNUNET_free (debit_account);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_free (credit_account);
+ GNUNET_free (debit_account);
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Free the state of a "bank check" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_bank_admin_transfer_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct BankAdminCheckState *bcs = cls;
+
+ GNUNET_free (bcs);
+}
+
+
+/**
+ * Offer internal data from a "bank admin check" CMD state.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+check_bank_admin_transfer_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_trait_end ()
+ };
+
+ (void) cls;
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make a "bank check" CMD. It checks whether a particular wire transfer to
+ * the exchange (credit) has been made or not.
+ *
+ * @param label the command label.
+ * @param amount the amount expected to be transferred.
+ * @param debit_payto the account that gave money.
+ * @param credit_payto the account that received money.
+ * @param reserve_pub_ref command that provides the reserve public key to expect
+ * @return the command
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_bank_admin_transfer
+ (const char *label,
+ const char *amount,
+ const char *debit_payto,
+ const char *credit_payto,
+ const char *reserve_pub_ref)
+{
+ struct BankAdminCheckState *bcs;
+
+ bcs = GNUNET_new (struct BankAdminCheckState);
+ bcs->amount = amount;
+ bcs->debit_payto = debit_payto;
+ bcs->credit_payto = credit_payto;
+ bcs->reserve_pub_ref = reserve_pub_ref;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = bcs,
+ .run = &check_bank_admin_transfer_run,
+ .cleanup = &check_bank_admin_transfer_cleanup,
+ .traits = &check_bank_admin_transfer_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_bank_check.c b/src/testing/testing_api_cmd_bank_check.c
@@ -0,0 +1,305 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_check.c
+ * @brief command to check if a particular wire transfer took
+ * place.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+
+
+/**
+ * State for a "bank check" CMD.
+ */
+struct BankCheckState
+{
+
+ /**
+ * Base URL of the exchange supposed to be
+ * involved in the bank transaction.
+ */
+ const char *exchange_base_url;
+
+ /**
+ * Expected transferred amount.
+ */
+ const char *amount;
+
+ /**
+ * Expected debit bank account.
+ */
+ const char *debit_payto;
+
+ /**
+ * Expected credit bank account.
+ */
+ const char *credit_payto;
+
+ /**
+ * Binary form of the wire transfer subject.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to a CMD that provides all the data
+ * needed to issue the bank check. If NULL, that data
+ * must exist here in the state.
+ */
+ const char *deposit_reference;
+};
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+check_bank_transfer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct BankCheckState *bcs = cls;
+ struct TALER_Amount amount;
+ char *debit_account;
+ char *credit_account;
+ const char *exchange_base_url;
+ const char *debit_payto;
+ const char *credit_payto;
+
+ if (NULL == bcs->deposit_reference)
+ {
+ TALER_LOG_INFO ("Deposit reference NOT given\n");
+ debit_payto = bcs->debit_payto;
+ credit_payto = bcs->credit_payto;
+ 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;
+ }
+ }
+ else
+ {
+ const struct TALER_TESTING_Command *deposit_cmd;
+ const struct TALER_Amount *amount_ptr;
+
+ TALER_LOG_INFO ("`%s' uses reference (%s/%p)\n",
+ TALER_TESTING_interpreter_get_current_label
+ (is),
+ bcs->deposit_reference,
+ bcs->deposit_reference);
+ deposit_cmd
+ = TALER_TESTING_interpreter_lookup_command (is,
+ bcs->deposit_reference);
+ if (NULL == deposit_cmd)
+ TALER_TESTING_FAIL (is);
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount_obj (deposit_cmd,
+ 0,
+ &amount_ptr)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto (deposit_cmd,
+ TALER_TESTING_PT_DEBIT,
+ &debit_payto)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto (deposit_cmd,
+ TALER_TESTING_PT_CREDIT,
+ &credit_payto)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_url (deposit_cmd,
+ TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ &exchange_base_url)) )
+ TALER_TESTING_FAIL (is);
+ amount = *amount_ptr;
+ }
+
+
+ debit_account = TALER_xtalerbank_account_from_payto (debit_payto);
+ credit_account = TALER_xtalerbank_account_from_payto (credit_payto);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "converted debit_payto (%s) to debit_account (%s)\n",
+ debit_payto,
+ debit_account);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "converted credit_payto (%s) to credit_account (%s)\n",
+ credit_payto,
+ credit_account);
+
+ if (GNUNET_OK !=
+ TALER_FAKEBANK_check_debit (is->fakebank,
+ &amount,
+ debit_account,
+ credit_account,
+ exchange_base_url,
+ &bcs->wtid))
+ {
+ GNUNET_break (0);
+ GNUNET_free (credit_account);
+ GNUNET_free (debit_account);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_free (credit_account);
+ GNUNET_free (debit_account);
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Free the state of a "bank check" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_bank_transfer_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct BankCheckState *bcs = cls;
+
+ GNUNET_free (bcs);
+}
+
+
+/**
+ * Offer internal data from a "bank check" CMD state.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+check_bank_transfer_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct BankCheckState *bcs = cls;
+ struct TALER_WireTransferIdentifierRawP *wtid_ptr = &bcs->wtid;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_wtid (0,
+ wtid_ptr),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ bcs->exchange_base_url),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make a "bank check" CMD. It checks whether a
+ * particular wire transfer has been made or not.
+ *
+ * @param label the command label.
+ * @param exchange_base_url base url of the exchange involved in
+ * the wire transfer.
+ * @param amount the amount expected to be transferred.
+ * @param debit_payto the account that gave money.
+ * @param credit_payto the account that received money.
+ *
+ * @return the command
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_bank_transfer (const char *label,
+ const char *exchange_base_url,
+ const char *amount,
+ const char *debit_payto,
+ const char *credit_payto)
+{
+ struct BankCheckState *bcs;
+
+ bcs = GNUNET_new (struct BankCheckState);
+ bcs->exchange_base_url = exchange_base_url;
+ bcs->amount = amount;
+ bcs->debit_payto = debit_payto;
+ bcs->credit_payto = credit_payto;
+ bcs->deposit_reference = NULL;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = bcs,
+ .run = &check_bank_transfer_run,
+ .cleanup = &check_bank_transfer_cleanup,
+ .traits = &check_bank_transfer_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Define a "bank check" CMD that takes the input
+ * data from another CMD that offers it.
+ *
+ * @param label command label.
+ * @param deposit_reference reference to a CMD that is
+ * able to provide the "check bank transfer" operation
+ * input data.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_bank_transfer_with_ref
+ (const char *label,
+ const char *deposit_reference)
+{
+ struct BankCheckState *bcs;
+
+ bcs = GNUNET_new (struct BankCheckState);
+ bcs->deposit_reference = deposit_reference;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = bcs,
+ .run = &check_bank_transfer_run,
+ .cleanup = &check_bank_transfer_cleanup,
+ .traits = &check_bank_transfer_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_bank_check_empty.c b/src/testing/testing_api_cmd_bank_check_empty.c
@@ -0,0 +1,102 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_check_empty.c
+ * @brief command to check if a particular wire transfer took
+ * place.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+
+
+/**
+ * Cleanup the state, only defined to respect the API.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_bank_empty_cleanup
+ (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ return;
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+check_bank_empty_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ if (GNUNET_OK != TALER_FAKEBANK_check_empty (is->fakebank))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Some commands (notably "bank history") could randomly
+ * look for traits; this way makes sure we don't segfault.
+ */
+static int
+check_bank_empty_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Checks wheter all the wire transfers got "checked"
+ * by the "bank check" CMD.
+ *
+ * @param label command label.
+ *
+ * @return the command
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_bank_empty (const char *label)
+{
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = &check_bank_empty_run,
+ .cleanup = &check_bank_empty_cleanup,
+ .traits = &check_bank_empty_traits
+ };
+
+ return cmd;
+}
diff --git a/src/testing/testing_api_cmd_bank_history_credit.c b/src/testing/testing_api_cmd_bank_history_credit.c
@@ -0,0 +1,599 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_history_credit.c
+ * @brief command to check the /history/incoming 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"
+
+
+/**
+ * Item in the transaction history, as reconstructed from the
+ * command history.
+ */
+struct History
+{
+
+ /**
+ * Wire details.
+ */
+ struct TALER_BANK_CreditDetails details;
+
+ /**
+ * Serial ID of the wire transfer.
+ */
+ uint64_t row_id;
+
+ /**
+ * URL to free.
+ */
+ char *url;
+};
+
+
+/**
+ * State for a "history" CMD.
+ */
+struct HistoryState
+{
+ /**
+ * Base URL of the account offering the "history" operation.
+ */
+ char *account_url;
+
+ /**
+ * Reference to command defining the
+ * first row number we want in the result.
+ */
+ const char *start_row_reference;
+
+ /**
+ * How many rows we want in the result, _at most_,
+ * and ascending/descending.
+ */
+ long long num_results;
+
+ /**
+ * Handle to a pending "history" operation.
+ */
+ struct TALER_BANK_CreditHistoryHandle *hh;
+
+ /**
+ * Authentication data for the operation.
+ */
+ struct TALER_BANK_AuthenticationData auth;
+
+ /**
+ * Expected number of results (= rows).
+ */
+ uint64_t results_obtained;
+
+ /**
+ * Set to GNUNET_YES if the callback detects something
+ * unexpected.
+ */
+ int failed;
+
+ /**
+ * Expected history.
+ */
+ struct History *h;
+
+ /**
+ * Length of @e h
+ */
+ unsigned int total;
+
+};
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret set to the wanted data.
+ * @param trait name of the trait.
+ * @param index index number of the traits to be returned.
+ *
+ * @return #GNUNET_OK on success
+ */
+static int
+history_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ (void) cls;
+ (void) ret;
+ (void) trait;
+ (void) index;
+ /* Must define this function because some callbacks
+ * look for certain traits on _all_ the commands. */
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Log which history we expected. Called when an error occurs.
+ *
+ * @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,
+ unsigned int h_len,
+ unsigned int off)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Transaction history (credit) mismatch at position %u/%u\n",
+ off,
+ h_len);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history:\n");
+ for (unsigned int i = 0; i<h_len; i++)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "H(%u): %s (serial: %llu, subject: %s,"
+ " counterpart: %s)\n",
+ i,
+ TALER_amount2s (&h[i].details.amount),
+ (unsigned long long) h[i].row_id,
+ TALER_B2S (&h[i].details.reserve_pub),
+ h[i].details.debit_account_url);
+ }
+}
+
+
+/**
+ * This function constructs the list of history elements that
+ * interest the account number of the caller. It has two main
+ * loops: the first to figure out how many history elements have
+ * to be allocated, and the second to actually populate every
+ * element.
+ *
+ * @param is interpreter state (supposedly having the
+ * current CMD pointing at a "history" CMD).
+ * @param[out] rh history array to initialize.
+ * @return number of entries in @a rh.
+ */
+static unsigned int
+build_history (struct TALER_TESTING_Interpreter *is,
+ struct History **rh)
+{
+ struct HistoryState *hs = is->commands[is->ip].cls;
+ unsigned int total;
+ unsigned int pos;
+ struct History *h;
+ const struct TALER_TESTING_Command *add_incoming_cmd;
+ int inc;
+ unsigned int start;
+ unsigned int end;
+
+ /* @var turns GNUNET_YES whenever either no 'start' value was
+ * given for the history query, or the given value is found
+ * in the list of all the CMDs. *///
+ int ok;
+ const uint64_t *row_id_start = NULL;
+
+ 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)
+ {
+ TALER_LOG_DEBUG ("Checking history at FIRST transaction (EMPTY)\n");
+ *rh = NULL;
+ return 0;
+ }
+
+ if (hs->num_results > 0)
+ {
+ inc = 1; /* _inc_rement */
+ start = 0;
+ end = is->ip - 1;
+ }
+ else
+ {
+ inc = -1;
+ start = is->ip - 1;
+ end = 0;
+ }
+
+ ok = GNUNET_NO;
+ if (NULL == row_id_start)
+ ok = GNUNET_YES;
+ h = NULL;
+ total = 0;
+ GNUNET_array_grow (h,
+ total,
+ 4);
+ pos = 0;
+ for (unsigned int off = start; off != end + inc; off += inc)
+ {
+ const struct TALER_TESTING_Command *cmd = &is->commands[off];
+ const uint64_t *row_id;
+ const char *credit_account;
+ const char *debit_account;
+ const struct TALER_Amount *amount;
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+ const char *exchange_credit_url;
+
+ /* The following command allows us to skip over those CMDs
+ * that do not offer a "row_id" trait. Such skipped CMDs are
+ * not interesting for building a history. *///
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_bank_row (cmd,
+ &row_id)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto (cmd,
+ TALER_TESTING_PT_CREDIT,
+ &credit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto (cmd,
+ TALER_TESTING_PT_DEBIT,
+ &debit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount_obj (cmd,
+ 0,
+ &amount)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (cmd,
+ 0,
+ &reserve_pub)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_url (cmd,
+ TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
+ &exchange_credit_url)) )
+ continue; /* not an interesting event */
+ /* Seek "/history/incoming" starting row. */
+ if ( (NULL != row_id_start) &&
+ (*row_id_start == *row_id) &&
+ (GNUNET_NO == ok) )
+ {
+ /* Until here, nothing counted. */
+ ok = GNUNET_YES;
+ continue;
+ }
+ /* when 'start' was _not_ given, then ok == GNUNET_YES */
+ if (GNUNET_NO == ok)
+ continue; /* skip until we find the marker */
+ if (0 != strcasecmp (hs->account_url,
+ exchange_credit_url))
+ continue; /* account missmatch */
+ if (total >= GNUNET_MAX (hs->num_results,
+ -hs->num_results) )
+ {
+ TALER_LOG_DEBUG ("Hit history limit\n");
+ break;
+ }
+ TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
+ debit_account,
+ credit_account,
+ hs->account_url);
+ /* found matching record, make sure we have room */
+ if (pos == total)
+ GNUNET_array_grow (h,
+ total,
+ pos * 2);
+ h[pos].url = GNUNET_strdup (debit_account);
+ h[pos].details.debit_account_url = h[pos].url;
+ h[pos].details.amount = *amount;
+ h[pos].row_id = *row_id;
+ h[pos].details.reserve_pub = *reserve_pub;
+ h[pos].details.credit_account_url = exchange_credit_url;
+ pos++;
+ }
+ GNUNET_assert (GNUNET_YES == ok);
+ GNUNET_array_grow (h,
+ total,
+ pos);
+ if (0 == pos)
+ TALER_LOG_DEBUG ("Empty credit history computed\n");
+ *rh = h;
+ return total;
+}
+
+
+/**
+ * Check that the "/history/incoming" response matches the
+ * CMD whose offset in the list of CMDs is @a off.
+ *
+ * @param is the interpreter state.
+ * @param h expected history (array)
+ * @param total length of @a h
+ * @param off the offset (of the CMD list) where the command
+ * to check is.
+ * @param details the expected transaction details.
+ * @return #GNUNET_OK if the transaction is what we expect.
+ */
+static int
+check_result (struct TALER_TESTING_Interpreter *is,
+ struct History *h,
+ unsigned int total,
+ unsigned int off,
+ const struct TALER_BANK_CreditDetails *details)
+{
+ if (off >= total)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Test says history has at most %u"
+ " results, but got result #%u to check\n",
+ total,
+ off);
+ print_expected (h,
+ total,
+ off);
+ return GNUNET_SYSERR;
+ }
+ if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub,
+ &details->reserve_pub)) ||
+ (0 != TALER_amount_cmp (&h[off].details.amount,
+ &details->amount)) ||
+ (0 != strcasecmp (h[off].details.debit_account_url,
+ details->debit_account_url)) )
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "expected debit_account_url: %s\n",
+ details->debit_account_url);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "actual debit_account_url: %s\n",
+ h[off].details.debit_account_url);
+ print_expected (h,
+ total,
+ off);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * This callback will (1) check that the HTTP response code
+ * is acceptable and (2) that the history is consistent. The
+ * consistency is checked by going through all the past CMDs,
+ * reconstructing then the expected history as of those, and
+ * finally check it against what the bank returned.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200)
+ * for successful status request 0 if the bank's reply is
+ * bogus (fails to follow the protocol),
+ * #MHD_HTTP_NO_CONTENT if there are no more results; on
+ * success the last callback is always of this status
+ * (even if `abs(num_results)` were already returned).
+ * @param ec taler status code.
+ * @param row_id monotonically increasing counter corresponding to
+ * the transaction.
+ * @param details details about the wire transfer.
+ * @param json detailed response from the HTTPD, or NULL if
+ * reply was not in JSON.
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
+ */
+static int
+history_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ uint64_t row_id,
+ const struct TALER_BANK_CreditDetails *details,
+ const json_t *json)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct HistoryState *hs = is->commands[is->ip].cls;
+
+ (void) row_id;
+ if (NULL == details)
+ {
+ hs->hh = NULL;
+ if ( (hs->results_obtained != hs->total) ||
+ (GNUNET_YES == hs->failed) ||
+ (MHD_HTTP_NO_CONTENT != http_status) )
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history of length %u, got %llu;"
+ " HTTP status code: %u/%d, failed: %d\n",
+ hs->total,
+ (unsigned long long) hs->results_obtained,
+ http_status,
+ (int) ec,
+ hs->failed);
+ print_expected (hs->h,
+ hs->total,
+ UINT_MAX);
+ TALER_TESTING_interpreter_fail (is);
+ return GNUNET_SYSERR;
+ }
+ TALER_TESTING_interpreter_next (is);
+ return GNUNET_OK;
+ }
+ if (MHD_HTTP_OK != http_status)
+ {
+ hs->hh = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unwanted response code from /history/incoming: %u\n",
+ http_status);
+ TALER_TESTING_interpreter_fail (is);
+ return GNUNET_SYSERR;
+ }
+
+ /* check current element */
+ if (GNUNET_OK != check_result (is,
+ hs->h,
+ hs->total,
+ hs->results_obtained,
+ details))
+ {
+ char *acc;
+
+ GNUNET_break (0);
+ acc = json_dumps (json,
+ JSON_COMPACT);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Result %u was `%s'\n",
+ (unsigned int) hs->results_obtained++,
+ acc);
+ if (NULL != acc)
+ free (acc);
+ hs->failed = GNUNET_YES;
+ return GNUNET_SYSERR;
+ }
+ hs->results_obtained++;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+history_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct HistoryState *hs = cls;
+ uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
+ const uint64_t *row_ptr;
+
+ (void) cmd;
+ /* 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_ptr))
+ TALER_TESTING_FAIL (is);
+ else
+ row_id = *row_ptr;
+ TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
+ (unsigned long long) row_id);
+ }
+ hs->total = build_history (is,
+ &hs->h);
+ hs->hh = TALER_BANK_credit_history (is->ctx,
+ &hs->auth,
+ row_id,
+ hs->num_results,
+ &history_cb,
+ is);
+ GNUNET_assert (NULL != hs->hh);
+}
+
+
+/**
+ * Free the state from a "history" CMD, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+history_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct HistoryState *hs = cls;
+
+ (void) cmd;
+ if (NULL != hs->hh)
+ {
+ TALER_LOG_WARNING ("/history/incoming did not complete\n");
+ TALER_BANK_credit_history_cancel (hs->hh);
+ }
+ GNUNET_free (hs->account_url);
+ for (unsigned int off = 0; off<hs->total; off++)
+ GNUNET_free (hs->h[off].url);
+ GNUNET_free_non_null (hs->h);
+ GNUNET_free (hs);
+}
+
+
+/**
+ * Make a "history" CMD.
+ *
+ * @param label command label.
+ * @param auth authentication data to talk with the wire gateway
+ * @param start_row_reference reference to a command that can
+ * offer a row identifier, to be used as the starting row
+ * to accept in the result.
+ * @param num_results how many rows we want in the result.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_credits (const char *label,
+ const struct
+ TALER_BANK_AuthenticationData *auth,
+ const char *start_row_reference,
+ long long num_results)
+{
+ struct HistoryState *hs;
+
+ hs = GNUNET_new (struct HistoryState);
+ hs->account_url = GNUNET_strdup (auth->wire_gateway_url);
+ hs->start_row_reference = start_row_reference;
+ hs->num_results = num_results;
+ hs->auth = *auth;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = hs,
+ .run = &history_run,
+ .cleanup = &history_cleanup,
+ .traits = &history_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_credit_history.c */
diff --git a/src/testing/testing_api_cmd_bank_history_debit.c b/src/testing/testing_api_cmd_bank_history_debit.c
@@ -0,0 +1,602 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_history_debit.c
+ * @brief command to check the /history/outgoing 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"
+
+/**
+ * Item in the transaction history, as reconstructed from the
+ * command history.
+ */
+struct History
+{
+
+ /**
+ * Wire details.
+ */
+ struct TALER_BANK_DebitDetails details;
+
+ /**
+ * Serial ID of the wire transfer.
+ */
+ uint64_t row_id;
+
+ /**
+ * URL to free.
+ */
+ char *c_url;
+
+ /**
+ * URL to free.
+ */
+ char *d_url;
+};
+
+
+/**
+ * State for a "history" CMD.
+ */
+struct HistoryState
+{
+ /**
+ * Base URL of the account offering the "history" operation.
+ */
+ const char *account_url;
+
+ /**
+ * Reference to command defining the
+ * first row number we want in the result.
+ */
+ const char *start_row_reference;
+
+ /**
+ * How many rows we want in the result, _at most_,
+ * and ascending/descending.
+ */
+ long long num_results;
+
+ /**
+ * Login data to use to authenticate.
+ */
+ struct TALER_BANK_AuthenticationData auth;
+
+ /**
+ * Handle to a pending "history" operation.
+ */
+ struct TALER_BANK_DebitHistoryHandle *hh;
+
+ /**
+ * Expected number of results (= rows).
+ */
+ uint64_t results_obtained;
+
+ /**
+ * Set to #GNUNET_YES if the callback detects something
+ * unexpected.
+ */
+ int failed;
+
+ /**
+ * Expected history.
+ */
+ struct History *h;
+
+ /**
+ * Length of @e h
+ */
+ unsigned int total;
+
+};
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret set to the wanted data.
+ * @param trait name of the trait.
+ * @param index index number of the traits to be returned.
+ *
+ * @return #GNUNET_OK on success
+ */
+static int
+history_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ (void) cls;
+ (void) ret;
+ (void) trait;
+ (void) index;
+ /* Must define this function because some callbacks
+ * look for certain traits on _all_ the commands. */
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Log which history we expected. Called when an error occurs.
+ *
+ * @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,
+ unsigned int h_len,
+ unsigned int off)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Transaction history (debit) mismatch at position %u/%u\n",
+ off,
+ h_len);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history:\n");
+ for (unsigned int i = 0; i<h_len; i++)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "H(%u): %s (serial: %llu, subject: %s, counterpart: %s)\n",
+ i,
+ TALER_amount2s (&h[i].details.amount),
+ (unsigned long long) h[i].row_id,
+ TALER_B2S (&h[i].details.wtid),
+ h[i].details.credit_account_url);
+ }
+}
+
+
+/**
+ * This function constructs the list of history elements that
+ * interest the account number of the caller. It has two main
+ * loops: the first to figure out how many history elements have
+ * to be allocated, and the second to actually populate every
+ * element.
+ *
+ * @param is interpreter state (supposedly having the
+ * current CMD pointing at a "history" CMD).
+ * @param[out] rh history array to initialize.
+ * @return number of entries in @a rh.
+ */
+static unsigned int
+build_history (struct TALER_TESTING_Interpreter *is,
+ struct History **rh)
+{
+ struct HistoryState *hs = is->commands[is->ip].cls;
+ unsigned int total;
+ unsigned int pos;
+ struct History *h;
+ const struct TALER_TESTING_Command *add_incoming_cmd;
+ int inc;
+ int start;
+ int end;
+ /* #GNUNET_YES whenever either no 'start' value was given for the history
+ * query, or the given value is found in the list of all the CMDs. */
+ int ok;
+ const uint64_t *row_id_start = NULL;
+
+ 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)
+ {
+ TALER_LOG_DEBUG ("Checking history at first CMD..\n");
+ *rh = NULL;
+ return 0;
+ }
+
+ /* AKA 'delta' */
+ if (hs->num_results > 0)
+ {
+ inc = 1; /* _inc_rement: go forwards */
+ start = 0;
+ end = is->ip;
+ }
+ else
+ {
+ inc = -1; /* decrement: we go backwards */
+ start = is->ip - 1;
+ end = -1; /* range is exclusive, do look at 0! */
+ }
+
+ ok = GNUNET_NO;
+ if (NULL == row_id_start)
+ ok = GNUNET_YES;
+ h = NULL;
+ total = 0;
+ GNUNET_array_grow (h,
+ total,
+ 4);
+ pos = 0;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking commands %u to %u for debit history\n",
+ start,
+ end);
+ for (int off = start; off != end; off += inc)
+ {
+ const struct TALER_TESTING_Command *cmd = &is->commands[off];
+ const uint64_t *row_id;
+ const char *debit_account;
+ const char *credit_account;
+ const struct TALER_Amount *amount;
+ const struct TALER_WireTransferIdentifierRawP *wtid;
+ const char *exchange_base_url;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Checking if command %s is relevant for debit history\n",
+ cmd->label);
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_bank_row (cmd,
+ &row_id)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto (cmd,
+ TALER_TESTING_PT_DEBIT,
+ &debit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_payto (cmd,
+ TALER_TESTING_PT_CREDIT,
+ &credit_account)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount_obj (cmd,
+ 0,
+ &amount)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_wtid (cmd,
+ 0,
+ &wtid)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_url (cmd,
+ TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ &exchange_base_url)) )
+ continue; /* not an event we care about */
+ /* Seek "/history/outgoing" starting row. */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Command %s is relevant for debit history!\n",
+ cmd->label);
+ if ( (NULL != row_id_start) &&
+ (*row_id_start == *row_id) &&
+ (GNUNET_NO == ok) )
+ {
+ /* Until here, nothing counted. */
+ ok = GNUNET_YES;
+ continue;
+ }
+ /* when 'start' was _not_ given, then ok == GNUNET_YES */
+ if (GNUNET_NO == ok)
+ continue; /* skip until we find the marker */
+ if (total >= GNUNET_MAX (hs->num_results,
+ -hs->num_results) )
+ {
+ TALER_LOG_DEBUG ("Hit history limit\n");
+ break;
+ }
+ TALER_LOG_INFO ("Found history: %s->%s for account %s\n",
+ debit_account,
+ credit_account,
+ hs->account_url);
+ /* found matching record, make sure we have room */
+ if (pos == total)
+ GNUNET_array_grow (h,
+ total,
+ pos * 2);
+ h[pos].c_url = GNUNET_strdup (credit_account);
+ h[pos].d_url = GNUNET_strdup (debit_account);
+ h[pos].details.credit_account_url = h[pos].c_url;
+ h[pos].details.debit_account_url = h[pos].d_url;
+ h[pos].details.amount = *amount;
+ h[pos].row_id = *row_id;
+ h[pos].details.wtid = *wtid;
+ h[pos].details.exchange_base_url = exchange_base_url;
+ pos++;
+ }
+ GNUNET_assert (GNUNET_YES == ok);
+ GNUNET_array_grow (h,
+ total,
+ pos);
+ if (0 == pos)
+ TALER_LOG_DEBUG ("Empty debit history computed\n");
+ *rh = h;
+ return total;
+}
+
+
+/**
+ * Check that the "/history/outgoing" response matches the
+ * CMD whose offset in the list of CMDs is @a off.
+ *
+ * @param is the interpreter state.
+ * @param h expected history
+ * @param total number of entries in @a h
+ * @param off the offset (of the CMD list) where the command
+ * to check is.
+ * @param details the expected transaction details.
+ * @return #GNUNET_OK if the transaction is what we expect.
+ */
+static int
+check_result (struct TALER_TESTING_Interpreter *is,
+ struct History *h,
+ uint64_t total,
+ unsigned int off,
+ const struct TALER_BANK_DebitDetails *details)
+{
+ 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 ( (0 != GNUNET_memcmp (&h[off].details.wtid,
+ &details->wtid)) ||
+ (0 != TALER_amount_cmp (&h[off].details.amount,
+ &details->amount)) ||
+ (0 != strcasecmp (h[off].details.credit_account_url,
+ details->credit_account_url)) )
+ {
+ GNUNET_break (0);
+ print_expected (h,
+ total,
+ off);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * This callback will (1) check that the HTTP response code
+ * is acceptable and (2) that the history is consistent. The
+ * consistency is checked by going through all the past CMDs,
+ * reconstructing then the expected history as of those, and
+ * finally check it against what the bank returned.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200)
+ * for successful status request 0 if the bank's reply is
+ * bogus (fails to follow the protocol),
+ * #MHD_HTTP_NO_CONTENT if there are no more results; on
+ * success the last callback is always of this status
+ * (even if `abs(num_results)` were already returned).
+ * @param ec taler status code.
+ * @param row_id monotonically increasing counter corresponding to
+ * the transaction.
+ * @param details details about the wire transfer.
+ * @param json detailed response from the HTTPD, or NULL if
+ * reply was not in JSON.
+ * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
+ */
+static int
+history_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ uint64_t row_id,
+ const struct TALER_BANK_DebitDetails *details,
+ const json_t *json)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct HistoryState *hs = is->commands[is->ip].cls;
+
+ (void) row_id;
+ if (NULL == details)
+ {
+ hs->hh = NULL;
+ if ( (hs->results_obtained != hs->total) ||
+ (GNUNET_YES == hs->failed) ||
+ (MHD_HTTP_NO_CONTENT != http_status) )
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected history of length %u, got %llu;"
+ " HTTP status code: %u/%d, failed: %d\n",
+ hs->total,
+ (unsigned long long) hs->results_obtained,
+ http_status,
+ (int) ec,
+ hs->failed);
+ print_expected (hs->h,
+ hs->total,
+ UINT_MAX);
+ TALER_TESTING_interpreter_fail (is);
+ return GNUNET_SYSERR;
+ }
+ TALER_TESTING_interpreter_next (is);
+ return GNUNET_OK;
+ }
+ if (MHD_HTTP_OK != http_status)
+ {
+ hs->hh = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unwanted response code from /history/outgoing: %u\n",
+ http_status);
+ TALER_TESTING_interpreter_fail (is);
+ return GNUNET_SYSERR;
+ }
+
+ /* check current element */
+ if (GNUNET_OK != check_result (is,
+ hs->h,
+ hs->total,
+ hs->results_obtained,
+ details))
+ {
+ char *acc;
+
+ GNUNET_break (0);
+ acc = json_dumps (json,
+ JSON_COMPACT);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Result %u was `%s'\n",
+ (unsigned int) hs->results_obtained++,
+ acc);
+ if (NULL != acc)
+ free (acc);
+ hs->failed = GNUNET_YES;
+ return GNUNET_SYSERR;
+ }
+ hs->results_obtained++;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+history_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct HistoryState *hs = cls;
+ uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX;
+ const uint64_t *row_ptr;
+
+ (void) cmd;
+ /* 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_ptr))
+ TALER_TESTING_FAIL (is);
+ else
+ row_id = *row_ptr;
+ TALER_LOG_DEBUG ("row id (from trait) is %llu\n",
+ (unsigned long long) row_id);
+ }
+ hs->total = build_history (is, &hs->h);
+ hs->hh = TALER_BANK_debit_history (is->ctx,
+ &hs->auth,
+ row_id,
+ hs->num_results,
+ &history_cb,
+ is);
+ GNUNET_assert (NULL != hs->hh);
+}
+
+
+/**
+ * Free the state from a "history" CMD, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+history_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct HistoryState *hs = cls;
+
+ (void) cmd;
+ if (NULL != hs->hh)
+ {
+ TALER_LOG_WARNING ("/history/outgoing did not complete\n");
+ TALER_BANK_debit_history_cancel (hs->hh);
+ }
+ for (unsigned int off = 0; off<hs->total; off++)
+ {
+ GNUNET_free (hs->h[off].c_url);
+ GNUNET_free (hs->h[off].d_url);
+ }
+ GNUNET_free_non_null (hs->h);
+ GNUNET_free (hs);
+}
+
+
+/**
+ * Make a "history" CMD.
+ *
+ * @param label command label.
+ * @param auth login data to use
+ * @param start_row_reference reference to a command that can
+ * offer a row identifier, to be used as the starting row
+ * to accept in the result.
+ * @param num_results how many rows we want in the result.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_bank_debits (const char *label,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *start_row_reference,
+ long long num_results)
+{
+ struct HistoryState *hs;
+
+ hs = GNUNET_new (struct HistoryState);
+ hs->account_url = auth->wire_gateway_url;
+ hs->start_row_reference = start_row_reference;
+ hs->num_results = num_results;
+ hs->auth = *auth;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = hs,
+ .run = &history_run,
+ .cleanup = &history_cleanup,
+ .traits = &history_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_bank_history_debit.c */
diff --git a/src/testing/testing_api_cmd_bank_transfer.c b/src/testing/testing_api_cmd_bank_transfer.c
@@ -0,0 +1,405 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_bank_transfer.c
+ * @brief implementation of a bank /transfer command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "backoff.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_bank_service.h"
+#include "taler_fakebank_lib.h"
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "transfer" CMD.
+ */
+struct TransferState
+{
+
+ /**
+ * Wire transfer amount.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Base URL of the debit account.
+ */
+ const char *account_debit_url;
+
+ /**
+ * Money receiver payto URL.
+ */
+ char *payto_debit_account;
+
+ /**
+ * Money receiver account URL.
+ */
+ const char *payto_credit_account;
+
+ /**
+ * Username to use for authentication.
+ */
+ struct TALER_BANK_AuthenticationData auth;
+
+ /**
+ * Base URL of the exchange.
+ */
+ const char *exchange_base_url;
+
+ /**
+ * Wire transfer identifier to use.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /**
+ * Handle to the pending request at the fakebank.
+ */
+ struct TALER_BANK_WireExecuteHandle *weh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Set to the wire transfer's unique ID.
+ */
+ uint64_t serial_id;
+
+ /**
+ * Timestamp of the transaction (as returned from the bank).
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Configuration filename. Used to get the tip reserve key
+ * filename (used to obtain a public key to write in the
+ * transfer subject).
+ */
+ const char *config_filename;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Was this command modified via
+ * #TALER_TESTING_cmd_admin_add_incoming_with_retry to
+ * enable retries?
+ */
+ int do_retry;
+};
+
+
+/**
+ * Run the "transfer" CMD.
+ *
+ * @param cls closure.
+ * @param cmd CMD being run.
+ * @param is interpreter state.
+ */
+static void
+transfer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #transfer_run.
+ *
+ * @param cls a `struct TransferState`
+ */
+static void
+do_retry (void *cls)
+{
+ struct TransferState *fts = cls;
+
+ fts->retry_task = NULL;
+ transfer_run (fts,
+ NULL,
+ fts->is);
+}
+
+
+/**
+ * This callback will process the fakebank response to the wire
+ * transfer. It just checks whether the HTTP response code is
+ * acceptable.
+ *
+ * @param cls closure with the interpreter state
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
+ * successful status request; 0 if the exchange's reply is
+ * bogus (fails to follow the protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
+ * @param serial_id unique ID of the wire transfer
+ * @param timestamp time stamp of the transaction made.
+ */
+static void
+confirmation_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ uint64_t serial_id,
+ struct GNUNET_TIME_Absolute timestamp)
+{
+ struct TransferState *fts = cls;
+ struct TALER_TESTING_Interpreter *is = fts->is;
+
+ fts->weh = NULL;
+ if (MHD_HTTP_OK != http_status)
+ {
+ if (GNUNET_YES == fts->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying transfer failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ fts->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ fts->backoff = EXCHANGE_LIB_BACKOFF (fts->backoff);
+ fts->retry_task = GNUNET_SCHEDULER_add_delayed
+ (fts->backoff,
+ &do_retry,
+ fts);
+ return;
+ }
+ }
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fakebank returned HTTP status %u/%d\n",
+ http_status,
+ (int) ec);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ fts->serial_id = serial_id;
+ fts->timestamp = timestamp;
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the "transfer" CMD.
+ *
+ * @param cls closure.
+ * @param cmd CMD being run.
+ * @param is interpreter state.
+ */
+static void
+transfer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TransferState *fts = cls;
+ void *buf;
+ size_t buf_size;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Transfer of %s from %s to %s\n",
+ TALER_amount2s (&fts->amount),
+ fts->account_debit_url,
+ fts->payto_credit_account);
+ TALER_BANK_prepare_wire_transfer (fts->payto_credit_account,
+ &fts->amount,
+ fts->exchange_base_url,
+ &fts->wtid,
+ &buf,
+ &buf_size);
+ fts->is = is;
+ fts->weh
+ = TALER_BANK_execute_wire_transfer
+ (TALER_TESTING_interpreter_get_context (is),
+ &fts->auth,
+ buf,
+ buf_size,
+ &confirmation_cb,
+ fts);
+ GNUNET_free (buf);
+ if (NULL == fts->weh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "fakebank transfer" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure
+ * @param cmd current CMD being cleaned up.
+ */
+static void
+transfer_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct TransferState *fts = cls;
+
+ if (NULL != fts->weh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %s did not complete\n",
+ cmd->label);
+ TALER_BANK_execute_wire_transfer_cancel (fts->weh);
+ fts->weh = NULL;
+ }
+ if (NULL != fts->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (fts->retry_task);
+ fts->retry_task = NULL;
+ }
+ GNUNET_free (fts->payto_debit_account);
+ GNUNET_free (fts);
+}
+
+
+/**
+ * Offer internal data from a "fakebank transfer" CMD to other
+ * commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+transfer_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct TransferState *fts = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ fts->exchange_base_url),
+ TALER_TESTING_make_trait_bank_row (&fts->serial_id),
+ TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
+ fts->payto_credit_account),
+ TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
+ fts->payto_debit_account),
+ TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
+ TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
+ TALER_TESTING_make_trait_wtid (0,
+ &fts->wtid),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Create transfer command.
+ *
+ * @param label command label.
+ * @param amount amount to transfer.
+ * @param auth authentication data to use
+ * @param payto_debit_account which account sends money.
+ * @param payto_credit_account which account receives money.
+ * @param wtid wire transfer identifier to use
+ * @param exchange_base_url exchange URL to use
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_transfer (const char *label,
+ const char *amount,
+ const struct TALER_BANK_AuthenticationData *auth,
+ const char *payto_debit_account,
+ const char *payto_credit_account,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ const char *exchange_base_url)
+{
+ struct TransferState *fts;
+
+ fts = GNUNET_new (struct TransferState);
+ fts->account_debit_url = auth->wire_gateway_url;
+ fts->exchange_base_url = exchange_base_url;
+ fts->payto_debit_account = GNUNET_strdup (payto_debit_account);
+ fts->payto_credit_account = payto_credit_account;
+ fts->auth = *auth;
+ fts->wtid = *wtid;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &fts->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %s\n",
+ amount,
+ label);
+ GNUNET_assert (0);
+ }
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = fts,
+ .label = label,
+ .run = &transfer_run,
+ .cleanup = &transfer_cleanup,
+ .traits = &transfer_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a transfer command to enable retries when the reserve is not yet
+ * full or we get other transient errors from the bank.
+ *
+ * @param cmd a fakebank transfer command
+ * @return the command with retries enabled
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_transfer_retry (struct TALER_TESTING_Command cmd)
+{
+ struct TransferState *fts;
+
+ GNUNET_assert (&transfer_run == cmd.run);
+ fts = cmd.cls;
+ fts->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_transfer.c */
diff --git a/src/testing/testing_api_cmd_batch.c b/src/testing/testing_api_cmd_batch.c
@@ -0,0 +1,227 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 testing/testing_api_cmd_batch.c
+ * @brief Implement batch-execution of CMDs.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "batch" CMD.
+ */
+struct BatchState
+{
+ /**
+ * CMDs batch.
+ */
+ struct TALER_TESTING_Command *batch;
+
+ /**
+ * Internal command pointer.
+ */
+ unsigned int batch_ip;
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+batch_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct BatchState *bs = cls;
+
+ if (NULL != bs->batch[bs->batch_ip].label)
+ TALER_LOG_INFO ("Running batched command: %s\n",
+ bs->batch[bs->batch_ip].label);
+
+ /* hit end command, leap to next top-level command. */
+ if (NULL == bs->batch[bs->batch_ip].label)
+ {
+ TALER_LOG_INFO ("Exiting from batch: %s\n",
+ cmd->label);
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+
+ bs->batch[bs->batch_ip].run (bs->batch[bs->batch_ip].cls,
+ &bs->batch[bs->batch_ip],
+ is);
+}
+
+
+/**
+ * Cleanup the state from a "reserve status" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+batch_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct BatchState *bs = cls;
+
+ for (unsigned int i = 0;
+ NULL != bs->batch[i].label;
+ i++)
+ bs->batch[i].cleanup (bs->batch[i].cls,
+ &bs->batch[i]);
+ GNUNET_free_non_null (bs->batch);
+ GNUNET_free (bs);
+}
+
+
+/**
+ * Offer internal data from a "batch" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+batch_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+#define CURRENT_CMD_INDEX 0
+#define BATCH_INDEX 1
+
+ struct BatchState *bs = cls;
+
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_cmd
+ (CURRENT_CMD_INDEX, &bs->batch[bs->batch_ip]),
+ TALER_TESTING_make_trait_cmd
+ (BATCH_INDEX, bs->batch),
+ TALER_TESTING_trait_end ()
+ };
+
+ /* Always return current command. */
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Create a "batch" command. Such command takes a
+ * end_CMD-terminated array of CMDs and executed them.
+ * Once it hits the end CMD, it passes the control
+ * to the next top-level CMD, regardless of it being
+ * another batch or ordinary CMD.
+ *
+ * @param label the command label.
+ * @param batch array of CMDs to execute.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_batch (const char *label,
+ struct TALER_TESTING_Command *batch)
+{
+ struct BatchState *bs;
+ unsigned int i;
+
+ bs = GNUNET_new (struct BatchState);
+
+ /* Get number of commands. */
+ for (i = 0; NULL != batch[i].label; i++)
+ /* noop */
+ ;
+
+ bs->batch = GNUNET_new_array (i + 1,
+ struct TALER_TESTING_Command);
+ memcpy (bs->batch,
+ batch,
+ sizeof (struct TALER_TESTING_Command) * i);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = bs,
+ .label = label,
+ .run = &batch_run,
+ .cleanup = &batch_cleanup,
+ .traits = &batch_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Advance internal pointer to next command.
+ *
+ * @param is interpreter state.
+ */
+void
+TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is)
+{
+ struct BatchState *bs = is->commands[is->ip].cls;
+
+ if (NULL == bs->batch[bs->batch_ip].label)
+ {
+ is->ip++;
+ return;
+ }
+
+ bs->batch_ip++;
+}
+
+
+/**
+ * Test if this command is a batch command.
+ *
+ * @return false if not, true if it is a batch command
+ */
+int
+TALER_TESTING_cmd_is_batch (const struct TALER_TESTING_Command *cmd)
+{
+ return cmd->run == &batch_run;
+}
+
+
+/**
+ * Obtain what command the batch is at.
+ *
+ * @return cmd current batch command
+ */
+struct TALER_TESTING_Command *
+TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
+{
+ struct BatchState *bs = cmd->cls;
+
+ return &bs->batch[bs->batch_ip];
+}
diff --git a/src/testing/testing_api_cmd_check_keys.c b/src/testing/testing_api_cmd_check_keys.c
@@ -0,0 +1,358 @@
+/*
+ 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 testing/testing_api_cmd_check_keys.c
+ * @brief Implementation of "check keys" test command. XXX-NOTE:
+ * the number of 'expected keys' is NOT the number of the
+ * downloaded keys, but rather the number of keys that the
+ * libtalerutil library keeps locally. As for the current
+ * design, keys are _never_ discarded by the library,
+ * therefore their (expected) number is monotonically
+ * ascending.
+ *
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "check keys" CMD.
+ */
+struct CheckKeysState
+{
+ /**
+ * This number will instruct the CMD interpreter to
+ * make sure that /keys was downloaded `generation` times
+ * _before_ running the very CMD logic.
+ */
+ unsigned int generation;
+
+ /**
+ * How many denomination keys the exchange is
+ * supposed to have.
+ */
+ unsigned int num_denom_keys;
+
+ /**
+ * If this value is GNUNET_YES, then the "cherry
+ * picking" facility is turned off; whole /keys is
+ * downloaded.
+ */
+ unsigned int pull_all_keys;
+
+ /**
+ * If GNUNET_YES, then the user must specify the
+ * last_denom_issue_date manually. This way, it is possible
+ * to force whatever X value here (including 0): /keys?last_denom_issue=X.
+ */
+ unsigned int set_last_denom;
+
+ /**
+ * Value X to set as the URL parameter:
+ * "/keys?last_denom_issue=X" is used only when `set_last_denom'
+ * equals GNUNET_YES.
+ */
+ struct GNUNET_TIME_Absolute last_denom_date;
+
+ /**
+ * If GNUNET_YES, then we'll provide the "/keys" request.
+ * with the "now" argument.
+ */
+ int with_now;
+
+ /**
+ * Fake now as passed by the user.
+ */
+ struct GNUNET_TIME_Absolute now;
+
+};
+
+
+/**
+ * Run the "check keys" command.
+ *
+ * @param cls closure.
+ * @param cmd the command currently being executed.
+ * @param is the interpreter state.
+ */
+static void
+check_keys_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct CheckKeysState *cks = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "cmd `%s' (ip: %u), key generation: %d\n",
+ cmd->label,
+ is->ip,
+ is->key_generation);
+
+ if (is->key_generation < cks->generation)
+ {
+ is->working = GNUNET_NO;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Triggering GET /keys, cmd `%s'\n",
+ cmd->label);
+
+ if (GNUNET_YES == cks->set_last_denom)
+ {
+ TALER_LOG_DEBUG ("Forcing last_denom_date URL argument\n");
+ TALER_EXCHANGE_set_last_denom (is->exchange,
+ cks->last_denom_date);
+ }
+
+ if (GNUNET_YES == cks->with_now)
+ TALER_EXCHANGE_set_now (is->exchange,
+ cks->now);
+ /* Redownload /keys. */
+ GNUNET_break
+ (0 == TALER_EXCHANGE_check_keys_current
+ (is->exchange,
+ GNUNET_YES,
+ cks->pull_all_keys).abs_value_us);
+ return;
+ }
+
+#if 0
+ /**
+ * Not sure this check makes sense: GET /keys is performed on
+ * a "maybe" basis, so it can get quite hard to track /keys
+ * request. Rather, this CMD should just check if /keys was
+ * requested AT LEAST n times before going ahead with checks.
+ *///
+ if (is->key_generation > cks->generation)
+ {
+ /* We got /keys too often, strange. Fatal. May theoretically
+ happen if somehow we were really unlucky and /keys expired
+ "naturally", but obviously with a sane configuration this
+ should also not be. */
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Acutal- vs expected key"
+ " generation: %u vs %u\n",
+ is->key_generation,
+ cks->generation);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+#endif
+ /* "/keys" was updated, let's check they were OK! */
+ if (cks->num_denom_keys != is->keys->num_denom_keys)
+ {
+ /* Did not get the expected number of denomination keys! */
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Got %u keys in step %s, expected %u\n",
+ is->keys->num_denom_keys,
+ cmd->label,
+ cks->num_denom_keys);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ /* Let's unset the fake now before moving on. */
+ TALER_EXCHANGE_unset_now (is->exchange);
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+check_keys_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct CheckKeysState *cks = cls;
+
+ GNUNET_free (cks);
+}
+
+
+/**
+ * Make a "check keys" command. This type of command
+ * checks whether the number of denomination keys from
+ * @a exchange matches @a num_denom_keys. Additionally,
+ * it lets the user set a last denom issue date to be
+ * used in the request for /keys.
+ *
+ * @param label command label
+ * @param generation when this command is run, exactly @a
+ * generation /keys downloads took place. If the number
+ * of downloads is less than @a generation, the logic will
+ * first make sure that @a generation downloads are done,
+ * and _then_ execute the rest of the command.
+ * @param num_denom_keys expected number of denomination keys.
+ * @param last_denom_date date to be set in the "last_denom_issue"
+ * URL parameter of /keys.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_keys_with_last_denom (const char *label,
+ unsigned int generation,
+ unsigned int num_denom_keys,
+ struct GNUNET_TIME_Absolute
+ last_denom_date)
+{
+ struct CheckKeysState *cks;
+
+ cks = GNUNET_new (struct CheckKeysState);
+ cks->generation = generation;
+ cks->num_denom_keys = num_denom_keys;
+ cks->set_last_denom = GNUNET_YES;
+ cks->last_denom_date = last_denom_date;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cks,
+ .label = label,
+ .run = &check_keys_run,
+ .cleanup = &check_keys_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make a "check keys" command. This type of command
+ * checks whether the number of denomination keys from
+ * @a exchange matches @a num_denom_keys.
+ *
+ * @param label command label
+ * @param generation when this command is run, exactly @a
+ * generation /keys downloads took place. If the number
+ * of downloads is less than @a generation, the logic will
+ * first make sure that @a generation downloads are done,
+ * and _then_ execute the rest of the command.
+ * @param num_denom_keys expected number of denomination keys.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_keys (const char *label,
+ unsigned int generation,
+ unsigned int num_denom_keys)
+{
+ struct CheckKeysState *cks;
+
+ cks = GNUNET_new (struct CheckKeysState);
+ cks->generation = generation;
+ cks->num_denom_keys = num_denom_keys;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cks,
+ .label = label,
+ .run = &check_keys_run,
+ .cleanup = &check_keys_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make a "check keys" command. This type of command
+ * checks whether the number of denomination keys from
+ * @a exchange matches @a num_denom_keys.
+ *
+ * @param label command label
+ * @param generation when this command is run, exactly @a
+ * generation /keys downloads took place. If the number
+ * of downloads is less than @a generation, the logic will
+ * first make sure that @a generation downloads are done,
+ * and _then_ execute the rest of the command.
+ * @param num_denom_keys expected number of denomination keys.
+ * @param now timestamp to use when fetching keys
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_keys_with_now (const char *label,
+ unsigned int generation,
+ unsigned int num_denom_keys,
+ struct GNUNET_TIME_Absolute now)
+{
+ struct CheckKeysState *cks;
+
+ cks = GNUNET_new (struct CheckKeysState);
+ cks->generation = generation;
+ cks->num_denom_keys = num_denom_keys;
+ cks->now = now;
+ cks->with_now = GNUNET_YES;
+
+ /* Force to NOT cherry pick, otherwise they conflict. */
+ cks->pull_all_keys = GNUNET_YES;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cks,
+ .label = label,
+ .run = &check_keys_run,
+ .cleanup = &check_keys_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make a "check keys" command that forcedly does NOT cherry pick;
+ * just redownload the whole /keys. Then checks whether the number
+ * of denomination keys from @a exchange matches @a num_denom_keys.
+ *
+ * @param label command label
+ * @param generation when this command is run, exactly @a
+ * generation /keys downloads took place. If the number
+ * of downloads is less than @a generation, the logic will
+ * first make sure that @a generation downloads are done,
+ * and _then_ execute the rest of the command.
+ * @param num_denom_keys expected number of denomination keys.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_check_keys_pull_all_keys (const char *label,
+ unsigned int generation,
+ unsigned int num_denom_keys)
+{
+ struct CheckKeysState *cks;
+
+ cks = GNUNET_new (struct CheckKeysState);
+ cks->generation = generation;
+ cks->num_denom_keys = num_denom_keys;
+ cks->pull_all_keys = GNUNET_YES;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cks,
+ .label = label,
+ .run = &check_keys_run,
+ .cleanup = &check_keys_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_check_keys.c */
diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c
@@ -0,0 +1,567 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_deposit.c
+ * @brief command for testing /deposit.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "deposit" CMD.
+ */
+struct DepositState
+{
+
+ /**
+ * Amount to deposit.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Reference to any command that is able to provide a coin.
+ */
+ const char *coin_reference;
+
+ /**
+ * If @e coin_reference refers to an operation that generated
+ * an array of coins, this value determines which coin to pick.
+ */
+ unsigned int coin_index;
+
+ /**
+ * Wire details of who is depositing -- this would be merchant
+ * wire details in a normal scenario.
+ */
+ json_t *wire_details;
+
+ /**
+ * JSON string describing what a proposal is about.
+ */
+ json_t *contract_terms;
+
+ /**
+ * Refund deadline. Zero for no refunds.
+ */
+ struct GNUNET_TIME_Absolute refund_deadline;
+
+ /**
+ * Set (by the interpreter) to a fresh private key. This
+ * key will be used to sign the deposit request.
+ */
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+
+ /**
+ * Deposit handle while operation is running.
+ */
+ struct TALER_EXCHANGE_DepositHandle *dh;
+
+ /**
+ * Timestamp of the /deposit operation.
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Should we retry on (transient) failures?
+ */
+ int do_retry;
+
+ /**
+ * Set to #GNUNET_YES if the /deposit succeeded
+ * and we now can provide the resulting traits.
+ */
+ int traits_ready;
+
+ /**
+ * Signing key used by the exchange to sign the
+ * deposit confirmation.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * Signature from the exchange on the
+ * deposit confirmation.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+deposit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #deposit_run.
+ *
+ * @param cls a `struct DepositState`
+ */
+static void
+do_retry (void *cls)
+{
+ struct DepositState *ds = cls;
+
+ ds->retry_task = NULL;
+ deposit_run (ds,
+ NULL,
+ ds->is);
+}
+
+
+/**
+ * Callback to analyze the /deposit response, just used to
+ * check if the response code is acceptable.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param exchange_sig signature provided by the exchange
+ * (NULL on errors)
+ * @param exchange_pub public key of the exchange,
+ * used for signing the response.
+ * @param obj raw response from the exchange.
+ */
+static void
+deposit_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const struct TALER_ExchangeSignatureP *exchange_sig,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const json_t *obj)
+{
+ struct DepositState *ds = cls;
+
+ ds->dh = NULL;
+ if (ds->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == ds->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying deposit failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ ds->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ ds->backoff = EXCHANGE_LIB_BACKOFF (ds->backoff);
+ ds->retry_task
+ = GNUNET_SCHEDULER_add_delayed (ds->backoff,
+ &do_retry,
+ ds);
+ return;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ ds->is->commands[ds->is->ip].label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (obj, stderr, 0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return;
+ }
+ if (MHD_HTTP_OK == http_status)
+ {
+ ds->traits_ready = GNUNET_YES;
+ ds->exchange_pub = *exchange_pub;
+ ds->exchange_sig = *exchange_sig;
+ }
+ TALER_TESTING_interpreter_next (ds->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+deposit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct DepositState *ds = cls;
+ const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ const struct TALER_DenominationSignature *denom_pub_sig;
+ struct TALER_CoinSpendSignatureP coin_sig;
+ struct GNUNET_TIME_Absolute wire_deadline;
+ struct GNUNET_CRYPTO_EddsaPrivateKey *merchant_priv;
+ struct TALER_MerchantPublicKeyP merchant_pub;
+ struct GNUNET_HashCode h_contract_terms;
+
+ ds->is = is;
+ GNUNET_assert (ds->coin_reference);
+ coin_cmd = TALER_TESTING_interpreter_lookup_command
+ (is,
+ ds->coin_reference);
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if ( (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ ds->coin_index,
+ &coin_priv)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (coin_cmd,
+ ds->coin_index,
+ &denom_pub)) ||
+ (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (coin_cmd,
+ ds->coin_index,
+ &denom_pub_sig)) ||
+ (GNUNET_OK !=
+ TALER_JSON_hash (ds->contract_terms,
+ &h_contract_terms)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pub.eddsa_pub);
+
+ merchant_priv = GNUNET_CRYPTO_eddsa_key_create ();
+ ds->merchant_priv.eddsa_priv = *merchant_priv;
+ GNUNET_free (merchant_priv);
+
+ if (0 != ds->refund_deadline.abs_value_us)
+ {
+ struct GNUNET_TIME_Relative refund_deadline;
+
+ refund_deadline = GNUNET_TIME_absolute_get_remaining (ds->refund_deadline);
+ wire_deadline = GNUNET_TIME_relative_to_absolute
+ (GNUNET_TIME_relative_multiply (refund_deadline, 2));
+ }
+ else
+ {
+ ds->refund_deadline = ds->timestamp;
+ wire_deadline = GNUNET_TIME_relative_to_absolute
+ (GNUNET_TIME_UNIT_ZERO);
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
+ &merchant_pub.eddsa_pub);
+
+ (void) GNUNET_TIME_round_abs (&wire_deadline);
+
+ {
+ struct TALER_DepositRequestPS dr;
+
+ memset (&dr, 0, sizeof (dr));
+ dr.purpose.size = htonl
+ (sizeof (struct TALER_DepositRequestPS));
+ dr.purpose.purpose = htonl
+ (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ dr.h_contract_terms = h_contract_terms;
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_merchant_wire_signature_hash (ds->wire_details,
+ &dr.h_wire));
+ dr.timestamp = GNUNET_TIME_absolute_hton (ds->timestamp);
+ dr.refund_deadline = GNUNET_TIME_absolute_hton
+ (ds->refund_deadline);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &ds->amount);
+ TALER_amount_hton (&dr.deposit_fee,
+ &denom_pub->fee_deposit);
+ dr.merchant = merchant_pub;
+ dr.coin_pub = coin_pub;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
+ &dr.purpose,
+ &coin_sig.eddsa_signature));
+ }
+ ds->dh = TALER_EXCHANGE_deposit (is->exchange,
+ &ds->amount,
+ wire_deadline,
+ ds->wire_details,
+ &h_contract_terms,
+ &coin_pub,
+ denom_pub_sig,
+ &denom_pub->key,
+ ds->timestamp,
+ &merchant_pub,
+ ds->refund_deadline,
+ &coin_sig,
+ &deposit_cb,
+ ds);
+
+ if (NULL == ds->dh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "deposit" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct DepositState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+deposit_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct DepositState *ds = cls;
+
+ if (NULL != ds->dh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ ds->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_deposit_cancel (ds->dh);
+ ds->dh = NULL;
+ }
+ if (NULL != ds->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (ds->retry_task);
+ ds->retry_task = NULL;
+ }
+ json_decref (ds->wire_details);
+ json_decref (ds->contract_terms);
+ GNUNET_free (ds);
+}
+
+
+/**
+ * Offer internal data from a "deposit" CMD, to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ *
+ * @return #GNUNET_OK on success.
+ */
+static int
+deposit_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct DepositState *ds = cls;
+ const struct TALER_TESTING_Command *coin_cmd;
+ /* Will point to coin cmd internals. */
+ const struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
+
+ coin_cmd
+ = TALER_TESTING_interpreter_lookup_command (ds->is,
+ ds->coin_reference);
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return GNUNET_NO;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ ds->coin_index,
+ &coin_spent_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ds->is);
+ return GNUNET_NO;
+ }
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ /* First two traits are only available if
+ ds->traits is #GNUNET_YES */
+ TALER_TESTING_make_trait_exchange_pub (0,
+ &ds->exchange_pub),
+ TALER_TESTING_make_trait_exchange_sig (0,
+ &ds->exchange_sig),
+ /* These traits are always available */
+ TALER_TESTING_make_trait_coin_priv (0,
+ coin_spent_priv),
+ TALER_TESTING_make_trait_wire_details (0,
+ ds->wire_details),
+ TALER_TESTING_make_trait_contract_terms (0,
+ ds->contract_terms),
+ TALER_TESTING_make_trait_merchant_priv (0,
+ &ds->merchant_priv),
+ TALER_TESTING_make_trait_amount_obj (0,
+ &ds->amount),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait ((ds->traits_ready)
+ ? traits
+ : &traits[2],
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+/**
+ * Create a "deposit" command.
+ *
+ * @param label command label.
+ * @param coin_reference reference to any operation that can
+ * provide a coin.
+ * @param coin_index if @a withdraw_reference offers an array of
+ * coins, this parameter selects which one in that array.
+ * This value is currently ignored, as only one-coin
+ * withdrawals are implemented.
+ * @param target_account_payto target account for the "deposit"
+ * request.
+ * @param contract_terms contract terms to be signed over by the
+ * coin.
+ * @param refund_deadline refund deadline, zero means 'no refunds'.
+ * Note, if time were absolute, then it would have come
+ * one day and disrupt tests meaning.
+ * @param amount how much is going to be deposited.
+ * @param expected_response_code expected HTTP response code.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_deposit (const char *label,
+ const char *coin_reference,
+ unsigned int coin_index,
+ const char *target_account_payto,
+ const char *contract_terms,
+ struct GNUNET_TIME_Relative refund_deadline,
+ const char *amount,
+ unsigned int expected_response_code)
+{
+ struct DepositState *ds;
+ json_t *wire_details;
+
+ wire_details = TALER_TESTING_make_wire_details (target_account_payto);
+ ds = GNUNET_new (struct DepositState);
+ ds->coin_reference = coin_reference;
+ ds->coin_index = coin_index;
+ ds->wire_details = wire_details;
+ ds->contract_terms = json_loads (contract_terms,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == ds->contract_terms)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse contract terms `%s' for CMD `%s'\n",
+ contract_terms,
+ label);
+ GNUNET_assert (0);
+ }
+ ds->timestamp = GNUNET_TIME_absolute_get ();
+ (void) GNUNET_TIME_round_abs (&ds->timestamp);
+
+ json_object_set_new (ds->contract_terms,
+ "timestamp",
+ GNUNET_JSON_from_time_abs (ds->timestamp));
+ if (0 != refund_deadline.rel_value_us)
+ {
+ ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
+ (void) GNUNET_TIME_round_abs (&ds->refund_deadline);
+ json_object_set_new (ds->contract_terms,
+ "refund_deadline",
+ GNUNET_JSON_from_time_abs (ds->refund_deadline));
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (amount,
+ &ds->amount));
+ ds->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ds,
+ .label = label,
+ .run = &deposit_run,
+ .cleanup = &deposit_cleanup,
+ .traits = &deposit_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a deposit command to enable retries when we get transient
+ * errors from the exchange.
+ *
+ * @param cmd a deposit command
+ * @return the command with retries enabled
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_deposit_with_retry (struct TALER_TESTING_Command cmd)
+{
+ struct DepositState *ds;
+
+ GNUNET_assert (&deposit_run == cmd.run);
+ ds = cmd.cls;
+ ds->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_deposit.c */
diff --git a/src/testing/testing_api_cmd_exec_aggregator.c b/src/testing/testing_api_cmd_exec_aggregator.c
@@ -0,0 +1,166 @@
+/*
+ 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 testing/testing_api_cmd_exec_aggregator.c
+ * @brief run the taler-exchange-aggregator command
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "aggregator" CMD.
+ */
+struct AggregatorState
+{
+
+ /**
+ * Aggregator process.
+ */
+ struct GNUNET_OS_Process *aggregator_proc;
+
+ /**
+ * Configuration file used by the aggregator.
+ */
+ const char *config_filename;
+};
+
+
+/**
+ * Run the command. Use the `taler-exchange-aggregator' program.
+ *
+ * @param cls closure.
+ * @param cmd command being run.
+ * @param is interpreter state.
+ */
+static void
+aggregator_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AggregatorState *as = cls;
+
+ as->aggregator_proc
+ = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-aggregator",
+ "taler-exchange-aggregator",
+ "-c", as->config_filename,
+ "-t", /* exit when done */
+ NULL);
+ if (NULL == as->aggregator_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "aggregator" CMD, and possibly kill its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+aggregator_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AggregatorState *as = cls;
+
+ if (NULL != as->aggregator_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (as->aggregator_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (as->aggregator_proc);
+ GNUNET_OS_process_destroy (as->aggregator_proc);
+ as->aggregator_proc = NULL;
+ }
+ GNUNET_free (as);
+}
+
+
+/**
+ * Offer "aggregator" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static int
+aggregator_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AggregatorState *as = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0, &as->aggregator_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make a "aggregator" CMD.
+ *
+ * @param label command label.
+ * @param config_filename configuration file for the
+ * aggregator to use.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_aggregator (const char *label,
+ const char *config_filename)
+{
+ struct AggregatorState *as;
+
+ as = GNUNET_new (struct AggregatorState);
+ as->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = as,
+ .label = label,
+ .run = &aggregator_run,
+ .cleanup = &aggregator_cleanup,
+ .traits = &aggregator_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_aggregator.c */
diff --git a/src/testing/testing_api_cmd_exec_auditor-sign.c b/src/testing/testing_api_cmd_exec_auditor-sign.c
@@ -0,0 +1,232 @@
+/*
+ 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 testing/testing_api_cmd_exec_auditor-sign.c
+ * @brief run the taler-exchange-aggregator command
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "auditor sign" CMD.
+ */
+struct AuditorSignState
+{
+
+ /**
+ * Handle to the process making the signature.
+ */
+ struct GNUNET_OS_Process *auditor_sign_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+
+ /**
+ * File name of signed blob.
+ */
+ char *signed_keys_out;
+};
+
+
+/**
+ * Run the command; calls the `taler-auditor-sign' program.
+ *
+ * @param cls closure.
+ * @param cmd the command.
+ * @param is interpreter state.
+ */
+static void
+auditor_sign_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct AuditorSignState *ass = cls;
+
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ char *test_home_dir;
+ char *exchange_master_pub;
+ struct GNUNET_TIME_Absolute now;
+
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK != GNUNET_CONFIGURATION_load
+ (cfg, ass->config_filename))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "paths",
+ "TALER_TEST_HOME",
+ &test_home_dir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "paths",
+ "TALER_TEST_HOME");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ now = GNUNET_TIME_absolute_get ();
+ GNUNET_asprintf
+ (&ass->signed_keys_out,
+ "%s/.local/share/taler/auditors/auditor-%llu.out",
+ test_home_dir,
+ (unsigned long long) now.abs_value_us);
+ GNUNET_free (test_home_dir);
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "MASTER_PUBLIC_KEY",
+ &exchange_master_pub))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "MASTER_PUBLIC_KEY");
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ ass->auditor_sign_proc = GNUNET_OS_start_process
+ (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-sign",
+ "taler-auditor-sign",
+ "-c", ass->config_filename,
+ "-u", "http://auditor/",
+ "-m", exchange_master_pub,
+ "-r", "auditor.in",
+ "-o", ass->signed_keys_out,
+ NULL);
+ GNUNET_free (exchange_master_pub);
+ if (NULL == ass->auditor_sign_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "auditor sign" CMD, and possibly
+ * kill its process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+auditor_sign_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct AuditorSignState *ass = cls;
+
+ if (NULL != ass->auditor_sign_proc)
+ {
+ GNUNET_break (0 == GNUNET_OS_process_kill
+ (ass->auditor_sign_proc, SIGKILL));
+ GNUNET_OS_process_wait (ass->auditor_sign_proc);
+ GNUNET_OS_process_destroy (ass->auditor_sign_proc);
+ ass->auditor_sign_proc = NULL;
+ }
+ GNUNET_free_non_null (ass->signed_keys_out);
+ GNUNET_free (ass);
+}
+
+
+/**
+ * Offer "auditor sign" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+auditor_sign_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct AuditorSignState *ass = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0, &ass->auditor_sign_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make a "auditor sign" CMD.
+ *
+ * @param label command label
+ * @param config_filename configuration filename
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_auditor_sign (const char *label,
+ const char *config_filename)
+{
+ struct AuditorSignState *ass;
+
+ ass = GNUNET_new (struct AuditorSignState);
+ ass->config_filename = config_filename;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ass,
+ .label = label,
+ .run = &auditor_sign_run,
+ .cleanup = &auditor_sign_cleanup,
+ .traits = &auditor_sign_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_auditor-sign.c */
diff --git a/src/testing/testing_api_cmd_exec_keyup.c b/src/testing/testing_api_cmd_exec_keyup.c
@@ -0,0 +1,235 @@
+/*
+ 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 testing/testing_api_cmd_exec_keyup.c
+ * @brief run the taler-exchange-keyup command
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "keyup" CMD.
+ */
+struct KeyupState
+{
+
+ /**
+ * Process for the "keyup" command.
+ */
+ struct GNUNET_OS_Process *keyup_proc;
+
+ /**
+ * Configuration file used by the command.
+ */
+ const char *config_filename;
+
+ /**
+ * If GNUNET_YES, then the fake @e now value will be
+ * passed to taler-exchange-keyup via the --time
+ * option.
+ */
+ unsigned int with_now;
+
+ /**
+ * User-provided fake now.
+ */
+ struct GNUNET_TIME_Absolute now;
+};
+
+
+/**
+ * Run the command; calls the `taler-exchange-keyup' program.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+keyup_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct KeyupState *ks = cls;
+
+ if (GNUNET_YES == ks->with_now)
+ {
+ ks->keyup_proc = GNUNET_OS_start_process
+ (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-c", ks->config_filename,
+ "-o", "auditor.in",
+ "--time",
+ GNUNET_STRINGS_absolute_time_to_string (ks->now),
+ NULL);
+ }
+ else
+ ks->keyup_proc = GNUNET_OS_start_process
+ (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-c", ks->config_filename,
+ "-o", "auditor.in",
+ NULL);
+
+ if (NULL == ks->keyup_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ /* This function does not tell whether the command
+ * succeeded or not! */
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "keyup" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+keyup_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct KeyupState *ks = cls;
+
+ if (NULL != ks->keyup_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ks->keyup_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ks->keyup_proc);
+ GNUNET_OS_process_destroy (ks->keyup_proc);
+ ks->keyup_proc = NULL;
+ }
+ GNUNET_free (ks);
+}
+
+
+/**
+ * Offer "keyup" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ *
+ * @return #GNUNET_OK on success.
+ */
+static int
+keyup_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct KeyupState *ks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0, &ks->keyup_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make the "keyup" CMD, with "--timestamp" option.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @param now Unix timestamp representing the fake "now".
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_keyup_with_now
+ (const char *label,
+ const char *config_filename,
+ struct GNUNET_TIME_Absolute now)
+{
+ struct KeyupState *ks;
+
+ ks = GNUNET_new (struct KeyupState);
+ ks->config_filename = config_filename;
+ ks->now = now;
+ ks->with_now = GNUNET_YES;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &keyup_run,
+ .cleanup = &keyup_cleanup,
+ .traits = &keyup_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make the "keyup" CMD.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_keyup (const char *label,
+ const char *config_filename)
+{
+ struct KeyupState *ks;
+
+ ks = GNUNET_new (struct KeyupState);
+ ks->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ks,
+ .label = label,
+ .run = &keyup_run,
+ .cleanup = &keyup_cleanup,
+ .traits = &keyup_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_keyup.c */
diff --git a/src/testing/testing_api_cmd_exec_wirewatch.c b/src/testing/testing_api_cmd_exec_wirewatch.c
@@ -0,0 +1,167 @@
+/*
+ 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 testing/testing_api_cmd_exec_wirewatch.c
+ * @brief run the taler-exchange-wirewatch command
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "wirewatch" CMD.
+ */
+struct WirewatchState
+{
+
+ /**
+ * Process for the wirewatcher.
+ */
+ struct GNUNET_OS_Process *wirewatch_proc;
+
+ /**
+ * Configuration file used by the wirewatcher.
+ */
+ const char *config_filename;
+};
+
+/**
+ * Run the command; use the `taler-exchange-wirewatch' program.
+ *
+ * @param cls closure.
+ * @param cmd command currently being executed.
+ * @param is interpreter state.
+ */
+static void
+wirewatch_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct WirewatchState *ws = cls;
+
+ ws->wirewatch_proc
+ = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-wirewatch",
+ "taler-exchange-wirewatch",
+ "-c", ws->config_filename,
+ "-T", /* exit when done */
+ NULL);
+ if (NULL == ws->wirewatch_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Free the state of a "wirewatch" CMD, and possibly
+ * kills its process if it did not terminate regularly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+wirewatch_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct WirewatchState *ws = cls;
+
+ if (NULL != ws->wirewatch_proc)
+ {
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (ws->wirewatch_proc,
+ SIGKILL));
+ GNUNET_OS_process_wait (ws->wirewatch_proc);
+ GNUNET_OS_process_destroy (ws->wirewatch_proc);
+ ws->wirewatch_proc = NULL;
+ }
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Offer "wirewatch" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+wirewatch_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct WirewatchState *ws = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_process (0,
+ &ws->wirewatch_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Make a "wirewatch" CMD.
+ *
+ * @param label command label.
+ * @param config_filename configuration filename.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_exec_wirewatch (const char *label,
+ const char *config_filename)
+{
+ struct WirewatchState *ws;
+
+ ws = GNUNET_new (struct WirewatchState);
+ ws->config_filename = config_filename;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &wirewatch_run,
+ .cleanup = &wirewatch_cleanup,
+ .traits = &wirewatch_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_exec_wirewatch.c */
diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c
@@ -0,0 +1,318 @@
+/*
+ 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 testing/testing_api_cmd_insert_deposit.c
+ * @brief deposit a coin directly into the database.
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+#include "taler_exchangedb_plugin.h"
+
+
+/**
+ * State for a "insert-deposit" CMD.
+ */
+struct InsertDepositState
+{
+ /**
+ * Configuration file used by the command.
+ */
+ const struct TALER_TESTING_DatabaseConnection *dbc;
+
+ /**
+ * Human-readable name of the shop.
+ */
+ const char *merchant_name;
+
+ /**
+ * Merchant account name (NOT a payto-URI).
+ */
+ const char *merchant_account;
+
+ /**
+ * Deadline before which the aggregator should
+ * send the payment to the merchant.
+ */
+ struct GNUNET_TIME_Relative wire_deadline;
+
+ /**
+ * Amount to deposit, inclusive of deposit fee.
+ */
+ const char *amount_with_fee;
+
+ /**
+ * Deposit fee.
+ */
+ const char *deposit_fee;
+};
+
+/**
+ * Setup (fake) information about a coin used in deposit.
+ *
+ * @param[out] issue information to initialize with "valid" data
+ */
+static void
+fake_issue (struct TALER_EXCHANGEDB_DenominationKeyInformationP *issue)
+{
+ memset (issue, 0, sizeof (struct
+ TALER_EXCHANGEDB_DenominationKeyInformationP));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:1",
+ &issue->properties.value));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_withdraw));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_deposit));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_refresh));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount_nbo ("EUR:0.1",
+ &issue->properties.fee_refund));
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+insert_deposit_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct InsertDepositState *ids = cls;
+ struct TALER_EXCHANGEDB_Deposit deposit;
+ struct TALER_MerchantPrivateKeyP merchant_priv;
+ struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
+ struct TALER_DenominationPublicKey dpk;
+ struct GNUNET_CRYPTO_RsaPrivateKey *denom_priv;
+ struct GNUNET_HashCode hc;
+
+ // prepare and store issue first.
+ fake_issue (&issue);
+ denom_priv = GNUNET_CRYPTO_rsa_private_key_create (1024);
+ dpk.rsa_public_key = GNUNET_CRYPTO_rsa_private_key_get_public (denom_priv);
+ GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key,
+ &issue.properties.denom_hash);
+
+ if ( (GNUNET_OK !=
+ ids->dbc->plugin->start (ids->dbc->plugin->cls,
+ ids->dbc->session,
+ "talertestinglib: denomination insertion")) ||
+ (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ ids->dbc->plugin->insert_denomination_info (ids->dbc->plugin->cls,
+ ids->dbc->session,
+ &dpk,
+ &issue)) ||
+ (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+ ids->dbc->plugin->commit (ids->dbc->plugin->cls,
+ ids->dbc->session)) )
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ /* prepare and store deposit now. */
+ memset (&deposit,
+ 0,
+ sizeof (deposit));
+
+ GNUNET_CRYPTO_kdf (&merchant_priv,
+ sizeof (struct TALER_MerchantPrivateKeyP),
+ "merchant-priv",
+ strlen ("merchant-priv"),
+ ids->merchant_name,
+ strlen (ids->merchant_name),
+ NULL,
+ 0);
+ GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv.eddsa_priv,
+ &deposit.merchant_pub.eddsa_pub);
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &deposit.h_contract_terms);
+ if ( (GNUNET_OK !=
+ TALER_string_to_amount (ids->amount_with_fee,
+ &deposit.amount_with_fee)) ||
+ (GNUNET_OK !=
+ TALER_string_to_amount (ids->deposit_fee,
+ &deposit.deposit_fee)) )
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_CRYPTO_rsa_public_key_hash (dpk.rsa_public_key,
+ &deposit.coin.denom_pub_hash);
+
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
+ &hc);
+ deposit.coin.denom_sig.rsa_signature = GNUNET_CRYPTO_rsa_sign_fdh (denom_priv,
+ &hc);
+ {
+ char *str;
+
+ GNUNET_asprintf (&str,
+ "payto://x-taler-bank/localhost/%s",
+ ids->merchant_account);
+ deposit.receiver_wire_account
+ = json_pack ("{s:s, s:s}",
+ "salt", "this-is-a-salt-value",
+ "url", str);
+ GNUNET_free (str);
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_merchant_wire_signature_hash (
+ deposit.receiver_wire_account,
+ &deposit.h_wire));
+ deposit.timestamp = GNUNET_TIME_absolute_get ();
+ GNUNET_TIME_round_abs (&deposit.timestamp);
+ deposit.wire_deadline = GNUNET_TIME_relative_to_absolute (
+ ids->wire_deadline);
+ GNUNET_TIME_round_abs (&deposit.wire_deadline);
+
+ /* finally, actually perform the DB operation */
+ if ( (GNUNET_OK !=
+ ids->dbc->plugin->start (ids->dbc->plugin->cls,
+ ids->dbc->session,
+ "libtalertesting: insert deposit")) ||
+ (0 >
+ ids->dbc->plugin->ensure_coin_known (ids->dbc->plugin->cls,
+ ids->dbc->session,
+ &deposit.coin)) ||
+ (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls,
+ ids->dbc->session,
+ &deposit)) ||
+ (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
+ ids->dbc->plugin->commit (ids->dbc->plugin->cls,
+ ids->dbc->session)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ }
+
+ GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig.rsa_signature);
+ GNUNET_CRYPTO_rsa_public_key_free (dpk.rsa_public_key);
+ GNUNET_CRYPTO_rsa_private_key_free (denom_priv);
+ json_decref (deposit.receiver_wire_account);
+
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Free the state of a "auditor-dbinit" CMD, and possibly kills its
+ * process if it did not terminate correctly.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+insert_deposit_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct InsertDepositState *ids = cls;
+
+ GNUNET_free (ids);
+}
+
+
+/**
+ * Offer "insert-deposit" CMD internal data to other commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+insert_deposit_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ (void) cls;
+ (void) ret;
+ (void) trait;
+ (void) index;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Make the "insert-deposit" CMD.
+ *
+ * @param label command label.
+ * @param dbc collects database plugin and session handles.
+ * @param merchant_name Human-readable name of the merchant.
+ * @param merchant_account merchant's account name (NOT a payto:// URI)
+ * @param wire_deadline point in time where the aggregator should have
+ * wired money to the merchant.
+ * @param amount_with_fee amount to deposit (inclusive of deposit fee)
+ * @param deposit_fee deposit fee
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_insert_deposit (const char *label,
+ const struct
+ TALER_TESTING_DatabaseConnection *dbc,
+ const char *merchant_name,
+ const char *merchant_account,
+ struct GNUNET_TIME_Relative wire_deadline,
+ const char *amount_with_fee,
+ const char *deposit_fee)
+{
+ struct InsertDepositState *ids;
+
+ ids = GNUNET_new (struct InsertDepositState);
+ ids->dbc = dbc;
+ ids->merchant_name = merchant_name;
+ ids->merchant_account = merchant_account;
+ ids->wire_deadline = wire_deadline;
+ ids->amount_with_fee = amount_with_fee;
+ ids->deposit_fee = deposit_fee;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ids,
+ .label = label,
+ .run = &insert_deposit_run,
+ .cleanup = &insert_deposit_cleanup,
+ .traits = &insert_deposit_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_insert_deposit.c */
diff --git a/src/testing/testing_api_cmd_recoup.c b/src/testing/testing_api_cmd_recoup.c
@@ -0,0 +1,619 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 testing/testing_api_cmd_recoup.c
+ * @brief Implement the /revoke and /recoup test commands.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "revoke" CMD.
+ */
+struct RevokeState
+{
+ /**
+ * Expected HTTP status code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Command that offers a denomination to revoke.
+ */
+ const char *coin_reference;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * The revoke process handle.
+ */
+ struct GNUNET_OS_Process *revoke_proc;
+
+ /**
+ * Configuration file name.
+ */
+ const char *config_filename;
+
+ /**
+ * Encoding of the denomination (to revoke) public key hash.
+ */
+ char *dhks;
+
+};
+
+
+/**
+ * State for a "pay back" CMD.
+ */
+struct RecoupState
+{
+ /**
+ * Expected HTTP status code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Command that offers a reserve private key,
+ * plus a coin to be paid back.
+ */
+ const char *coin_reference;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Amount expected to be paid back.
+ */
+ const char *amount;
+
+ /**
+ * Handle to the ongoing operation.
+ */
+ struct TALER_EXCHANGE_RecoupHandle *ph;
+
+ /**
+ * NULL if coin was not refreshed, otherwise reference
+ * to the melt operation underlying @a coin_reference.
+ */
+ const char *melt_reference;
+
+};
+
+
+/**
+ * Parser reference to a coin.
+ *
+ * @param coin_reference of format $LABEL['#' $INDEX]?
+ * @param[out] cref where we return a copy of $LABEL
+ * @param[out] idx where we set $INDEX
+ * @return #GNUNET_SYSERR if $INDEX is present but not numeric
+ */
+static int
+parse_coin_reference (const char *coin_reference,
+ char **cref,
+ unsigned int *idx)
+{
+ const char *index;
+
+ /* We allow command references of the form "$LABEL#$INDEX" or
+ just "$LABEL", which implies the index is 0. Figure out
+ which one it is. */
+ index = strchr (coin_reference, '#');
+ if (NULL == index)
+ {
+ *idx = 0;
+ *cref = GNUNET_strdup (coin_reference);
+ return GNUNET_OK;
+ }
+ *cref = GNUNET_strndup (coin_reference,
+ index - coin_reference);
+ if (1 != sscanf (index + 1,
+ "%u",
+ idx))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Numeric index (not `%s') required after `#' in command reference of command in %s:%u\n",
+ index,
+ __FILE__,
+ __LINE__);
+ GNUNET_free (*cref);
+ *cref = NULL;
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check the result of the recoup request: checks whether
+ * the HTTP response code is good, and that the coin that
+ * was paid back belonged to the right reserve.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param amount amount the exchange will wire back for this coin.
+ * @param timestamp what time did the exchange receive the
+ * /recoup request
+ * @param reserve_pub public key of the reserve receiving the recoup, NULL if refreshed or on error
+ * @param old_coin_pub public key of the dirty coin, NULL if not refreshed or on error
+ * @param full_response raw response from the exchange.
+ */
+static void
+recoup_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const struct TALER_Amount *amount,
+ struct GNUNET_TIME_Absolute timestamp,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ const struct TALER_CoinSpendPublicKeyP *old_coin_pub,
+ const json_t *full_response)
+{
+ struct RecoupState *ps = cls;
+ struct TALER_TESTING_Interpreter *is = ps->is;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+ const struct TALER_TESTING_Command *reserve_cmd;
+ char *cref;
+ unsigned int idx;
+
+ ps->ph = NULL;
+ if (ps->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ cmd->label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (full_response, stderr, 0);
+ fprintf (stderr, "\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ parse_coin_reference (ps->coin_reference,
+ &cref,
+ &idx))
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ reserve_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, cref);
+ GNUNET_free (cref);
+
+ if (NULL == reserve_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ /* first, check amount */
+ {
+ struct TALER_Amount expected_amount;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (ps->amount, &expected_amount))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (0 != TALER_amount_cmp (amount, &expected_amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Total amount missmatch to command %s\n",
+ cmd->label);
+ json_dumpf (full_response, stderr, 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ /* now, check old_coin_pub or reserve_pub, respectively */
+ if (NULL != ps->melt_reference)
+ {
+ const struct TALER_TESTING_Command *melt_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *dirty_priv;
+ struct TALER_CoinSpendPublicKeyP oc;
+
+ melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ ps->melt_reference);
+ if (NULL == melt_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (melt_cmd,
+ 0,
+ &dirty_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv,
+ &oc.eddsa_pub);
+ if (0 != GNUNET_memcmp (&oc,
+ old_coin_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ else
+ {
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+ struct TALER_ReservePublicKeyP rp;
+
+ if (NULL == reserve_pub)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv
+ (reserve_cmd, idx, &reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
+ &rp.eddsa_pub);
+ if (0 != GNUNET_memcmp (reserve_pub, &rp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unmanaged HTTP status code %u.\n",
+ http_status);
+ break;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+recoup_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RecoupState *ps = cls;
+ const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ const struct TALER_DenominationBlindingKeyP *blinding_key;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+ const struct TALER_DenominationSignature *coin_sig;
+ struct TALER_PlanchetSecretsP planchet;
+ char *cref;
+ unsigned int idx;
+
+ ps->is = is;
+ if (GNUNET_OK !=
+ parse_coin_reference (ps->coin_reference,
+ &cref,
+ &idx))
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ coin_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, cref);
+ GNUNET_free (cref);
+
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
+ (coin_cmd, idx, &coin_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_blinding_key
+ (coin_cmd, idx, &blinding_key))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ planchet.coin_priv = *coin_priv;
+ planchet.blinding_key = *blinding_key;
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
+ (coin_cmd, idx, &denom_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig
+ (coin_cmd, idx, &coin_sig))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Trying to get '%s..' paid back\n",
+ TALER_B2S (&denom_pub->h_key));
+
+ ps->ph = TALER_EXCHANGE_recoup (is->exchange,
+ denom_pub,
+ coin_sig,
+ &planchet,
+ NULL != ps->melt_reference,
+ recoup_cb,
+ ps);
+ GNUNET_assert (NULL != ps->ph);
+}
+
+
+/**
+ * Cleanup the state.
+ *
+ * @param cls closure, must be a `struct RevokeState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+revoke_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RevokeState *rs = cls;
+
+ if (NULL != rs->revoke_proc)
+ {
+ GNUNET_break (0 == GNUNET_OS_process_kill
+ (rs->revoke_proc, SIGKILL));
+ GNUNET_OS_process_wait (rs->revoke_proc);
+ GNUNET_OS_process_destroy (rs->revoke_proc);
+ rs->revoke_proc = NULL;
+ }
+ GNUNET_free_non_null (rs->dhks);
+ GNUNET_free (rs);
+}
+
+
+/**
+ * Cleanup the "recoup" CMD state, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+recoup_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RecoupState *ps = cls;
+ if (NULL != ps->ph)
+ {
+ TALER_EXCHANGE_recoup_cancel (ps->ph);
+ ps->ph = NULL;
+ }
+ GNUNET_free (ps);
+}
+
+
+/**
+ * Offer internal data from a "revoke" CMD to other CMDs.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static int
+revoke_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RevokeState *rs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ /* Needed by the handler which waits the proc'
+ * death and calls the next command */
+ TALER_TESTING_make_trait_process (0, &rs->revoke_proc),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Run the "revoke" command. The core of the function
+ * is to call the "keyup" utility passing it the base32
+ * encoding of the denomination to revoke.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+revoke_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RevokeState *rs = cls;
+ const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
+
+ rs->is = is;
+ /* Get denom pub from trait */
+ coin_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, rs->coin_reference);
+
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_denom_pub
+ (coin_cmd, 0, &denom_pub));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Trying to revoke denom '%s..'\n",
+ TALER_B2S (&denom_pub->h_key));
+
+ rs->dhks = GNUNET_STRINGS_data_to_string_alloc
+ (&denom_pub->h_key, sizeof (struct GNUNET_HashCode));
+
+ rs->revoke_proc = GNUNET_OS_start_process
+ (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-c", rs->config_filename,
+ "-r", rs->dhks,
+ NULL);
+
+ if (NULL == rs->revoke_proc)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Revoke is ongoing..\n");
+
+ is->reload_keys = GNUNET_OK;
+ TALER_TESTING_wait_for_sigchld (is);
+}
+
+
+/**
+ * Make a "recoup" command.
+ *
+ * @param label the command label
+ * @param expected_response_code expected HTTP status code
+ * @param coin_reference reference to any command which
+ * offers a coin & reserve private key.
+ * @param amount denomination to pay back.
+ * @param melt_reference NULL if coin was not refreshed
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_recoup (const char *label,
+ unsigned int expected_response_code,
+ const char *coin_reference,
+ const char *amount,
+ const char *melt_reference)
+{
+ struct RecoupState *ps;
+
+ ps = GNUNET_new (struct RecoupState);
+ ps->expected_response_code = expected_response_code;
+ ps->coin_reference = coin_reference;
+ ps->amount = amount;
+ ps->melt_reference = melt_reference;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ps,
+ .label = label,
+ .run = &recoup_run,
+ .cleanup = &recoup_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make a "revoke" command.
+ *
+ * @param label the command label.
+ * @param expected_response_code expected HTTP status code.
+ * @param coin_reference reference to a CMD that will offer the
+ * denomination to revoke.
+ * @param config_filename configuration file name.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_revoke (const char *label,
+ unsigned int expected_response_code,
+ const char *coin_reference,
+ const char *config_filename)
+{
+
+ struct RevokeState *rs;
+
+ rs = GNUNET_new (struct RevokeState);
+ rs->expected_response_code = expected_response_code;
+ rs->coin_reference = coin_reference;
+ rs->config_filename = config_filename;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rs,
+ .label = label,
+ .run = &revoke_run,
+ .cleanup = &revoke_cleanup,
+ .traits = &revoke_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_refresh.c b/src/testing/testing_api_cmd_refresh.c
@@ -0,0 +1,1410 @@
+/*
+ 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 testing/testing_api_cmd_refresh.c
+ * @brief commands for testing all "refresh" features.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_signatures.h"
+#include "backoff.h"
+
+
+/**
+ * Information about a fresh coin generated by the refresh
+ * operation.
+ */
+struct TALER_TESTING_FreshCoinData
+{
+
+ /**
+ * If @e amount is NULL, this specifies the denomination key to
+ * use. Otherwise, this will be set (by the interpreter) to the
+ * denomination PK matching @e amount.
+ */
+ const struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+ /**
+ * Set (by the interpreter) to the exchange's signature over the
+ * coin's public key.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Set (by the interpreter) to the coin's private key.
+ */
+ struct TALER_CoinSpendPrivateKeyP coin_priv;
+
+ /**
+ * The blinding key (needed for recoup operations).
+ */
+ struct TALER_DenominationBlindingKeyP blinding_key;
+
+};
+
+
+/**
+ * State for a "refresh melt" command.
+ */
+struct RefreshMeltState
+{
+
+ /**
+ * Reference to reserve_withdraw operations for coin to
+ * be used for the /refresh/melt operation.
+ */
+ const char *coin_reference;
+
+ /**
+ * "Crypto data" used in the refresh operation.
+ */
+ char *refresh_data;
+
+ /**
+ * Reference to a previous melt command.
+ */
+ const char *melt_reference;
+
+ /**
+ * Melt handle while operation is running.
+ */
+ struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Array of the denomination public keys
+ * corresponding to the @e num_fresh_coins;
+ */
+ struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
+
+ /**
+ * Private key of the dirty coin being melted.
+ */
+ const struct TALER_CoinSpendPrivateKeyP *melt_priv;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Number of bytes in @e refresh_data.
+ */
+ size_t refresh_data_length;
+
+ /**
+ * Amounts to be generated during melt.
+ */
+ const char **melt_fresh_amounts;
+
+ /**
+ * Number of fresh coins generated by the melt.
+ */
+ unsigned int num_fresh_coins;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * if set to #GNUNET_YES, then two /refresh/melt operations
+ * will be performed. This is needed to trigger the logic
+ * that manages those already-made requests. Note: it
+ * is not possible to just copy-and-paste a test refresh melt
+ * CMD to have the same effect, because every data preparation
+ * generates new planchets that (in turn) make the whole "hash"
+ * different from any previous one, therefore NOT allowing the
+ * exchange to pick any previous /rerfesh/melt operation from
+ * the database.
+ */
+ unsigned int double_melt;
+
+ /**
+ * Should we retry on (transient) failures?
+ */
+ int do_retry;
+
+ /**
+ * Set by the melt callback as it comes from the exchange.
+ */
+ uint16_t noreveal_index;
+};
+
+
+/**
+ * State for a "refresh reveal" CMD.
+ */
+struct RefreshRevealState
+{
+ /**
+ * Link to a "refresh melt" command.
+ */
+ const char *melt_reference;
+
+ /**
+ * Reveal handle while operation is running.
+ */
+ struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
+
+ /**
+ * Convenience struct to keep in one place all the
+ * data related to one fresh coin, set by the reveal callback
+ * as it comes from the exchange.
+ */
+ struct TALER_TESTING_FreshCoinData *fresh_coins;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Number of fresh coins withdrawn, set by the
+ * reveal callback as it comes from the exchange,
+ * it is the length of the @e fresh_coins array.
+ */
+ unsigned int num_fresh_coins;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Should we retry on (transient) failures?
+ */
+ int do_retry;
+
+};
+
+
+/**
+ * State for a "refresh link" CMD.
+ */
+struct RefreshLinkState
+{
+ /**
+ * Link to a "refresh reveal" command.
+ */
+ const char *reveal_reference;
+
+ /**
+ * Handle to the ongoing operation.
+ */
+ struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Should we retry on (transient) failures?
+ */
+ int do_retry;
+
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refresh_reveal_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #refresh_reveal_run.
+ *
+ * @param cls a `struct RefreshRevealState`
+ */
+static void
+do_reveal_retry (void *cls)
+{
+ struct RefreshRevealState *rrs = cls;
+
+ rrs->retry_task = NULL;
+ refresh_reveal_run (rrs,
+ NULL,
+ rrs->is);
+}
+
+
+/**
+ * "refresh reveal" request callback; it checks that the response
+ * code is expected and copies into its command's state the data
+ * coming from the exchange, namely the fresh coins.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param num_coins number of fresh coins created, length of the
+ * @a sigs and @a coin_privs arrays, 0 if the operation
+ * failed.
+ * @param coin_privs array of @a num_coins private keys for the
+ * coins that were created, NULL on error.
+ * @param sigs array of signature over @a num_coins coins,
+ * NULL on error.
+ * @param full_response raw exchange response.
+ */
+static void
+reveal_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ unsigned int num_coins,
+ const struct TALER_PlanchetSecretsP *coin_privs,
+ const struct TALER_DenominationSignature *sigs,
+ const json_t *full_response)
+{
+ struct RefreshRevealState *rrs = cls;
+ const struct TALER_TESTING_Command *melt_cmd;
+
+ rrs->rrh = NULL;
+ if (rrs->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == rrs->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying refresh reveal failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ rrs->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ rrs->backoff = EXCHANGE_LIB_BACKOFF (rrs->backoff);
+ rrs->retry_task = GNUNET_SCHEDULER_add_delayed (rrs->backoff,
+ &do_reveal_retry,
+ rrs);
+ return;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d to command %s in %s:%u\n",
+ http_status,
+ (int) ec,
+ rrs->is->commands[rrs->is->ip].label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (full_response, stderr, 0);
+ TALER_TESTING_interpreter_fail (rrs->is);
+ return;
+ }
+ melt_cmd = TALER_TESTING_interpreter_lookup_command
+ (rrs->is, rrs->melt_reference);
+ if (NULL == melt_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rrs->is);
+ return;
+ }
+ rrs->num_fresh_coins = num_coins;
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ rrs->fresh_coins = GNUNET_new_array (num_coins,
+ struct TALER_TESTING_FreshCoinData);
+ for (unsigned int i = 0; i<num_coins; i++)
+ {
+ struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_pub (melt_cmd,
+ i,
+ &fc->pk))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rrs->is);
+ return;
+ }
+ fc->coin_priv = coin_privs[i].coin_priv;
+ fc->blinding_key = coin_privs[i].blinding_key;
+ fc->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup
+ (sigs[i].rsa_signature);
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unknown HTTP status %d\n",
+ http_status);
+ }
+ TALER_TESTING_interpreter_next (rrs->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refresh_reveal_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RefreshRevealState *rrs = cls;
+ struct RefreshMeltState *rms;
+ const struct TALER_TESTING_Command *melt_cmd;
+
+ rrs->is = is;
+ melt_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, rrs->melt_reference);
+
+ if (NULL == melt_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rrs->is);
+ return;
+ }
+ rms = melt_cmd->cls;
+ rrs->rrh = TALER_EXCHANGE_refresh_reveal
+ (is->exchange,
+ rms->refresh_data_length,
+ rms->refresh_data,
+ rms->noreveal_index,
+ &reveal_cb, rrs);
+
+ if (NULL == rrs->rrh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state from a "refresh reveal" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+refresh_reveal_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RefreshRevealState *rrs = cls;
+
+ if (NULL != rrs->rrh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ rrs->is->ip,
+ cmd->label);
+
+ TALER_EXCHANGE_refresh_reveal_cancel (rrs->rrh);
+ rrs->rrh = NULL;
+ }
+ if (NULL != rrs->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rrs->retry_task);
+ rrs->retry_task = NULL;
+ }
+
+ for (unsigned int j = 0; j < rrs->num_fresh_coins; j++)
+ GNUNET_CRYPTO_rsa_signature_free (rrs->fresh_coins[j].sig.rsa_signature);
+
+ GNUNET_free_non_null (rrs->fresh_coins);
+ rrs->fresh_coins = NULL;
+ rrs->num_fresh_coins = 0;
+ GNUNET_free (rrs);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refresh_link_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #refresh_link_run.
+ *
+ * @param cls a `struct RefreshLinkState`
+ */
+static void
+do_link_retry (void *cls)
+{
+ struct RefreshLinkState *rls = cls;
+
+ rls->retry_task = NULL;
+ refresh_link_run (rls,
+ NULL,
+ rls->is);
+}
+
+
+/**
+ * "refresh link" operation callback, checks that HTTP response
+ * code is expected _and_ that all the linked coins were actually
+ * withdrawn by the "refresh reveal" CMD.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code
+ * @param num_coins number of fresh coins created, length of the
+ * @a sigs and @a coin_privs arrays, 0 if the operation
+ * failed.
+ * @param coin_privs array of @a num_coins private keys for the
+ * coins that were created, NULL on error.
+ * @param sigs array of signature over @a num_coins coins, NULL on
+ * error.
+ * @param pubs array of public keys for the @a sigs,
+ * NULL on error.
+ * @param full_response raw response from the exchange.
+ */
+static void
+link_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ unsigned int num_coins,
+ const struct TALER_CoinSpendPrivateKeyP *coin_privs,
+ const struct TALER_DenominationSignature *sigs,
+ const struct TALER_DenominationPublicKey *pubs,
+ const json_t *full_response)
+{
+
+ struct RefreshLinkState *rls = cls;
+ const struct TALER_TESTING_Command *reveal_cmd;
+ struct TALER_TESTING_Command *link_cmd
+ = &rls->is->commands[rls->is->ip];
+ unsigned int found;
+ const unsigned int *num_fresh_coins;
+
+ rls->rlh = NULL;
+ if (rls->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == rls->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying refresh link failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ rls->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ rls->backoff = EXCHANGE_LIB_BACKOFF (rls->backoff);
+ rls->retry_task = GNUNET_SCHEDULER_add_delayed (rls->backoff,
+ &do_link_retry,
+ rls);
+ return;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d to command %s in %s:%u\n",
+ http_status,
+ (int) ec,
+ link_cmd->label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (full_response, stderr, 0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+ reveal_cmd = TALER_TESTING_interpreter_lookup_command
+ (rls->is, rls->reveal_reference);
+
+ if (NULL == reveal_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ /* check that number of coins returned matches */
+ if (GNUNET_OK != TALER_TESTING_get_trait_uint
+ (reveal_cmd, 0, &num_fresh_coins))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+ if (num_coins != *num_fresh_coins)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected number of fresh coins: %d vs %d in %s:%u\n",
+ num_coins,
+ *num_fresh_coins,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+ /* check that the coins match */
+ for (unsigned int i = 0; i<num_coins; i++)
+ for (unsigned int j = i + 1; j<num_coins; j++)
+ if (0 == GNUNET_memcmp
+ (&coin_privs[i], &coin_privs[j]))
+ GNUNET_break (0);
+ /* Note: coins might be legitimately permutated in here... */
+ found = 0;
+
+ /* Will point to the pointer inside the cmd state. */
+ const struct TALER_TESTING_FreshCoinData *fc = NULL;
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_fresh_coins
+ (reveal_cmd, 0, &fc))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+
+ for (unsigned int i = 0; i<num_coins; i++)
+ for (unsigned int j = 0; j<num_coins; j++)
+ {
+ if ( (0 == GNUNET_memcmp
+ (&coin_privs[i], &fc[j].coin_priv)) &&
+ (0 == GNUNET_CRYPTO_rsa_signature_cmp
+ (fc[i].sig.rsa_signature,
+ sigs[j].rsa_signature)) &&
+ (0 == GNUNET_CRYPTO_rsa_public_key_cmp
+ (fc[i].pk->key.rsa_public_key,
+ pubs[j].rsa_public_key)) )
+ {
+ found++;
+ break;
+ }
+ }
+ if (found != num_coins)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Only %u/%u coins match expectations\n",
+ found, num_coins);
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+ break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unknown HTTP response code %u.\n",
+ http_status);
+ }
+ TALER_TESTING_interpreter_next (rls->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refresh_link_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RefreshLinkState *rls = cls;
+ struct RefreshRevealState *rrs;
+ struct RefreshMeltState *rms;
+ const struct TALER_TESTING_Command *reveal_cmd;
+ const struct TALER_TESTING_Command *melt_cmd;
+ const struct TALER_TESTING_Command *coin_cmd;
+
+ rls->is = is;
+ reveal_cmd = TALER_TESTING_interpreter_lookup_command
+ (rls->is, rls->reveal_reference);
+
+ if (NULL == reveal_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+ rrs = reveal_cmd->cls;
+ melt_cmd = TALER_TESTING_interpreter_lookup_command
+ (rls->is, rrs->melt_reference);
+
+ if (NULL == melt_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+
+ /* find reserve_withdraw command */
+ {
+ rms = melt_cmd->cls;
+ coin_cmd = TALER_TESTING_interpreter_lookup_command
+ (rls->is, rms->coin_reference);
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+ }
+
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
+ (coin_cmd, 0, &coin_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+
+ /* finally, use private key from withdraw sign command */
+ rls->rlh = TALER_EXCHANGE_refresh_link
+ (is->exchange, coin_priv, &link_cb, rls);
+
+ if (NULL == rls->rlh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rls->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of the "refresh link" CMD, and possibly
+ * cancel a operation thereof.
+ *
+ * @param cls closure
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+refresh_link_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RefreshLinkState *rls = cls;
+
+ if (NULL != rls->rlh)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ rls->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_refresh_link_cancel (rls->rlh);
+ rls->rlh = NULL;
+ }
+ if (NULL != rls->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rls->retry_task);
+ rls->retry_task = NULL;
+ }
+ GNUNET_free (rls);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refresh_melt_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #refresh_melt_run.
+ *
+ * @param cls a `struct RefreshMeltState`
+ */
+static void
+do_melt_retry (void *cls)
+{
+ struct RefreshMeltState *rms = cls;
+
+ rms->retry_task = NULL;
+ refresh_melt_run (rms,
+ NULL,
+ rms->is);
+}
+
+
+/**
+ * Callback for a "refresh melt" operation; checks if the HTTP
+ * response code is okay and re-run the melt operation if the
+ * CMD was set to do so.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param noreveal_index choice by the exchange in the
+ * cut-and-choose protocol, UINT16_MAX on error.
+ * @param exchange_pub public key the exchange used for signing.
+ * @param full_response raw response body from the exchange.
+ */
+static void
+melt_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ uint32_t noreveal_index,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const json_t *full_response)
+{
+ struct RefreshMeltState *rms = cls;
+
+ rms->rmh = NULL;
+ if (rms->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == rms->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying refresh melt failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ rms->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ rms->backoff = EXCHANGE_LIB_BACKOFF (rms->backoff);
+ rms->retry_task = GNUNET_SCHEDULER_add_delayed
+ (rms->backoff,
+ &do_melt_retry,
+ rms);
+ return;
+ }
+ }
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d to command %s in %s:%u\n",
+ http_status,
+ (int) ec,
+ rms->is->commands[rms->is->ip].label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (full_response, stderr, 0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ rms->noreveal_index = noreveal_index;
+
+ if (GNUNET_YES == rms->double_melt)
+ {
+ TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
+ rms->is->commands[rms->is->ip].label);
+ rms->rmh = TALER_EXCHANGE_refresh_melt
+ (rms->is->exchange, rms->refresh_data_length,
+ rms->refresh_data, &melt_cb, rms);
+ rms->double_melt = GNUNET_NO;
+ return;
+ }
+ TALER_TESTING_interpreter_next (rms->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refresh_melt_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RefreshMeltState *rms = cls;
+ unsigned int num_fresh_coins;
+ const char *default_melt_fresh_amounts[] = {
+ "EUR:1", "EUR:1", "EUR:1", "EUR:0.1",
+ NULL
+ };
+ const char **melt_fresh_amounts;
+
+ if (NULL == (melt_fresh_amounts = rms->melt_fresh_amounts))
+ melt_fresh_amounts = default_melt_fresh_amounts;
+ rms->is = is;
+ rms->noreveal_index = UINT16_MAX;
+ for (num_fresh_coins = 0;
+ NULL != melt_fresh_amounts[num_fresh_coins];
+ num_fresh_coins++)
+ ;
+ rms->num_fresh_coins = num_fresh_coins;
+ rms->fresh_pks = GNUNET_new_array
+ (num_fresh_coins,
+ struct TALER_EXCHANGE_DenomPublicKey);
+ {
+ struct TALER_Amount melt_amount;
+ struct TALER_Amount fresh_amount;
+ const struct TALER_DenominationSignature *melt_sig;
+ const struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
+ const struct TALER_TESTING_Command *coin_command;
+
+ if (NULL == (coin_command
+ = TALER_TESTING_interpreter_lookup_command
+ (is, rms->coin_reference)))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
+ (coin_command, 0, &rms->melt_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_denom_sig (coin_command,
+ 0,
+ &melt_sig))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
+ (coin_command, 0, &melt_denom_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ /* Melt amount starts with the melt fee of the old coin; we'll add the
+ values and withdraw fees of the fresh coins next */
+ melt_amount = melt_denom_pub->fee_refresh;
+ for (unsigned int i = 0; i<num_fresh_coins; i++)
+ {
+ const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
+
+ if (GNUNET_OK != TALER_string_to_amount
+ (melt_fresh_amounts[i], &fresh_amount))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at index %u\n",
+ melt_fresh_amounts[i], i);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ fresh_pk = TALER_TESTING_find_pk
+ (TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount);
+ if (NULL == fresh_pk)
+ {
+ GNUNET_break (0);
+ /* Subroutine logs specific error */
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_add (&melt_amount,
+ &melt_amount,
+ &fresh_amount));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_amount_add (&melt_amount,
+ &melt_amount,
+ &fresh_pk->fee_withdraw));
+ rms->fresh_pks[i] = *fresh_pk;
+ /* Make a deep copy of the RSA key */
+ rms->fresh_pks[i].key.rsa_public_key
+ = GNUNET_CRYPTO_rsa_public_key_dup (fresh_pk->key.rsa_public_key);
+ }
+ rms->refresh_data
+ = TALER_EXCHANGE_refresh_prepare (rms->melt_priv,
+ &melt_amount,
+ melt_sig,
+ melt_denom_pub,
+ num_fresh_coins,
+ rms->fresh_pks,
+ &rms->refresh_data_length);
+
+ if (NULL == rms->refresh_data)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ rms->rmh = TALER_EXCHANGE_refresh_melt (is->exchange,
+ rms->refresh_data_length,
+ rms->refresh_data,
+ &melt_cb,
+ rms);
+
+ if (NULL == rms->rmh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rms->is);
+ return;
+ }
+ }
+}
+
+
+/**
+ * Free the "refresh melt" CMD state, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure, must be a `struct RefreshMeltState`.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+refresh_melt_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RefreshMeltState *rms = cls;
+
+ if (NULL != rms->rmh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ rms->is->ip, rms->is->commands[rms->is->ip].label);
+ TALER_EXCHANGE_refresh_melt_cancel (rms->rmh);
+ rms->rmh = NULL;
+ }
+ if (NULL != rms->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (rms->retry_task);
+ rms->retry_task = NULL;
+ }
+ if (NULL != rms->fresh_pks)
+ {
+ for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
+ GNUNET_CRYPTO_rsa_public_key_free (rms->fresh_pks[i].key.rsa_public_key);
+ }
+ GNUNET_free_non_null (rms->fresh_pks);
+ rms->fresh_pks = NULL;
+ GNUNET_free_non_null (rms->refresh_data);
+ rms->refresh_data = NULL;
+ rms->refresh_data_length = 0;
+ GNUNET_free_non_null (rms->melt_fresh_amounts);
+ GNUNET_free (rms);
+}
+
+
+/**
+ * Offer internal data to the "refresh melt" CMD.
+ *
+ * @param cls closure.
+ * @param[out] ret result (could be anything).
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+refresh_melt_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RefreshMeltState *rms = cls;
+
+ if (index >= rms->num_fresh_coins)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_denom_pub (index, &rms->fresh_pks[index]),
+ TALER_TESTING_make_trait_coin_priv (0, rms->melt_priv),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+/**
+ * Parse list of amounts for melt operation.
+ *
+ * @param[in,out] rms where to store the list
+ * @param ap NULL-termianted list of amounts to be melted (one per fresh coin)
+ * @return #GNUNET_OK on success
+ */
+static int
+parse_amounts (struct RefreshMeltState *rms,
+ va_list ap)
+{
+ unsigned int len;
+ unsigned int off;
+ const char *amount;
+
+ len = 0;
+ off = 0;
+ while (NULL != (amount = va_arg (ap, const char *)))
+ {
+ if (len == off)
+ {
+ struct TALER_Amount a;
+
+ GNUNET_array_grow (rms->melt_fresh_amounts,
+ len,
+ off + 16);
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount, &a))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at index %u\n",
+ amount, off);
+ GNUNET_free (rms->melt_fresh_amounts);
+ rms->melt_fresh_amounts = NULL;
+ return GNUNET_SYSERR;
+ }
+ rms->melt_fresh_amounts[off++] = amount;
+ }
+ }
+ if (0 == off)
+ return GNUNET_OK; /* no amounts given == use defaults! */
+ /* ensure NULL-termination */
+ GNUNET_array_grow (rms->melt_fresh_amounts,
+ len,
+ off + 1);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Create a "refresh melt" command.
+ *
+ * @param label command label.
+ * @param coin_reference reference to a command
+ * that will provide a coin to refresh.
+ * @param expected_response_code expected HTTP code.
+ * @param ... NULL-terminated list of amounts to be melted
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_melt (const char *label,
+ const char *coin_reference,
+ unsigned int expected_response_code,
+ ...)
+{
+ struct RefreshMeltState *rms;
+ va_list ap;
+
+ rms = GNUNET_new (struct RefreshMeltState);
+ rms->coin_reference = coin_reference;
+ rms->expected_response_code = expected_response_code;
+ va_start (ap, expected_response_code);
+ GNUNET_assert (GNUNET_OK ==
+ parse_amounts (rms, ap));
+ va_end (ap);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = rms,
+ .run = &refresh_melt_run,
+ .cleanup = &refresh_melt_cleanup,
+ .traits = &refresh_melt_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Create a "refresh melt" CMD that does TWO /refresh/melt
+ * requests. This was needed to test the replay of a valid melt
+ * request, see #5312.
+ *
+ * @param label command label
+ * @param coin_reference reference to a command that will provide
+ * a coin to refresh
+ * @param expected_response_code expected HTTP code
+ * @param ... NULL-terminated list of amounts to be melted
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_melt_double (const char *label,
+ const char *coin_reference,
+ unsigned int expected_response_code,
+ ...)
+{
+ struct RefreshMeltState *rms;
+ va_list ap;
+
+ rms = GNUNET_new (struct RefreshMeltState);
+ rms->coin_reference = coin_reference;
+ rms->expected_response_code = expected_response_code;
+ rms->double_melt = GNUNET_YES;
+ va_start (ap, expected_response_code);
+ GNUNET_assert (GNUNET_OK ==
+ parse_amounts (rms, ap));
+ va_end (ap);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .cls = rms,
+ .run = &refresh_melt_run,
+ .cleanup = &refresh_melt_cleanup,
+ .traits = &refresh_melt_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a "refresh melt" command to enable retries.
+ *
+ * @param cmd command
+ * @return modified command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_melt_with_retry (struct TALER_TESTING_Command cmd)
+{
+ struct RefreshMeltState *rms;
+
+ GNUNET_assert (&refresh_melt_run == cmd.run);
+ rms = cmd.cls;
+ rms->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/**
+ * Offer internal data from a "refresh reveal" CMD.
+ *
+ * @param cls closure.
+ * @param[out] ret result (could be anything).
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+refresh_reveal_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RefreshRevealState *rrs = cls;
+ unsigned int num_coins = rrs->num_fresh_coins;
+#define NUM_TRAITS ((num_coins * 4) + 3)
+ struct TALER_TESTING_Trait traits[NUM_TRAITS];
+
+ /* Making coin privs traits */
+ for (unsigned int i = 0; i<num_coins; i++)
+ traits[i] = TALER_TESTING_make_trait_coin_priv
+ (i, &rrs->fresh_coins[i].coin_priv);
+
+ /* Making denom pubs traits */
+ for (unsigned int i = 0; i<num_coins; i++)
+ traits[num_coins + i]
+ = TALER_TESTING_make_trait_denom_pub
+ (i, rrs->fresh_coins[i].pk);
+
+ /* Making denom sigs traits */
+ for (unsigned int i = 0; i<num_coins; i++)
+ traits[(num_coins * 2) + i]
+ = TALER_TESTING_make_trait_denom_sig
+ (i, &rrs->fresh_coins[i].sig);
+ /* blinding key traits */
+ for (unsigned int i = 0; i<num_coins; i++)
+ traits[(num_coins * 3) + i]
+ = TALER_TESTING_make_trait_blinding_key (i,
+ &rrs->fresh_coins[i].blinding_key),
+
+ /* number of fresh coins */
+ traits[(num_coins * 4)] = TALER_TESTING_make_trait_uint
+ (0, &rrs->num_fresh_coins);
+
+ /* whole array of fresh coins */
+ traits[(num_coins * 4) + 1]
+ = TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins),
+
+ /* end of traits */
+ traits[(num_coins * 4) + 2] = TALER_TESTING_trait_end ();
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Create a "refresh reveal" command.
+ *
+ * @param label command label.
+ * @param melt_reference reference to a "refresh melt" command.
+ * @param expected_response_code expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_reveal (const char *label,
+ const char *melt_reference,
+ unsigned int expected_response_code)
+{
+ struct RefreshRevealState *rrs;
+
+ rrs = GNUNET_new (struct RefreshRevealState);
+ rrs->melt_reference = melt_reference;
+ rrs->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rrs,
+ .label = label,
+ .run = &refresh_reveal_run,
+ .cleanup = &refresh_reveal_cleanup,
+ .traits = &refresh_reveal_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a "refresh reveal" command to enable retries.
+ *
+ * @param cmd command
+ * @return modified command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_reveal_with_retry (struct TALER_TESTING_Command cmd)
+{
+ struct RefreshRevealState *rrs;
+
+ GNUNET_assert (&refresh_reveal_run == cmd.run);
+ rrs = cmd.cls;
+ rrs->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/**
+ * Create a "refresh link" command.
+ *
+ * @param label command label.
+ * @param reveal_reference reference to a "refresh reveal" CMD.
+ * @param expected_response_code expected HTTP response code
+ * @return the "refresh link" command
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_link (const char *label,
+ const char *reveal_reference,
+ unsigned int expected_response_code)
+{
+ struct RefreshLinkState *rrs;
+
+ rrs = GNUNET_new (struct RefreshLinkState);
+ rrs->reveal_reference = reveal_reference;
+ rrs->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rrs,
+ .label = label,
+ .run = &refresh_link_run,
+ .cleanup = &refresh_link_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a "refresh link" command to enable retries.
+ *
+ * @param cmd command
+ * @return modified command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refresh_link_with_retry (struct TALER_TESTING_Command cmd)
+{
+ struct RefreshLinkState *rls;
+
+ GNUNET_assert (&refresh_link_run == cmd.run);
+ rls = cmd.cls;
+ rls->do_retry = GNUNET_YES;
+ return cmd;
+}
diff --git a/src/testing/testing_api_cmd_refund.c b/src/testing/testing_api_cmd_refund.c
@@ -0,0 +1,332 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-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 testing/testing_api_cmd_refund.c
+ * @brief Implement the /refund test command, plus other
+ * corollary commands (?).
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "refund" CMD.
+ */
+struct RefundState
+{
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Amount to be refunded.
+ */
+ const char *refund_amount;
+
+ /**
+ * Expected refund fee.
+ */
+ const char *refund_fee;
+
+ /**
+ * Reference to any command that can provide a coin to refund.
+ */
+ const char *coin_reference;
+
+ /**
+ * Refund transaction identifier.
+ */
+ uint64_t refund_transaction_id;
+
+ /**
+ * Connection to the exchange.
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * Handle to the refund operation.
+ */
+ struct TALER_EXCHANGE_RefundHandle *rh;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Check the result for the refund request, just check if the
+ * response code is acceptable.
+ *
+ * @param cls closure
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param exchange_pub public key the exchange
+ * used for signing @a obj.
+ * @param obj response object.
+ */
+static void
+refund_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const json_t *obj)
+{
+
+ struct RefundState *rs = cls;
+ struct TALER_TESTING_Command *refund_cmd;
+
+ refund_cmd = &rs->is->commands[rs->is->ip];
+ rs->rh = NULL;
+ if (rs->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ refund_cmd->label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (obj, stderr, 0);
+ TALER_TESTING_interpreter_fail (rs->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (rs->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+refund_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RefundState *rs = cls;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ struct TALER_CoinSpendPublicKeyP coin;
+ const json_t *contract_terms;
+ struct GNUNET_HashCode h_contract_terms;
+ struct TALER_Amount refund_fee;
+ struct TALER_Amount refund_amount;
+ const struct TALER_MerchantPrivateKeyP *merchant_priv;
+ const struct TALER_TESTING_Command *coin_cmd;
+
+ rs->exchange = is->exchange;
+ rs->is = is;
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (rs->refund_amount,
+ &refund_amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u/%s\n",
+ rs->refund_amount,
+ is->ip,
+ cmd->label);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_string_to_amount (rs->refund_fee,
+ &refund_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %u/%s\n",
+ rs->refund_fee,
+ is->ip,
+ cmd->label);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ rs->coin_reference);
+ if (NULL == coin_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_contract_terms (coin_cmd,
+ 0,
+ &contract_terms))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_hash (contract_terms,
+ &h_contract_terms));
+
+ /* Hunting for a coin .. */
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (coin_cmd,
+ 0,
+ &coin_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin.eddsa_pub);
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_merchant_priv (coin_cmd,
+ 0,
+ &merchant_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ rs->rh = TALER_EXCHANGE_refund (rs->exchange,
+ &refund_amount,
+ &refund_fee,
+ &h_contract_terms,
+ &coin,
+ rs->refund_transaction_id,
+ merchant_priv,
+ &refund_cb,
+ rs);
+ GNUNET_assert (NULL != rs->rh);
+}
+
+
+/**
+ * Free the state from a "refund" CMD, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+refund_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RefundState *rs = cls;
+
+ if (NULL != rs->rh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ rs->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_refund_cancel (rs->rh);
+ rs->rh = NULL;
+ }
+ GNUNET_free (rs);
+}
+
+
+/**
+ * Create a "refund" command.
+ *
+ * @param label command label.
+ * @param expected_response_code expected HTTP status code.
+ * @param refund_amount the amount to ask a refund for.
+ * @param refund_fee expected refund fee.
+ * @param coin_reference reference to a command that can
+ * provide a coin to be refunded.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refund (const char *label,
+ unsigned int expected_response_code,
+ const char *refund_amount,
+ const char *refund_fee,
+ const char *coin_reference)
+{
+ struct RefundState *rs;
+
+ rs = GNUNET_new (struct RefundState);
+
+ rs->expected_response_code = expected_response_code;
+ rs->refund_amount = refund_amount;
+ rs->refund_fee = refund_fee;
+ rs->coin_reference = coin_reference;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rs,
+ .label = label,
+ .run = &refund_run,
+ .cleanup = &refund_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Create a "refund" command, allow to specify refund transaction
+ * id. Mainly used to create conflicting requests.
+ *
+ * @param label command label.
+ * @param expected_response_code expected HTTP status code.
+ * @param refund_amount the amount to ask a refund for.
+ * @param refund_fee expected refund fee.
+ * @param coin_reference reference to a command that can
+ * provide a coin to be refunded.
+ * @param refund_transaction_id transaction id to use
+ * in the request.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_refund_with_id
+ (const char *label,
+ unsigned int expected_response_code,
+ const char *refund_amount,
+ const char *refund_fee,
+ const char *coin_reference,
+ uint64_t refund_transaction_id)
+{
+ struct RefundState *rs;
+
+ rs = GNUNET_new (struct RefundState);
+ rs->expected_response_code = expected_response_code;
+ rs->refund_amount = refund_amount;
+ rs->refund_fee = refund_fee;
+ rs->coin_reference = coin_reference;
+ rs->refund_transaction_id = refund_transaction_id;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rs,
+ .label = label,
+ .run = &refund_run,
+ .cleanup = &refund_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_serialize_keys.c b/src/testing/testing_api_cmd_serialize_keys.c
@@ -0,0 +1,295 @@
+/*
+ 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 testing/testing_api_cmd_serialize_keys.c
+ * @brief Lets tests use the keys serialization API.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include <jansson.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * Internal state for a serialize-keys CMD.
+ */
+struct SerializeKeysState
+{
+ /**
+ * Serialized keys.
+ */
+ json_t *keys;
+
+ /**
+ * Exchange URL. Needed because the exchange gets disconnected
+ * from, after keys serialization. This value is then needed by
+ * subsequent commands that have to reconnect to the exchagne.
+ */
+ char *exchange_url;
+};
+
+
+/**
+ * Internal state for a connect-with-state CMD.
+ */
+struct ConnectWithStateState
+{
+
+ /**
+ * Reference to a CMD that offers a serialized key-state
+ * that will be used in the reconnection.
+ */
+ const char *state_reference;
+
+ /**
+ * If set to GNUNET_YES, then the /keys callback has already
+ * been passed the control to the next CMD. This is necessary
+ * because it is not uncommon that the /keys callback gets
+ * invoked multiple times, and without this flag, we would keep
+ * going "next" CMD upon every invocation (causing impredictable
+ * behaviour as for the instruction pointer.)
+ */
+ unsigned int consumed;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+serialize_keys_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct SerializeKeysState *sks = cls;
+
+ sks->keys = TALER_EXCHANGE_serialize_data (is->exchange);
+ if (NULL == sks->keys)
+ TALER_TESTING_interpreter_fail (is);
+
+ sks->exchange_url = GNUNET_strdup
+ (TALER_EXCHANGE_get_base_url (is->exchange));
+ TALER_EXCHANGE_disconnect (is->exchange);
+ is->exchange = NULL;
+ is->working = GNUNET_NO;
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state of a "serialize keys" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+serialize_keys_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct SerializeKeysState *sks = cls;
+
+ if (NULL != sks->keys)
+ {
+ json_decref (sks->keys);
+ }
+ GNUNET_free_non_null (sks->exchange_url);
+ GNUNET_free (sks);
+}
+
+
+/**
+ * Offer serialized keys as trait.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+serialize_keys_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct SerializeKeysState *sks = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_exchange_keys (0, sks->keys),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ sks->exchange_url),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+connect_with_state_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ConnectWithStateState *cwss = cls;
+ const struct TALER_TESTING_Command *state_cmd;
+ const json_t *serialized_keys;
+ const char *exchange_url;
+
+ /* This command usually gets rescheduled after serialized
+ * reconnection. */
+ if (GNUNET_YES == cwss->consumed)
+ {
+ TALER_TESTING_interpreter_next (is);
+ return;
+ }
+
+ cwss->is = is;
+ state_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, cwss->state_reference);
+
+ /* Command providing serialized keys not found. */
+ if (NULL == state_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_exchange_keys (state_cmd,
+ 0,
+ &serialized_keys));
+ {
+ char *dump;
+
+ dump = json_dumps (serialized_keys,
+ JSON_INDENT (1));
+ TALER_LOG_DEBUG ("Serialized key-state: %s\n",
+ dump);
+ free (dump);
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_url (state_cmd,
+ TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ &exchange_url));
+ is->exchange = TALER_EXCHANGE_connect (is->ctx,
+ exchange_url,
+ TALER_TESTING_cert_cb,
+ cwss,
+ TALER_EXCHANGE_OPTION_DATA,
+ serialized_keys,
+ TALER_EXCHANGE_OPTION_END);
+ cwss->consumed = GNUNET_YES;
+}
+
+
+/**
+ * Cleanup the state of a "connect with state" CMD. Just
+ * a placeholder to avoid jumping on an invalid address.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+connect_with_state_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ConnectWithStateState *cwss = cls;
+
+ GNUNET_free (cwss);
+}
+
+
+/**
+ * Make a serialize-keys CMD. It will ask for
+ * keys serialization __and__ disconnect from the
+ * exchange.
+ *
+ * @param label CMD label
+ * @return the CMD.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_serialize_keys (const char *label)
+{
+ struct SerializeKeysState *sks;
+
+ sks = GNUNET_new (struct SerializeKeysState);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = sks,
+ .label = label,
+ .run = serialize_keys_run,
+ .cleanup = serialize_keys_cleanup,
+ .traits = serialize_keys_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make a connect-with-state CMD. This command
+ * will use a serialized key state to reconnect
+ * to the exchange.
+ *
+ * @param label command label
+ * @param state_reference label of a CMD offering
+ * a serialized key state.
+ * @return the CMD.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_connect_with_state (const char *label,
+ const char *state_reference)
+{
+ struct ConnectWithStateState *cwss;
+
+ cwss = GNUNET_new (struct ConnectWithStateState);
+ cwss->state_reference = state_reference;
+ cwss->consumed = GNUNET_NO;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cwss,
+ .label = label,
+ .run = connect_with_state_run,
+ .cleanup = connect_with_state_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_signal.c b/src/testing/testing_api_cmd_signal.c
@@ -0,0 +1,115 @@
+/*
+ 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 testing/testing_api_cmd_signal.c
+ * @brief command(s) to send signals to processes.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "signal" CMD.
+ */
+struct SignalState
+{
+ /**
+ * The process to send the signal to.
+ */
+ struct GNUNET_OS_Process *process;
+
+ /**
+ * The signal to send to the process.
+ */
+ int signal;
+};
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+signal_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct SignalState *ss = cls;
+
+ GNUNET_break (0 == GNUNET_OS_process_kill
+ (ss->process, ss->signal));
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Signaling '%d'..\n",
+ ss->signal);
+ sleep (6);
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state from a "signal" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+signal_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct SignalState *ss = cls;
+
+ GNUNET_free (ss);
+}
+
+
+/**
+ * Create a "signal" CMD.
+ *
+ * @param label command label.
+ * @param process handle to the process to signal.
+ * @param signal signal to send.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_signal (const char *label,
+ struct GNUNET_OS_Process *process,
+ int signal)
+{
+ struct SignalState *ss;
+
+ ss = GNUNET_new (struct SignalState);
+ ss->process = process;
+ ss->signal = signal;
+
+
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &signal_run,
+ .cleanup = &signal_cleanup
+ };
+
+ return cmd;
+}
diff --git a/src/testing/testing_api_cmd_sleep.c b/src/testing/testing_api_cmd_sleep.c
@@ -0,0 +1,133 @@
+/*
+ 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 testing/testing_api_cmd_sleep.c
+ * @brief command(s) to sleep for a bit
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "sleep" CMD.
+ */
+struct SleepState
+{
+
+ /**
+ * How long should we sleep?
+ */
+ unsigned int duration;
+};
+
+
+/**
+ * No traits to offer, just provide a stub to be called when
+ * some CMDs iterates through the list of all the commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the trait to return.
+ * @return #GNUNET_OK on success.
+ */
+static int
+sleep_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ (void) cls;
+ (void) ret;
+ (void) trait;
+ (void) index;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+sleep_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct SleepState *ss = cls;
+
+ sleep (ss->duration);
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Cleanup the state from a "sleep" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+sleep_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct SleepState *ss = cls;
+
+ (void) cmd;
+ GNUNET_free (ss);
+}
+
+
+/**
+ * Sleep for @a duration_s seconds.
+ *
+ * @param label command label.
+ * @param duration_s number of seconds to sleep
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_sleep (const char *label,
+ unsigned int duration_s)
+{
+ struct SleepState *ss;
+
+ ss = GNUNET_new (struct SleepState);
+ ss->duration = duration_s;
+
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &sleep_run,
+ .cleanup = &sleep_cleanup,
+ .traits = &sleep_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_sleep.c */
diff --git a/src/testing/testing_api_cmd_status.c b/src/testing/testing_api_cmd_status.c
@@ -0,0 +1,237 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2020 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 testing/testing_api_cmd_status.c
+ * @brief Implement the /reserve/status test command.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "status" CMD.
+ */
+struct StatusState
+{
+ /**
+ * Label to the command which created the reserve to check,
+ * needed to resort the reserve key.
+ */
+ const char *reserve_reference;
+
+ /**
+ * Handle to the "reserve status" operation.
+ */
+ struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
+
+ /**
+ * Expected reserve balance.
+ */
+ const char *expected_balance;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Check that the reserve balance and HTTP response code are
+ * both acceptable.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param json original JSON response from the exchange
+ * @param balance current balance in the reserve, NULL on error.
+ * @param history_length number of entries in the transaction
+ * history, 0 on error.
+ * @param history detailed transaction history, NULL on error.
+ */
+static void
+reserve_status_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const json_t *json,
+ const struct TALER_Amount *balance,
+ unsigned int history_length,
+ const struct TALER_EXCHANGE_ReserveHistory *history)
+{
+ struct StatusState *ss = cls;
+ struct TALER_Amount eb;
+
+ ss->rsh = NULL;
+ if (ss->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected HTTP response code: %d in %s:%u\n",
+ http_status,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ss->expected_balance,
+ &eb));
+
+ if (0 != TALER_amount_cmp (&eb,
+ balance))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected amount in reserve: %s\n",
+ TALER_amount_to_string (balance));
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+
+ /**
+ * TODO (#6049): We should check that reserve history is consistent. Every
+ * command which relates to reserve 'x' should be added in a linked list of
+ * all commands that relate to the same reserve 'x'.
+ *
+ * API-wise, any command that relates to a reserve should offer a
+ * method called e.g. "compare_with_history" that takes an element
+ * of the array returned by "/reserve/status" and checks if that
+ * element correspond to itself (= the command exposing the check-
+ * method).
+ *
+ * IDEA: Maybe realize this via another trait, some kind of
+ * "reserve history update trait" which returns information about
+ * how the command changes the history (provided only by commands
+ * that change reserve balances)?
+ *///
+ TALER_TESTING_interpreter_next (ss->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command being executed.
+ * @param is the interpreter state.
+ */
+static void
+status_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct StatusState *ss = cls;
+ const struct TALER_TESTING_Command *create_reserve;
+ const struct TALER_ReservePublicKeyP *reserve_pubp;
+
+ ss->is = is;
+ create_reserve
+ = TALER_TESTING_interpreter_lookup_command (is,
+ ss->reserve_reference);
+
+ if (NULL == create_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (create_reserve,
+ 0,
+ &reserve_pubp))
+ {
+ GNUNET_break (0);
+ TALER_LOG_ERROR ("Failed to find reserve_pub for status query\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ss->rsh = TALER_EXCHANGE_reserve_status (is->exchange,
+ reserve_pubp,
+ &reserve_status_cb,
+ ss);
+}
+
+
+/**
+ * Cleanup the state from a "reserve status" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+status_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct StatusState *ss = cls;
+
+ if (NULL != ss->rsh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ ss->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_reserve_status_cancel (ss->rsh);
+ ss->rsh = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+/**
+ * Create a "reserve status" command.
+ *
+ * @param label the command label.
+ * @param reserve_reference reference to the reserve to check.
+ * @param expected_balance expected balance for the reserve.
+ * @param expected_response_code expected HTTP response code.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_status (const char *label,
+ const char *reserve_reference,
+ const char *expected_balance,
+ unsigned int expected_response_code)
+{
+ struct StatusState *ss;
+
+ GNUNET_assert (NULL != reserve_reference);
+ ss = GNUNET_new (struct StatusState);
+ ss->reserve_reference = reserve_reference;
+ ss->expected_balance = expected_balance;
+ ss->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &status_run,
+ .cleanup = &status_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_track.c b/src/testing/testing_api_cmd_track.c
@@ -0,0 +1,805 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2020 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 testing/testing_api_cmd_track.c
+ * @brief Implement the testing CMDs for the /track operations.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+/**
+ * State for a "track transaction" CMD.
+ */
+struct TrackTransactionState
+{
+
+ /**
+ * If non NULL, will provide a WTID to be compared against
+ * the one returned by the "track transaction" operation.
+ */
+ const char *bank_transfer_reference;
+
+ /**
+ * The WTID associated by the transaction being tracked.
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Reference to any operation that can provide a transaction.
+ * Will be the transaction to track.
+ */
+ const char *transaction_reference;
+
+ /**
+ * Index of the coin involved in the transaction. Recall:
+ * at the exchange, the tracking is done _per coin_.
+ */
+ unsigned int coin_index;
+
+ /**
+ * Handle to the "track transaction" pending operation.
+ */
+ struct TALER_EXCHANGE_TrackTransactionHandle *tth;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * State for a "track transfer" CMD.
+ */
+struct TrackTransferState
+{
+
+ /**
+ * Expected amount for the WTID being tracked.
+ */
+ const char *expected_total_amount;
+
+ /**
+ * Expected fee for this WTID.
+ */
+ const char *expected_wire_fee;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Reference to any operation that can provide a WTID.
+ * Will be the WTID to track.
+ */
+ const char *wtid_reference;
+
+ /**
+ * Reference to any operation that can provide wire details.
+ * Those wire details will then be matched against the credit
+ * bank account of the tracked WTID. This way we can test that
+ * a wire transfer paid back one particular bank account.
+ */
+ const char *wire_details_reference;
+
+ /**
+ * Reference to any operation that can provide an amount.
+ * This way we can check that the transferred amount matches
+ * our expectations.
+ */
+ const char *total_amount_reference;
+
+ /**
+ * Index to the WTID to pick, in case @a wtid_reference has
+ * many on offer.
+ */
+ unsigned int index;
+
+ /**
+ * Handle to a pending "track transfer" operation.
+ */
+ struct TALER_EXCHANGE_TrackTransferHandle *tth;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Checks what is returned by the "track transaction" operation.
+ * Checks that the HTTP response code is acceptable, and - if the
+ * right reference is non NULL - that the wire transfer subject
+ * line matches our expectations.
+ *
+ * @param cls closure.
+ * @param http_status HTTP status code we got.
+ * @param ec taler-specific error code.
+ * @param exchange_pub public key of the exchange
+ * @param json original json reply (may include signatures, those
+ * have then been validated already).
+ * @param wtid wire transfer identifier, NULL if exchange did not
+ * execute the transaction yet.
+ * @param execution_time actual or planned execution time for the
+ * wire transfer.
+ * @param coin_contribution contribution to the total amount of
+ * the deposited coin (can be NULL).
+ */
+static void
+deposit_wtid_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const json_t *json,
+ const struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_Amount *coin_contribution)
+{
+ struct TrackTransactionState *tts = cls;
+ struct TALER_TESTING_Interpreter *is = tts->is;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+
+ (void) coin_contribution;
+ (void) exchange_pub;
+ tts->tth = NULL;
+ if (tts->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ cmd->label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (json, stderr, 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ tts->wtid = *wtid;
+ if (NULL != tts->bank_transfer_reference)
+ {
+ const struct TALER_TESTING_Command *bank_transfer_cmd;
+ const struct TALER_WireTransferIdentifierRawP *wtid_want;
+
+ /* _this_ wire transfer subject line. */
+ bank_transfer_cmd = TALER_TESTING_interpreter_lookup_command
+ (is, tts->bank_transfer_reference);
+ if (NULL == bank_transfer_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_wtid
+ (bank_transfer_cmd, 0, &wtid_want))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ /* Compare that expected and gotten subjects match. */
+ if (0 != GNUNET_memcmp (wtid,
+ wtid_want))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+ }
+ break;
+ case MHD_HTTP_ACCEPTED:
+ /* allowed, nothing to check here */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* allowed, nothing to check here */
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ TALER_TESTING_interpreter_next (tts->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+track_transaction_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TrackTransactionState *tts = cls;
+ const struct TALER_TESTING_Command *transaction_cmd;
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
+ const json_t *contract_terms;
+ const json_t *wire_details;
+ struct GNUNET_HashCode h_wire_details;
+ struct GNUNET_HashCode h_contract_terms;
+ const struct TALER_MerchantPrivateKeyP *merchant_priv;
+
+ tts->is = is;
+ transaction_cmd
+ = TALER_TESTING_interpreter_lookup_command (tts->is,
+ tts->transaction_reference);
+ if (NULL == transaction_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_coin_priv (transaction_cmd,
+ tts->coin_index,
+ &coin_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
+ &coin_pub.eddsa_pub);
+
+ /* Get the strings.. */
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_wire_details (transaction_cmd,
+ 0,
+ &wire_details))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_contract_terms (transaction_cmd,
+ 0,
+ &contract_terms))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ if ( (NULL == wire_details) ||
+ (NULL == contract_terms) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ /* Should not fail here, json has been parsed already */
+ GNUNET_assert
+ ( (GNUNET_OK ==
+ TALER_JSON_merchant_wire_signature_hash (wire_details,
+ &h_wire_details)) &&
+ (GNUNET_OK ==
+ TALER_JSON_hash (contract_terms,
+ &h_contract_terms)) );
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_merchant_priv (transaction_cmd,
+ 0,
+ &merchant_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ tts->tth = TALER_EXCHANGE_track_transaction (is->exchange,
+ merchant_priv,
+ &h_wire_details,
+ &h_contract_terms,
+ &coin_pub,
+ &deposit_wtid_cb,
+ tts);
+ GNUNET_assert (NULL != tts->tth);
+}
+
+
+/**
+ * Cleanup the state from a "track transaction" CMD, and possibly
+ * cancel a operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+track_transaction_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct TrackTransactionState *tts = cls;
+
+ if (NULL != tts->tth)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ tts->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_track_transaction_cancel (tts->tth);
+ tts->tth = NULL;
+ }
+ GNUNET_free (tts);
+}
+
+
+/**
+ * Offer internal data from a "track transaction" CMD.
+ *
+ * @param cls closure.
+ * @param[out] ret result (could be anything).
+ * @param trait name of the trait.
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success.
+ */
+static int
+track_transaction_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct TrackTransactionState *tts = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_wtid (0, &tts->wtid),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+/**
+ * Create a "track transaction" command.
+ *
+ * @param label the command label.
+ * @param transaction_reference reference to a deposit operation,
+ * will be used to get the input data for the track.
+ * @param coin_index index of the coin involved in the transaction.
+ * @param expected_response_code expected HTTP response code.
+ * @param bank_transfer_reference reference to a command that
+ * can offer a WTID so as to check that against what WTID
+ * the tracked operation has. Set as NULL if not needed.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_track_transaction (const char *label,
+ const char *transaction_reference,
+ unsigned int coin_index,
+ unsigned int expected_response_code,
+ const char *bank_transfer_reference)
+{
+ struct TrackTransactionState *tts;
+
+ tts = GNUNET_new (struct TrackTransactionState);
+ tts->transaction_reference = transaction_reference;
+ tts->expected_response_code = expected_response_code;
+ tts->bank_transfer_reference = bank_transfer_reference;
+ tts->coin_index = coin_index;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = tts,
+ .label = label,
+ .run = &track_transaction_run,
+ .cleanup = &track_transaction_cleanup,
+ .traits = &track_transaction_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Cleanup the state for a "track transfer" CMD, and possibly
+ * cancel a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+track_transfer_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+
+ struct TrackTransferState *tts = cls;
+
+ if (NULL != tts->tth)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ tts->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_track_transfer_cancel (tts->tth);
+ tts->tth = NULL;
+ }
+ GNUNET_free (tts);
+}
+
+
+/**
+ * Check whether the HTTP response code from a "track transfer"
+ * operation is acceptable, and all other values like total amount,
+ * wire fees and hashed wire details as well.
+ *
+ * @param cls closure.
+ * @param http_status HTTP status code we got.
+ * @param ec taler-specific error code.
+ * @param exchange_pub public key the exchange used for signing
+ * the response.
+ * @param json original json reply (may include signatures, those
+ * have then been validated already).
+ * @param h_wire hash of the wire transfer address the transfer
+ * went to, or NULL on error.
+ * @param execution_time time when the exchange claims to have
+ * performed the wire transfer.
+ * @param total_amount total amount of the wire transfer, or NULL
+ * if the exchange could not provide any @a wtid (set only
+ * if @a http_status is "200 OK").
+ * @param wire_fee wire fee that was charged by the exchange.
+ * @param details_length length of the @a details array.
+ * @param details array with details about the combined
+ * transactions.
+ */
+static void
+track_transfer_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const struct TALER_ExchangePublicKeyP *exchange_pub,
+ const json_t *json,
+ const struct GNUNET_HashCode *h_wire,
+ struct GNUNET_TIME_Absolute execution_time,
+ const struct TALER_Amount *total_amount,
+ const struct TALER_Amount *wire_fee,
+ unsigned int details_length,
+ const struct TALER_TrackTransferDetails *details)
+{
+ struct TrackTransferState *tts = cls;
+ struct TALER_TESTING_Interpreter *is = tts->is;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+ struct TALER_Amount expected_amount;
+
+ (void) exchange_pub;
+ tts->tth = NULL;
+ if (tts->expected_response_code != http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ cmd->label,
+ __FILE__,
+ __LINE__);
+ json_dumpf (json, stderr, 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ if (NULL == tts->expected_total_amount)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (NULL == tts->expected_wire_fee)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (tts->expected_total_amount,
+ &expected_amount))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (0 != TALER_amount_cmp (total_amount,
+ &expected_amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Total amount missmatch to command %s - "
+ "%s vs %s\n",
+ cmd->label,
+ TALER_amount_to_string (total_amount),
+ TALER_amount_to_string (&expected_amount));
+ json_dumpf (json, stderr, 0);
+ fprintf (stderr, "\n");
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_string_to_amount (tts->expected_wire_fee,
+ &expected_amount))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (0 != TALER_amount_cmp (wire_fee,
+ &expected_amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire fee missmatch to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ /**
+ * Optionally checking: (1) wire-details for this transfer
+ * match the ones from a referenced "deposit" operation -
+ * or any operation that could provide wire-details. (2)
+ * Total amount for this transfer matches the one from any
+ * referenced command that could provide one.
+ */if (NULL != tts->wire_details_reference)
+ {
+ const struct TALER_TESTING_Command *wire_details_cmd;
+ const json_t *wire_details;
+ struct GNUNET_HashCode h_wire_details;
+
+ if (NULL == (wire_details_cmd
+ = TALER_TESTING_interpreter_lookup_command
+ (is, tts->wire_details_reference)))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_wire_details (wire_details_cmd,
+ 0,
+ &wire_details))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_assert
+ (GNUNET_OK ==
+ TALER_JSON_merchant_wire_signature_hash (wire_details,
+ &h_wire_details));
+
+ if (0 != GNUNET_memcmp (&h_wire_details,
+ h_wire))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire hash missmath to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ if (NULL != tts->total_amount_reference)
+ {
+ const struct TALER_TESTING_Command *total_amount_cmd;
+ const struct TALER_Amount *total_amount_from_reference;
+
+ if (NULL == (total_amount_cmd
+ = TALER_TESTING_interpreter_lookup_command
+ (is, tts->total_amount_reference)))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_amount_obj (total_amount_cmd,
+ 0,
+ &total_amount_from_reference))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ if (0 != TALER_amount_cmp (total_amount,
+ total_amount_from_reference))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Amount missmath to command %s\n",
+ cmd->label);
+ json_dumpf (json, stderr, 0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ }
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command under execution.
+ * @param is the interpreter state.
+ */
+static void
+track_transfer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ /* looking for a wtid to track .. */
+ struct TrackTransferState *tts = cls;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ const struct TALER_WireTransferIdentifierRawP *wtid_ptr;
+
+ /* If no reference is given, we'll use a all-zeros
+ * WTID */
+ memset (&wtid, 0, sizeof (wtid));
+ wtid_ptr = &wtid;
+
+ tts->is = is;
+ if (NULL != tts->wtid_reference)
+ {
+ const struct TALER_TESTING_Command *wtid_cmd;
+
+ wtid_cmd = TALER_TESTING_interpreter_lookup_command
+ (tts->is, tts->wtid_reference);
+
+ if (NULL == wtid_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+
+ if (GNUNET_OK != TALER_TESTING_get_trait_wtid
+ (wtid_cmd, tts->index, &wtid_ptr))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tts->is);
+ return;
+ }
+ GNUNET_assert (NULL != wtid_ptr);
+ }
+ tts->tth = TALER_EXCHANGE_track_transfer (is->exchange,
+ wtid_ptr,
+ &track_transfer_cb,
+ tts);
+ GNUNET_assert (NULL != tts->tth);
+}
+
+
+/**
+ * Make a "track transfer" CMD where no "expected"-arguments,
+ * except the HTTP response code, are given. The best use case
+ * is when what matters to check is the HTTP response code, e.g.
+ * when a bogus WTID was passed.
+ *
+ * @param label the command label
+ * @param wtid_reference reference to any command which can provide
+ * a wtid. If NULL is given, then a all zeroed WTID is
+ * used that will at 99.9999% probability NOT match any
+ * existing WTID known to the exchange.
+ * @param index index number of the WTID to track, in case there
+ * are multiple on offer.
+ * @param expected_response_code expected HTTP response code.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_track_transfer_empty (const char *label,
+ const char *wtid_reference,
+ unsigned int index,
+ unsigned int expected_response_code)
+{
+ struct TrackTransferState *tts;
+
+ tts = GNUNET_new (struct TrackTransferState);
+ tts->wtid_reference = wtid_reference;
+ tts->index = index;
+ tts->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = tts,
+ .label = label,
+ .run = &track_transfer_run,
+ .cleanup = &track_transfer_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make a "track transfer" command, specifying which amount and
+ * wire fee are expected.
+ *
+ * @param label the command label.
+ * @param wtid_reference reference to any command which can provide
+ * a wtid. Will be the one tracked.
+ * @param index in case there are multiple WTID offered, this
+ * parameter selects a particular one.
+ * @param expected_response_code expected HTTP response code.
+ * @param expected_total_amount how much money we expect being moved
+ * with this wire-transfer.
+ * @param expected_wire_fee expected wire fee.
+ * @return the command
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_track_transfer (const char *label,
+ const char *wtid_reference,
+ unsigned int index,
+ unsigned int expected_response_code,
+ const char *expected_total_amount,
+ const char *expected_wire_fee)
+{
+ struct TrackTransferState *tts;
+
+ tts = GNUNET_new (struct TrackTransferState);
+ tts->wtid_reference = wtid_reference;
+ tts->index = index;
+ tts->expected_response_code = expected_response_code;
+ tts->expected_total_amount = expected_total_amount;
+ tts->expected_wire_fee = expected_wire_fee;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = tts,
+ .label = label,
+ .run = &track_transfer_run,
+ .cleanup = &track_transfer_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_track.c */
diff --git a/src/testing/testing_api_cmd_wait.c b/src/testing/testing_api_cmd_wait.c
@@ -0,0 +1,133 @@
+/*
+ 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 testing/testing_api_cmd_wait.c
+ * @brief command(s) to wait on some process
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * Cleanup the state from a "wait service" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+wait_service_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ (void) cls;
+ (void) cmd;
+ /* nothing to clean. */
+ return;
+}
+
+
+/**
+ * No traits to offer, just provide a stub to be called when
+ * some CMDs iterates through the list of all the commands.
+ *
+ * @param cls closure.
+ * @param[out] ret result.
+ * @param trait name of the trait.
+ * @param index index number of the trait to return.
+ * @return #GNUNET_OK on success.
+ */
+static int
+wait_service_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ (void) cls;
+ (void) ret;
+ (void) trait;
+ (void) index;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Run a "wait service" CMD.
+ *
+ * @param cls closure.
+ * @param cmd the command being run.
+ * @param is the interpreter state.
+ */
+static void
+wait_service_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ unsigned int iter = 0;
+ const char *url = cmd->cls;
+ char *wget_cmd;
+
+ GNUNET_asprintf (&wget_cmd,
+ "wget -q -t 1 -T 1 %s -o /dev/null -O /dev/null",
+ url);
+ do
+ {
+ fprintf (stderr, ".");
+
+ if (10 == iter++)
+ {
+ TALER_LOG_ERROR ("Could not reach the proxied service\n");
+ TALER_TESTING_interpreter_fail (is);
+ GNUNET_free (wget_cmd);
+ return;
+ }
+ }
+ while (0 != system (wget_cmd));
+
+ GNUNET_free (wget_cmd);
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * This CMD simply tries to connect via HTTP to the
+ * service addressed by @a url. It attemps 10 times
+ * before giving up and make the test fail.
+ *
+ * @param label label for the command.
+ * @param url complete URL to connect to.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wait_service (const char *label,
+ const char *url)
+{
+ struct TALER_TESTING_Command cmd = {
+ .label = label,
+ .run = wait_service_run,
+ .cleanup = wait_service_cleanup,
+ .traits = wait_service_traits,
+ .cls = (void *) url
+ };
+
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_sleep.c */
diff --git a/src/testing/testing_api_cmd_wire.c b/src/testing/testing_api_cmd_wire.c
@@ -0,0 +1,234 @@
+/*
+ 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 testing/testing_api_cmd_wire.c
+ * @brief command for testing /wire.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * State for a "wire" CMD.
+ */
+struct WireState
+{
+
+ /**
+ * Handle to the /wire operation.
+ */
+ struct TALER_EXCHANGE_WireHandle *wh;
+
+ /**
+ * Which wire-method we expect is offered by the exchange.
+ */
+ const char *expected_method;
+
+ /**
+ * Flag indicating if the expected method is actually
+ * offered.
+ */
+ unsigned int method_found;
+
+ /**
+ * Fee we expect is charged for this wire-transfer method.
+ */
+ const char *expected_fee;
+
+ /**
+ * Expected HTTP response code.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+};
+
+
+/**
+ * Check whether the HTTP response code is acceptable, that
+ * the expected wire method is offered by the exchange, and
+ * that the wire fee is acceptable too.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param accounts_len length of the @a accounts array.
+ * @param accounts list of wire accounts of the exchange,
+ * NULL on error.
+ */
+static void
+wire_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ unsigned int accounts_len,
+ const struct TALER_EXCHANGE_WireAccount *accounts)
+{
+ struct WireState *ws = cls;
+ struct TALER_TESTING_Command *cmd = \
+ &ws->is->commands[ws->is->ip];
+ struct TALER_Amount expected_fee;
+
+ TALER_LOG_DEBUG ("Checking parsed /wire response\n");
+ ws->wh = NULL;
+ if (ws->expected_response_code != http_status)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return;
+ }
+
+ if (MHD_HTTP_OK == http_status)
+ {
+ for (unsigned int i = 0; i<accounts_len; i++)
+ {
+ char *method;
+
+ method = TALER_payto_get_method (accounts[i].url);
+ if (0 == strcmp (ws->expected_method,
+ method))
+ {
+ ws->method_found = GNUNET_OK;
+ if (NULL != ws->expected_fee)
+ {
+ GNUNET_assert
+ (GNUNET_OK ==
+ TALER_string_to_amount (ws->expected_fee,
+ &expected_fee));
+ const struct TALER_EXCHANGE_WireAggregateFees *waf;
+ for (waf = accounts[i].fees;
+ NULL != waf;
+ waf = waf->next)
+ {
+ if (0 != TALER_amount_cmp (&waf->wire_fee,
+ &expected_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire fee missmatch to command %s\n",
+ cmd->label);
+ TALER_TESTING_interpreter_fail (ws->is);
+ GNUNET_free (method);
+ return;
+ }
+ }
+ }
+ }
+ TALER_LOG_DEBUG ("Freeing method '%s'\n",
+ method);
+ GNUNET_free (method);
+ }
+ if (GNUNET_OK != ws->method_found)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "/wire does not offer method '%s'\n",
+ ws->expected_method);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return;
+ }
+ }
+
+ TALER_TESTING_interpreter_next (ws->is);
+}
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the command to execute.
+ * @param is the interpreter state.
+ */
+static void
+wire_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct WireState *ws = cls;
+ ws->is = is;
+ ws->wh = TALER_EXCHANGE_wire (is->exchange,
+ &wire_cb,
+ ws);
+}
+
+
+/**
+ * Cleanup the state of a "wire" CMD, and possibly cancel a
+ * pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command which is being cleaned up.
+ */
+static void
+wire_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct WireState *ws = cls;
+
+ if (NULL != ws->wh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %u (%s) did not complete\n",
+ ws->is->ip,
+ cmd->label);
+ TALER_EXCHANGE_wire_cancel (ws->wh);
+ ws->wh = NULL;
+ }
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Create a "wire" command.
+ *
+ * @param label the command label.
+ * @param expected_method which wire-transfer method is expected
+ * to be offered by the exchange.
+ * @param expected_fee the fee the exchange should charge.
+ * @param expected_response_code the HTTP response the exchange
+ * should return.
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_wire (const char *label,
+ const char *expected_method,
+ const char *expected_fee,
+ unsigned int expected_response_code)
+{
+ struct WireState *ws;
+
+ ws = GNUNET_new (struct WireState);
+ ws->expected_method = expected_method;
+ ws->expected_fee = expected_fee;
+ ws->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &wire_run,
+ .cleanup = &wire_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c
@@ -0,0 +1,534 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_cmd_withdraw.c
+ * @brief main interpreter loop for testcases
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <microhttpd.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+#include "backoff.h"
+
+
+/**
+ * State for a "withdraw" CMD.
+ */
+struct WithdrawState
+{
+
+ /**
+ * Which reserve should we withdraw from?
+ */
+ const char *reserve_reference;
+
+ /**
+ * String describing the denomination value we should withdraw.
+ * A corresponding denomination key must exist in the exchange's
+ * offerings. Can be NULL if @e pk is set instead.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * If @e amount is NULL, this specifies the denomination key to
+ * use. Otherwise, this will be set (by the interpreter) to the
+ * denomination PK matching @e amount.
+ */
+ struct TALER_EXCHANGE_DenomPublicKey *pk;
+
+ /**
+ * Exchange base URL. Only used as offered trait.
+ */
+ char *exchange_url;
+
+ /**
+ * Interpreter state (during command).
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Set (by the interpreter) to the exchange's signature over the
+ * coin's public key.
+ */
+ struct TALER_DenominationSignature sig;
+
+ /**
+ * Private key material of the coin, set by the interpreter.
+ */
+ struct TALER_PlanchetSecretsP ps;
+
+ /**
+ * Withdraw handle (while operation is running).
+ */
+ struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh;
+
+ /**
+ * Task scheduled to try later.
+ */
+ struct GNUNET_SCHEDULER_Task *retry_task;
+
+ /**
+ * How long do we wait until we retry?
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Expected HTTP response code to the request.
+ */
+ unsigned int expected_response_code;
+
+ /**
+ * Was this command modified via
+ * #TALER_TESTING_cmd_withdraw_with_retry to
+ * enable retries?
+ */
+ int do_retry;
+};
+
+
+/**
+ * Run the command.
+ *
+ * @param cls closure.
+ * @param cmd the commaind being run.
+ * @param is interpreter state.
+ */
+static void
+withdraw_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is);
+
+
+/**
+ * Task scheduled to re-try #withdraw_run.
+ *
+ * @param cls a `struct WithdrawState`
+ */
+static void
+do_retry (void *cls)
+{
+ struct WithdrawState *ws = cls;
+
+ ws->retry_task = NULL;
+ withdraw_run (ws,
+ NULL,
+ ws->is);
+}
+
+
+/**
+ * "reserve withdraw" operation callback; checks that the
+ * response code is expected and store the exchange signature
+ * in the state.
+ *
+ * @param cls closure.
+ * @param http_status HTTP response code.
+ * @param ec taler-specific error code.
+ * @param sig signature over the coin, NULL on error.
+ * @param full_response raw response.
+ */
+static void
+reserve_withdraw_cb (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const struct TALER_DenominationSignature *sig,
+ const json_t *full_response)
+{
+ struct WithdrawState *ws = cls;
+ struct TALER_TESTING_Interpreter *is = ws->is;
+
+ ws->wsh = NULL;
+ if (ws->expected_response_code != http_status)
+ {
+ if (GNUNET_YES == ws->do_retry)
+ {
+ if ( (0 == http_status) ||
+ (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec) ||
+ (TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS == ec) ||
+ (TALER_EC_WITHDRAW_RESERVE_UNKNOWN == ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Retrying withdraw failed with %u/%d\n",
+ http_status,
+ (int) ec);
+ /* on DB conflicts, do not use backoff */
+ if (TALER_EC_DB_COMMIT_FAILED_ON_RETRY == ec)
+ ws->backoff = GNUNET_TIME_UNIT_ZERO;
+ else
+ ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);
+ ws->retry_task = GNUNET_SCHEDULER_add_delayed (ws->backoff,
+ &do_retry,
+ ws);
+ return;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d to command %s in %s:%u\n",
+ http_status,
+ (int) ec,
+ TALER_TESTING_interpreter_get_current_label (is),
+ __FILE__,
+ __LINE__);
+ json_dumpf (full_response,
+ stderr,
+ 0);
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ switch (http_status)
+ {
+ case MHD_HTTP_OK:
+ if (NULL == sig)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ ws->sig.rsa_signature
+ = GNUNET_CRYPTO_rsa_signature_dup (sig->rsa_signature);
+ break;
+ case MHD_HTTP_FORBIDDEN:
+ /* nothing to check */
+ break;
+ case MHD_HTTP_CONFLICT:
+ /* nothing to check */
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ /* nothing to check */
+ break;
+ default:
+ /* Unsupported status code (by test harness) */
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Withdraw test command does not support status code %u\n",
+ http_status);
+ GNUNET_break (0);
+ break;
+ }
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Run the command.
+ */
+static void
+withdraw_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct WithdrawState *ws = cls;
+ const struct TALER_ReservePrivateKeyP *rp;
+ const struct TALER_TESTING_Command *create_reserve;
+ const struct TALER_EXCHANGE_DenomPublicKey *dpk;
+
+ (void) cmd;
+ create_reserve = TALER_TESTING_interpreter_lookup_command
+ (is, ws->reserve_reference);
+ if (NULL == create_reserve)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (create_reserve,
+ 0,
+ &rp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+ TALER_planchet_setup_random (&ws->ps);
+ ws->is = is;
+
+ dpk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange),
+ &ws->amount);
+ if (NULL == dpk)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to determine denomination key at %s\n",
+ (NULL != cmd) ? cmd->label : "<retried command>");
+ GNUNET_assert (0);
+ }
+ else
+ {
+ /* We copy the denomination key, as re-querying /keys
+ * would free the old one. */
+ ws->pk = TALER_EXCHANGE_copy_denomination_key (dpk);
+ }
+
+ ws->wsh = TALER_EXCHANGE_reserve_withdraw (is->exchange,
+ ws->pk,
+ rp,
+ &ws->ps,
+ &reserve_withdraw_cb,
+ ws);
+ if (NULL == ws->wsh)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "withdraw" CMD, and possibly cancel
+ * a pending operation thereof.
+ *
+ * @param cls closure.
+ * @param cmd the command being freed.
+ */
+static void
+withdraw_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct WithdrawState *ws = cls;
+
+ if (NULL != ws->wsh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command %s did not complete\n",
+ cmd->label);
+ TALER_EXCHANGE_reserve_withdraw_cancel (ws->wsh);
+ ws->wsh = NULL;
+ }
+ if (NULL != ws->retry_task)
+ {
+ GNUNET_SCHEDULER_cancel (ws->retry_task);
+ ws->retry_task = NULL;
+ }
+ if (NULL != ws->sig.rsa_signature)
+ {
+ GNUNET_CRYPTO_rsa_signature_free (ws->sig.rsa_signature);
+ ws->sig.rsa_signature = NULL;
+ }
+ if (NULL != ws->pk)
+ {
+ TALER_EXCHANGE_destroy_denomination_key (ws->pk);
+ ws->pk = NULL;
+ }
+ GNUNET_free_non_null (ws->exchange_url);
+ GNUNET_free (ws);
+}
+
+
+/**
+ * Offer internal data to a "withdraw" CMD state to other
+ * commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to offer.
+ * @return #GNUNET_OK on success
+ */
+static int
+withdraw_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct WithdrawState *ws = cls;
+ const struct TALER_TESTING_Command *reserve_cmd;
+ const struct TALER_ReservePrivateKeyP *reserve_priv;
+ const struct TALER_ReservePublicKeyP *reserve_pub;
+
+ /* We offer the reserve key where these coins were withdrawn
+ * from. */
+ reserve_cmd = TALER_TESTING_interpreter_lookup_command
+ (ws->is, ws->reserve_reference);
+
+ if (NULL == reserve_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_priv (reserve_cmd,
+ 0,
+ &reserve_priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_reserve_pub (reserve_cmd,
+ 0,
+ &reserve_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return GNUNET_SYSERR;
+ }
+ if (NULL == ws->exchange_url)
+ ws->exchange_url
+ = GNUNET_strdup (TALER_EXCHANGE_get_base_url (ws->is->exchange));
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
+ &ws->ps.coin_priv),
+ TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
+ &ws->ps.blinding_key),
+ TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
+ ws->pk),
+ TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
+ &ws->sig),
+ TALER_TESTING_make_trait_reserve_priv (0,
+ reserve_priv),
+ TALER_TESTING_make_trait_reserve_pub (0,
+ reserve_pub),
+ TALER_TESTING_make_trait_amount_obj (0,
+ &ws->amount),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BASE_URL,
+ ws->exchange_url),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+/**
+ * Create a withdraw command, letting the caller specify
+ * the desired amount as string.
+ *
+ * @param label command label.
+ * @param reserve_reference command providing us with a reserve to withdraw from
+ * @param amount how much we withdraw.
+ * @param expected_response_code which HTTP response code
+ * we expect from the exchange.
+ * @return the withdraw command to be executed by the interpreter.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_withdraw_amount (const char *label,
+ const char *reserve_reference,
+ const char *amount,
+ unsigned int expected_response_code)
+{
+ struct WithdrawState *ws;
+
+ ws = GNUNET_new (struct WithdrawState);
+ ws->reserve_reference = reserve_reference;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (amount,
+ &ws->amount))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse amount `%s' at %s\n",
+ amount,
+ label);
+ GNUNET_assert (0);
+ }
+ ws->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &withdraw_run,
+ .cleanup = &withdraw_cleanup,
+ .traits = &withdraw_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Create withdraw command, letting the caller specify the
+ * amount by a denomination key.
+ *
+ * @param label command label.
+ * @param reserve_reference reference to the reserve to withdraw
+ * from; will provide reserve priv to sign the request.
+ * @param dk denomination public key.
+ * @param expected_response_code expected HTTP response code.
+ *
+ * @return the command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_withdraw_denomination (const char *label,
+ const char *reserve_reference,
+ const struct
+ TALER_EXCHANGE_DenomPublicKey *dk,
+ unsigned int expected_response_code)
+{
+ struct WithdrawState *ws;
+
+ if (NULL == dk)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Denomination key not specified at %s\n",
+ label);
+ GNUNET_assert (0);
+ }
+ ws = GNUNET_new (struct WithdrawState);
+ ws->reserve_reference = reserve_reference;
+ ws->pk = TALER_EXCHANGE_copy_denomination_key (dk);
+ ws->expected_response_code = expected_response_code;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ws,
+ .label = label,
+ .run = &withdraw_run,
+ .cleanup = &withdraw_cleanup,
+ .traits = &withdraw_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Modify a withdraw command to enable retries when the
+ * reserve is not yet full or we get other transient
+ * errors from the exchange.
+ *
+ * @param cmd a withdraw command
+ * @return the command with retries enabled
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_withdraw_with_retry (struct TALER_TESTING_Command cmd)
+{
+ struct WithdrawState *ws;
+
+ GNUNET_assert (&withdraw_run == cmd.run);
+ ws = cmd.cls;
+ ws->do_retry = GNUNET_YES;
+ return cmd;
+}
+
+
+/* end of testing_api_cmd_withdraw.c */
diff --git a/src/testing/testing_api_helpers_auditor.c b/src/testing/testing_api_helpers_auditor.c
@@ -0,0 +1,229 @@
+/*
+ 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 testing/testing_api_helpers_auditor.c
+ * @brief helper functions
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_auditor_service.h"
+
+
+/**
+ * Closure for #cleanup_auditor.
+ */
+struct CleanupContext
+{
+ /**
+ * Where we find the state to clean up.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Next cleanup routine to call, NULL for none.
+ */
+ GNUNET_SCHEDULER_TaskCallback fcb;
+
+ /**
+ * Closure for @e fcb
+ */
+ void *fcb_cls;
+};
+
+
+/**
+ * Function to clean up the auditor connection.
+ *
+ * @param cls a `struct CleanupContext`
+ */
+static void
+cleanup_auditor (void *cls)
+{
+ struct CleanupContext *cc = cls;
+ struct TALER_TESTING_Interpreter *is = cc->is;
+
+ TALER_AUDITOR_disconnect (is->auditor);
+ is->auditor = NULL;
+ if (NULL != cc->fcb)
+ cc->fcb (cc->fcb_cls);
+ GNUNET_free (cc);
+}
+
+
+/**
+ * Closure for #auditor_main_wrapper()
+ */
+struct MainWrapperContext
+{
+ /**
+ * Main function to launch.
+ */
+ TALER_TESTING_Main main_cb;
+
+ /**
+ * Closure for @e main_cb.
+ */
+ void *main_cb_cls;
+
+ /**
+ * Configuration we use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Name of the configuration file.
+ */
+ const char *config_filename;
+
+};
+
+
+/**
+ * Function called with information about the auditor.
+ *
+ * @param cls closure
+ * @param vi basic information about the auditor
+ * @param compat protocol compatibility information
+ */
+static void
+auditor_version_cb (void *cls,
+ const struct TALER_AUDITOR_VersionInformation *vi,
+ enum TALER_AUDITOR_VersionCompatibility compat)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+
+ if (TALER_AUDITOR_VC_MATCH != compat)
+ {
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ is->auditor_working = GNUNET_YES;
+}
+
+
+/**
+ * Setup the @a is 'auditor' member before running the main test loop.
+ *
+ * @param cls must be a `struct MainWrapperContext *`
+ * @param[in,out] is interpreter state to setup
+ */
+static void
+auditor_main_wrapper (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct MainWrapperContext *mwc = cls;
+ struct CleanupContext *cc;
+ char *auditor_base_url;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (mwc->cfg,
+ "auditor",
+ "BASE_URL",
+ &auditor_base_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "BASE_URL");
+ return;
+ }
+
+ is->auditor = TALER_AUDITOR_connect (is->ctx,
+ auditor_base_url,
+ &auditor_version_cb,
+ is);
+ GNUNET_free (auditor_base_url);
+
+ if (NULL == is->auditor)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ cc = GNUNET_new (struct CleanupContext);
+ cc->is = is;
+ cc->fcb = is->final_cleanup_cb;
+ cc->fcb_cls = is->final_cleanup_cb_cls;
+ is->final_cleanup_cb = cleanup_auditor;
+ is->final_cleanup_cb_cls = cc;
+ mwc->main_cb (mwc->main_cb_cls,
+ is);
+}
+
+
+/**
+ * Install signal handlers plus schedules the main wrapper
+ * around the "run" method.
+ *
+ * @param cls our `struct MainWrapperContext`
+ * @param cfg configuration we use
+ * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
+ * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
+ * times.
+ */
+static int
+setup_with_cfg (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct MainWrapperContext *mwc = cls;
+ struct TALER_TESTING_SetupContext setup_ctx = {
+ .config_filename = mwc->config_filename,
+ .main_cb = &auditor_main_wrapper,
+ .main_cb_cls = mwc
+ };
+
+ mwc->cfg = cfg;
+ return TALER_TESTING_setup_with_auditor_and_exchange_cfg (&setup_ctx,
+ cfg);
+}
+
+
+/**
+ * Install signal handlers plus schedules the main wrapper
+ * around the "run" method.
+ *
+ * @param main_cb the "run" method which contains all the
+ * commands.
+ * @param main_cb_cls a closure for "run", typically NULL.
+ * @param config_filename configuration filename.
+ * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
+ * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
+ * times.
+ */
+int
+TALER_TESTING_auditor_setup (TALER_TESTING_Main main_cb,
+ void *main_cb_cls,
+ const char *config_filename)
+{
+ struct MainWrapperContext mwc = {
+ .main_cb = main_cb,
+ .main_cb_cls = main_cb_cls,
+ .config_filename = config_filename
+ };
+
+ return GNUNET_CONFIGURATION_parse_and_run (config_filename,
+ &setup_with_cfg,
+ &mwc);
+}
+
+
+/* end of testing_auditor_api_helpers.c */
diff --git a/src/testing/testing_api_helpers_bank.c b/src/testing/testing_api_helpers_bank.c
@@ -0,0 +1,494 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_helpers_bank.c
+ * @brief convenience functions for bank tests.
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+
+#define BANK_FAIL() \
+ do {GNUNET_break (0); return NULL; } while (0)
+
+
+/**
+ * Runs the Fakebank by guessing / extracting the portnumber
+ * from the base URL.
+ *
+ * @param bank_url bank's base URL.
+ * @return the fakebank process handle, or NULL if any
+ * error occurs.
+ */
+struct TALER_FAKEBANK_Handle *
+TALER_TESTING_run_fakebank (const char *bank_url)
+{
+ const char *port;
+ long pnum;
+ struct TALER_FAKEBANK_Handle *fakebankd;
+
+ port = strrchr (bank_url,
+ (unsigned char) ':');
+ if (NULL == port)
+ pnum = 80;
+ else
+ pnum = strtol (port + 1, NULL, 10);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Starting Fakebank on port %u (%s)\n",
+ (unsigned int) pnum,
+ bank_url);
+ fakebankd = TALER_FAKEBANK_start ((uint16_t) pnum);
+ if (NULL == fakebankd)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ return fakebankd;
+}
+
+
+/**
+ * Look for substring in a programs' name.
+ *
+ * @param prog program's name to look into
+ * @param marker chunk to find in @a prog
+ * @return #GNUNET_YES if @a marker is present, otherwise #GNUNET_NO
+ */
+int
+TALER_TESTING_has_in_name (const char *prog,
+ const char *marker)
+{
+ size_t name_pos;
+ size_t pos;
+
+ if (! prog || ! marker)
+ return GNUNET_NO;
+
+ pos = 0;
+ name_pos = 0;
+ while (prog[pos])
+ {
+ if ('/' == prog[pos])
+ name_pos = pos + 1;
+ pos++;
+ }
+ if (name_pos == pos)
+ return GNUNET_YES;
+ return (NULL != strstr (prog + name_pos, marker));
+}
+
+
+/**
+ * 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.
+ * @param bank_url base URL of the bank, used by `wget' to check
+ * that the bank was started right.
+ * @return the process, or NULL if the process could not
+ * be started.
+ */
+struct GNUNET_OS_Process *
+TALER_TESTING_run_bank (const char *config_filename,
+ const char *bank_url)
+{
+ struct GNUNET_OS_Process *bank_proc;
+ unsigned int iter;
+ char *wget_cmd;
+ char *database;
+ char *serve_cfg;
+ char *serve_arg;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_load (cfg,
+ config_filename))
+ {
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ exit (77);
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "bank",
+ "database",
+ &database))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ "bank",
+ "database");
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ exit (77);
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "bank",
+ "serve",
+ &serve_cfg))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ "bank",
+ "serve");
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free (database);
+ exit (77);
+ }
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ serve_arg = "serve-http";
+ if (0 != strcmp ("http", serve_cfg))
+ serve_arg = "serve-uwsgi";
+ GNUNET_free (serve_cfg);
+ bank_proc = GNUNET_OS_start_process
+ (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-bank-manage-testing",
+ "taler-bank-manage-testing",
+ config_filename,
+ database,
+ serve_arg, NULL);
+ GNUNET_free (database);
+ if (NULL == bank_proc)
+ {
+ BANK_FAIL ();
+ }
+
+ GNUNET_asprintf (&wget_cmd,
+ "wget -q -t 2 -T 1 %s -o /dev/null -O /dev/null",
+ bank_url);
+
+ /* give child time to start and bind against the socket */
+ fprintf (stderr,
+ "Waiting for `taler-bank-manage' to be ready (via %s)\n", wget_cmd);
+ 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);
+ GNUNET_free (wget_cmd);
+ BANK_FAIL ();
+ }
+ fprintf (stderr, ".");
+ sleep (1);
+ iter++;
+ }
+ while (0 != system (wget_cmd));
+ GNUNET_free (wget_cmd);
+ fprintf (stderr, "\n");
+
+ return bank_proc;
+
+}
+
+
+/**
+ * Prepare the bank execution. Check if the port is available
+ * and reset database.
+ *
+ * @param config_filename configuration file name.
+ * @param config_section section of the configuration with the exchange's account
+ * @param[out] bc set to the bank's configuration data
+ * @return the base url, or NULL upon errors. Must be freed
+ * by the caller.
+ */
+int
+TALER_TESTING_prepare_bank (const char *config_filename,
+ const char *config_section,
+ struct TALER_TESTING_BankConfiguration *bc)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ unsigned long long port;
+ struct GNUNET_OS_Process *dbreset_proc;
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
+ char *database;
+ char *exchange_payto_uri;
+
+ cfg = GNUNET_CONFIGURATION_create ();
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_load (cfg, config_filename))
+ {
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "bank",
+ "DATABASE",
+ &database))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "bank",
+ "DATABASE");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ config_section,
+ "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */
+ &exchange_payto_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ config_section,
+ "URL");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+
+ 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);
+ GNUNET_free (database);
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
+ (uint16_t) port))
+ {
+ fprintf (stderr,
+ "Required port %llu not available, skipping.\n",
+ port);
+ GNUNET_break (0);
+ GNUNET_free (database);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+
+ /* 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", config_filename,
+ "--with-db", database,
+ "django",
+ "flush",
+ "--no-input", NULL)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to flush the bank db.\n");
+ GNUNET_free (database);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (database);
+
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_process_wait_status (dbreset_proc,
+ &type,
+ &code))
+ {
+ GNUNET_OS_process_destroy (dbreset_proc);
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ if ( (type == GNUNET_OS_PROCESS_EXITED) &&
+ (0 != code) )
+ {
+ fprintf (stderr,
+ "Failed to setup database\n");
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ if ( (type != GNUNET_OS_PROCESS_EXITED) ||
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected error running `taler-bank-manage django flush'!\n");
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_OS_process_destroy (dbreset_proc);
+ if (GNUNET_OK !=
+ TALER_BANK_auth_parse_cfg (cfg,
+ config_section,
+ &bc->exchange_auth))
+ {
+ GNUNET_break (0);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_CONFIGURATION_destroy (cfg);
+ bc->exchange_payto = exchange_payto_uri;
+ bc->user42_payto = "payto://x-taler-bank/localhost/42";
+ bc->user43_payto = "payto://x-taler-bank/localhost/43";
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Using pybank %s on port %u\n",
+ bc->exchange_auth.wire_gateway_url,
+ (unsigned int) port);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n",
+ bc->exchange_payto);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
+ bc->user42_payto);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
+ bc->user43_payto);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Prepare launching a fakebank. Check that the configuration
+ * file has the right option, and that the port is available.
+ * If everything is OK, return the configuration data of the fakebank.
+ *
+ * @param config_filename configuration file to use
+ * @param config_section which account to use (must match x-taler-bank)
+ * @param[out] bc set to the bank's configuration data
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_prepare_fakebank (const char *config_filename,
+ const char *config_section,
+ struct TALER_TESTING_BankConfiguration *bc)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ unsigned long long fakebank_port;
+ char *exchange_payto_uri;
+
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg,
+ config_filename))
+ return GNUNET_SYSERR;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "BANK",
+ "HTTP_PORT",
+ &fakebank_port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ "BANK",
+ "HTTP_PORT");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ config_section,
+ "URL", /* FIXME: config should be renamed to payto_uri, it's not an url even! */
+ &exchange_payto_uri))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ config_section,
+ "URL");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return GNUNET_SYSERR;
+ }
+ bc->exchange_auth.method = TALER_BANK_AUTH_NONE;
+ {
+ char *exchange_xtalerbank_account;
+
+ exchange_xtalerbank_account
+ = TALER_xtalerbank_account_from_payto (exchange_payto_uri);
+ if (NULL == exchange_xtalerbank_account)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_asprintf (&bc->exchange_auth.wire_gateway_url,
+ "http://localhost:%u/%s/",
+ (unsigned int) fakebank_port,
+ exchange_xtalerbank_account);
+ GNUNET_free (exchange_xtalerbank_account);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Using fakebank %s on port %u\n",
+ bc->exchange_auth.wire_gateway_url,
+ (unsigned int) fakebank_port);
+
+ GNUNET_CONFIGURATION_destroy (cfg);
+ if (GNUNET_OK !=
+ TALER_TESTING_url_port_free (bc->exchange_auth.wire_gateway_url))
+ {
+ GNUNET_free (bc->exchange_auth.wire_gateway_url);
+ bc->exchange_auth.wire_gateway_url = NULL;
+ return GNUNET_SYSERR;
+ }
+ /* Now we know it's the fake bank, for purpose of authentication, we
+ * don't have any auth. */
+ bc->exchange_auth.method = TALER_BANK_AUTH_NONE;
+ bc->exchange_payto = exchange_payto_uri;
+ bc->user42_payto = "payto://x-taler-bank/localhost/42";
+ bc->user43_payto = "payto://x-taler-bank/localhost/43";
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "exchange payto: %s\n",
+ bc->exchange_payto);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
+ bc->user42_payto);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "user42_payto: %s\n",
+ bc->user43_payto);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Allocate and return a piece of wire-details. Combines
+ * a @a payto -URL and adds some salt to create the JSON.
+ *
+ * @param payto payto://-URL to encapsulate
+ * @return JSON describing the account, including the
+ * payto://-URL of the account, must be manually decref'd
+ */
+json_t *
+TALER_TESTING_make_wire_details (const char *payto)
+{
+ return json_pack ("{s:s, s:s}",
+ "url", payto,
+ "salt",
+ "test-salt (must be constant for aggregation tests)");
+}
+
+
+/* end of testing_api_helpers_bank.c */
diff --git a/src/testing/testing_api_helpers_exchange.c b/src/testing/testing_api_helpers_exchange.c
@@ -0,0 +1,975 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_helpers_exchange.c
+ * @brief helper functions
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * Remove files from previous runs
+ *
+ * @param config_name configuration filename.
+ */
+void
+TALER_TESTING_cleanup_files (const char *config_name)
+{
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_parse_and_run (config_name,
+ &TALER_TESTING_cleanup_files_cfg,
+ NULL))
+ exit (77);
+}
+
+
+/**
+ * Remove files from previous runs
+ *
+ * @param cls NULL
+ * @param cfg configuration
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_cleanup_files_cfg (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *dir;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange",
+ "KEYDIR",
+ &dir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KEYDIR");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (dir,
+ GNUNET_NO))
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_DISK_directory_remove (dir));
+ GNUNET_free (dir);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "exchange",
+ "REVOCATION_DIR",
+ &dir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "REVOCATION_DIR");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_YES ==
+ GNUNET_DISK_directory_test (dir,
+ GNUNET_NO))
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_DISK_directory_remove (dir));
+ GNUNET_free (dir);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run `taler-exchange-keyup`.
+ *
+ * @param config_filename configuration file to use
+ * @param output_filename where to write the output for the auditor
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_run_keyup (const char *config_filename,
+ const char *output_filename)
+{
+ struct GNUNET_OS_Process *proc;
+
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-keyup",
+ "taler-exchange-keyup",
+ "-c", config_filename,
+ "-o", output_filename,
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-exchange-keyup`, is your PATH correct?\n");
+ return GNUNET_SYSERR;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_destroy (proc);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run `taler-auditor-sign`.
+ *
+ * @param config_filename configuration file to use
+ * @param exchange_master_pub master public key of the exchange
+ * @param auditor_base_url what is the base URL of the auditor
+ * @param signdata_in where is the information from taler-exchange-keyup
+ * @param signdata_out where to write the output for the exchange
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_run_auditor_sign (const char *config_filename,
+ const char *exchange_master_pub,
+ const char *auditor_base_url,
+ const char *signdata_in,
+ const char *signdata_out)
+{
+ struct GNUNET_OS_Process *proc;
+
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-sign",
+ "taler-auditor-sign",
+ "-c", config_filename,
+ "-u", auditor_base_url,
+ "-m", exchange_master_pub,
+ "-r", signdata_in,
+ "-o", signdata_out,
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-auditor-sign`, is your PATH correct?\n");
+ return GNUNET_SYSERR;
+ }
+ GNUNET_OS_process_wait (proc);
+ GNUNET_OS_process_destroy (proc);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run `taler-auditor-exchange`.
+ *
+ * @param config_filename configuration file to use
+ * @param exchange_master_pub master public key of the exchange
+ * @param exchange_base_url what is the base URL of the exchange
+ * @param do_remove #GNUNET_NO to add exchange, #GNUNET_YES to remove
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_run_auditor_exchange (const char *config_filename,
+ const char *exchange_master_pub,
+ const char *exchange_base_url,
+ int do_remove)
+{
+ struct GNUNET_OS_Process *proc;
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
+
+ TALER_LOG_DEBUG ("Add exchange (%s,%s) to the auditor\n",
+ exchange_base_url,
+ exchange_master_pub);
+
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-exchange",
+ "taler-auditor-exchange",
+ "-c", config_filename,
+ "-u", exchange_base_url,
+ "-m", exchange_master_pub,
+ (GNUNET_YES == do_remove)
+ ? "-r"
+ : NULL,
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-auditor-exchange`, is your PATH correct?\n");
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_OS_process_wait_status (proc,
+ &type,
+ &code));
+ GNUNET_OS_process_destroy (proc);
+ if ( (0 != code) ||
+ (GNUNET_OS_PROCESS_EXITED != type) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "taler-auditor-exchange terminated with error (%d/%d)\n",
+ (int) type,
+ (int) code);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run `taler-exchange-dbinit -r` (reset exchange database).
+ *
+ * @param config_filename configuration file to use
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_exchange_db_reset (const char *config_filename)
+{
+ struct GNUNET_OS_Process *proc;
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
+
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-dbinit",
+ "taler-exchange-dbinit",
+ "-c", config_filename,
+ "-r",
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-exchange-dbinit`, is your PATH correct?\n");
+ return GNUNET_NO;
+ }
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_process_wait_status (proc,
+ &type,
+ &code))
+ {
+ GNUNET_break (0);
+ GNUNET_OS_process_destroy (proc);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_OS_process_destroy (proc);
+ if ( (type == GNUNET_OS_PROCESS_EXITED) &&
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to setup (exchange) database, exit code %d\n",
+ (int) code);
+ return GNUNET_NO;
+ }
+ if ( (type != GNUNET_OS_PROCESS_EXITED) ||
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected error (%d/%d) running `taler-exchange-dbinit'!\n",
+ (int) type,
+ (int) code);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Run `taler-auditor-dbinit -r` (reset auditor database).
+ *
+ * @param config_filename configuration file to use
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_auditor_db_reset (const char *config_filename)
+{
+ struct GNUNET_OS_Process *proc;
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
+
+ proc = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-dbinit",
+ "taler-auditor-dbinit",
+ "-c", config_filename,
+ "-r",
+ NULL);
+ if (NULL == proc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run `taler-auditor-dbinit`, is your PATH correct?\n");
+ return GNUNET_NO;
+ }
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_process_wait_status (proc,
+ &type,
+ &code))
+ {
+ GNUNET_break (0);
+ GNUNET_OS_process_destroy (proc);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_OS_process_destroy (proc);
+ if ( (type == GNUNET_OS_PROCESS_EXITED) &&
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to setup (auditor) database, exit code %d\n",
+ (int) code);
+ return GNUNET_NO;
+ }
+ if ( (type != GNUNET_OS_PROCESS_EXITED) ||
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected error (%d/%d) running `taler-auditor-dbinit'!\n",
+ (int) type,
+ (int) code);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Type of closure for
+ * #sign_keys_for_exchange.
+ */
+struct SignInfo
+{
+ /**
+ * Members will be set to the exchange configuration.
+ */
+ struct TALER_TESTING_ExchangeConfiguration *ec;
+
+ /**
+ * Name of the configuration file to use.
+ */
+ const char *config_filename;
+
+ /**
+ * Must be set to input file with the data to be signed before
+ * calling #TALER_TESTING_sign_keys_for_exchange.
+ */
+ const char *auditor_sign_input_filename;
+};
+
+
+/**
+ * Sign the keys for an exchange given configuration @a cfg.
+ * The information to be signed must be in a file "auditor.in".
+ *
+ * @param[in,out] cls a `struct SignInfo` with further paramters
+ * @param cfg configuration to use
+ * @return #GNUNET_OK on success
+ */
+static int
+sign_keys_for_exchange (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct SignInfo *si = cls;
+ char *test_home_dir;
+ char *signed_keys_out;
+ char *exchange_master_pub;
+ int ret;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "BASE_URL",
+ &si->ec->exchange_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ "exchange",
+ "BASE_URL");
+ si->ec->exchange_url = NULL;
+ return GNUNET_NO;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "auditor",
+ "BASE_URL",
+ &si->ec->auditor_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ "auditor",
+ "BASE_URL");
+ GNUNET_free (si->ec->exchange_url);
+ si->ec->exchange_url = NULL;
+ si->ec->auditor_url = NULL;
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg,
+ "paths",
+ "TALER_TEST_HOME",
+ &test_home_dir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "paths",
+ "TALER_TEST_HOME");
+ ret = GNUNET_SYSERR;
+ goto fail;
+ }
+
+ GNUNET_asprintf (&signed_keys_out,
+ "%s/.local/share/taler/auditors/auditor.out",
+ test_home_dir);
+ GNUNET_free (test_home_dir);
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "MASTER_PUBLIC_KEY",
+ &exchange_master_pub))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "MASTER_PUBLIC_KEY");
+ GNUNET_free (signed_keys_out);
+ ret = GNUNET_SYSERR;
+ goto fail;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_run_auditor_exchange (si->config_filename,
+ exchange_master_pub,
+ si->ec->exchange_url,
+ GNUNET_NO))
+ {
+ GNUNET_free (signed_keys_out);
+ ret = GNUNET_NO;
+ goto fail;
+ }
+
+ if (GNUNET_OK !=
+ TALER_TESTING_run_auditor_sign (si->config_filename,
+ exchange_master_pub,
+ si->ec->auditor_url,
+ si->auditor_sign_input_filename,
+ signed_keys_out))
+ {
+ GNUNET_free (signed_keys_out);
+ GNUNET_free (exchange_master_pub);
+ ret = GNUNET_NO;
+ goto fail;
+ }
+ GNUNET_free (signed_keys_out);
+ GNUNET_free (exchange_master_pub);
+ return GNUNET_OK;
+fail:
+ GNUNET_free (si->ec->exchange_url);
+ GNUNET_free (si->ec->auditor_url);
+ si->ec->exchange_url = NULL;
+ si->ec->auditor_url = NULL;
+ return ret;
+}
+
+
+/**
+ * Prepare launching an exchange. Checks that the configured
+ * port is available, runs taler-exchange-keyup,
+ * taler-auditor-sign and taler-exchange-dbinit. Does NOT
+ * launch the exchange process itself.
+ *
+ * @param config_filename configuration file to use
+ * @param[out] ec will be set to the exchange configuration data
+ * @return #GNUNET_OK on success, #GNUNET_NO if test should be
+ * skipped, #GNUNET_SYSERR on test failure
+ */
+int
+TALER_TESTING_prepare_exchange (const char *config_filename,
+ struct TALER_TESTING_ExchangeConfiguration *ec)
+{
+ struct SignInfo si = {
+ .config_filename = config_filename,
+ .ec = ec,
+ .auditor_sign_input_filename = "auditor.in"
+ };
+
+ if (GNUNET_OK !=
+ TALER_TESTING_run_keyup (config_filename,
+ si.auditor_sign_input_filename))
+ return GNUNET_NO;
+ if (GNUNET_OK !=
+ TALER_TESTING_exchange_db_reset (config_filename))
+ return GNUNET_NO;
+ if (GNUNET_OK !=
+ TALER_TESTING_auditor_db_reset (config_filename))
+ return GNUNET_NO;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_parse_and_run (config_filename,
+ &sign_keys_for_exchange,
+ &si))
+ return GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Find denomination key matching the given amount.
+ *
+ * @param keys array of keys to search
+ * @param amount coin value to look for
+ * @return NULL if no matching key was found
+ */
+const struct TALER_EXCHANGE_DenomPublicKey *
+TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
+ const struct TALER_Amount *amount)
+{
+ struct GNUNET_TIME_Absolute now;
+ struct TALER_EXCHANGE_DenomPublicKey *pk;
+ char *str;
+
+ now = GNUNET_TIME_absolute_get ();
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ {
+ pk = &keys->denom_keys[i];
+ if ( (0 == TALER_amount_cmp (amount,
+ &pk->value)) &&
+ (now.abs_value_us >= pk->valid_from.abs_value_us) &&
+ (now.abs_value_us <
+ pk->withdraw_valid_until.abs_value_us) )
+ return pk;
+ }
+ /* do 2nd pass to check if expiration times are to blame for
+ * failure */
+ str = TALER_amount_to_string (amount);
+ for (unsigned int i = 0; i<keys->num_denom_keys; i++)
+ {
+ pk = &keys->denom_keys[i];
+ if ( (0 == TALER_amount_cmp (amount,
+ &pk->value)) &&
+ ( (now.abs_value_us < pk->valid_from.abs_value_us) ||
+ (now.abs_value_us >
+ pk->withdraw_valid_until.abs_value_us) ) )
+ {
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_WARNING,
+ "Have denomination key for `%s', but with wrong"
+ " expiration range %llu vs [%llu,%llu)\n",
+ str,
+ (unsigned long long) now.abs_value_us,
+ (unsigned long long) pk->valid_from.abs_value_us,
+ (unsigned long long)
+ pk->withdraw_valid_until.abs_value_us);
+ GNUNET_free (str);
+ return NULL;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No denomination key for amount %s found\n",
+ str);
+ GNUNET_free (str);
+ return NULL;
+}
+
+
+/**
+ * Wait for the exchange to have started. Waits for at
+ * most 10s, after that returns 77 to indicate an error.
+ *
+ * @param base_url what URL should we expect the exchange
+ * to be running at
+ * @return 0 on success
+ */
+int
+TALER_TESTING_wait_exchange_ready (const char *base_url)
+{
+ char *wget_cmd;
+ unsigned int iter;
+
+ GNUNET_asprintf (&wget_cmd,
+ "wget -q -t 1 -T 1 %skeys -o /dev/null -O /dev/null",
+ base_url); // make sure ends with '/'
+ /* give child time to start and bind against the socket */
+ fprintf (stderr,
+ "Waiting for `taler-exchange-httpd' to be ready (check with: %s)\n",
+ wget_cmd);
+ iter = 0;
+ do
+ {
+ if (10 == iter)
+ {
+ fprintf (stderr,
+ "Failed to launch `taler-exchange-httpd' (or `wget')\n");
+ GNUNET_free (wget_cmd);
+ return 77;
+ }
+ fprintf (stderr, ".\n");
+ sleep (1);
+ iter++;
+ }
+ while (0 != system (wget_cmd));
+ GNUNET_free (wget_cmd);
+ return 0;
+}
+
+
+/**
+ * Wait for the auditor to have started. Waits for at
+ * most 10s, after that returns 77 to indicate an error.
+ *
+ * @param base_url what URL should we expect the auditor
+ * to be running at
+ * @return 0 on success
+ */
+int
+TALER_TESTING_wait_auditor_ready (const char *base_url)
+{
+ char *wget_cmd;
+ unsigned int iter;
+
+ GNUNET_asprintf (&wget_cmd,
+ "wget -q -t 1 -T 1 %sversion -o /dev/null -O /dev/null",
+ base_url); // make sure ends with '/'
+ /* give child time to start and bind against the socket */
+ fprintf (stderr,
+ "Waiting for `taler-auditor-httpd' to be ready\n");
+ iter = 0;
+ do
+ {
+ if (10 == iter)
+ {
+ fprintf (stderr,
+ "Failed to launch `taler-auditor-httpd' (or `wget')\n");
+ GNUNET_free (wget_cmd);
+ return 77;
+ }
+ fprintf (stderr, ".\n");
+ sleep (1);
+ iter++;
+ }
+ while (0 != system (wget_cmd));
+ GNUNET_free (wget_cmd);
+ return 0;
+}
+
+
+/**
+ * Initialize scheduler loop and curl context for the testcase
+ * including starting and stopping the exchange using the given
+ * configuration file.
+ *
+ * @param main_cb routine containing all the commands to run.
+ * @param main_cb_cls closure for @a main_cb, typically NULL.
+ * @param config_file configuration file for the test-suite.
+ * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
+ * non-#GNUNET_OK codes are #GNUNET_SYSERR most of the
+ * time.
+ */
+int
+TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
+ void *main_cb_cls,
+ const char *config_file)
+{
+ struct TALER_TESTING_SetupContext setup_ctx = {
+ .config_filename = config_file,
+ .main_cb = main_cb,
+ .main_cb_cls = main_cb_cls
+ };
+ int result;
+
+ result =
+ GNUNET_CONFIGURATION_parse_and_run (config_file,
+ &TALER_TESTING_setup_with_exchange_cfg,
+ &setup_ctx);
+ if (GNUNET_OK != result)
+ return result;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Initialize scheduler loop and curl context for the test case
+ * including starting and stopping the exchange using the given
+ * configuration file.
+ *
+ * @param cls must be a `struct TALER_TESTING_SetupContext *`
+ * @param cfg configuration to use.
+ * @return #GNUNET_OK if no errors occurred.
+ */
+int
+TALER_TESTING_setup_with_exchange_cfg (void *cls,
+ const struct
+ GNUNET_CONFIGURATION_Handle *cfg)
+{
+ const struct TALER_TESTING_SetupContext *setup_ctx = cls;
+ struct GNUNET_OS_Process *exchanged;
+ unsigned long long port;
+ char *serve;
+ char *base_url;
+ int result;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "SERVE",
+ &serve))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "SERVE");
+ return GNUNET_NO;
+ }
+
+ if (0 == strcmp ("tcp", serve))
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "exchange",
+ "PORT",
+ &port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "PORT");
+ GNUNET_free (serve);
+ return GNUNET_NO;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
+ (uint16_t) port))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Required port %llu not available, skipping.\n",
+ port);
+ GNUNET_free (serve);
+ return GNUNET_NO;
+ }
+ }
+ GNUNET_free (serve);
+ exchanged = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-exchange-httpd",
+ "taler-exchange-httpd",
+ "-c", setup_ctx->config_filename,
+ "-i",
+ NULL);
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "BASE_URL",
+ &base_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL");
+ return GNUNET_NO;
+ }
+
+ if (0 != TALER_TESTING_wait_exchange_ready (base_url))
+ {
+ GNUNET_free (base_url);
+ return 77;
+ }
+ GNUNET_free (base_url);
+
+ /* NOTE: this call blocks. */
+ result = TALER_TESTING_setup (setup_ctx->main_cb,
+ setup_ctx->main_cb_cls,
+ setup_ctx->config_filename,
+ exchanged,
+ GNUNET_YES);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (exchanged,
+ SIGTERM));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_OS_process_wait (exchanged));
+ GNUNET_OS_process_destroy (exchanged);
+ return result;
+}
+
+
+/**
+ * Initialize scheduler loop and curl context for the test case
+ * including starting and stopping the auditor and exchange using the
+ * given configuration file.
+ *
+ * @param cls must be a `struct TALER_TESTING_SetupContext *`
+ * @param cfg configuration to use.
+ * @return #GNUNET_OK if no errors occurred.
+ */
+int
+TALER_TESTING_setup_with_auditor_and_exchange_cfg (void *cls,
+ const struct
+ GNUNET_CONFIGURATION_Handle *
+ cfg)
+{
+ const struct TALER_TESTING_SetupContext *setup_ctx = cls;
+ struct GNUNET_OS_Process *auditord;
+ unsigned long long port;
+ char *serve;
+ char *base_url;
+ int result;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "auditor",
+ "SERVE",
+ &serve))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "SERVE");
+ return GNUNET_NO;
+ }
+
+ if (0 == strcmp ("tcp", serve))
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "auditor",
+ "PORT",
+ &port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "PORT");
+ GNUNET_free (serve);
+ return GNUNET_NO;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
+ (uint16_t) port))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Required port %llu not available, skipping.\n",
+ port);
+ GNUNET_free (serve);
+ return GNUNET_NO;
+ }
+ }
+ GNUNET_free (serve);
+ auditord = GNUNET_OS_start_process (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "taler-auditor-httpd",
+ "taler-auditor-httpd",
+ "-c", setup_ctx->config_filename,
+ NULL);
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "auditor",
+ "BASE_URL",
+ &base_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "auditor",
+ "BASE_URL");
+ return GNUNET_NO;
+ }
+
+ if (0 != TALER_TESTING_wait_auditor_ready (base_url))
+ {
+ GNUNET_free (base_url);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (auditord,
+ SIGTERM));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_OS_process_wait (auditord));
+ GNUNET_OS_process_destroy (auditord);
+ return 77;
+ }
+ GNUNET_free (base_url);
+
+ /* NOTE: this call blocks. */
+ result = TALER_TESTING_setup_with_exchange_cfg ((void *) setup_ctx,
+ cfg);
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (auditord,
+ SIGTERM));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_OS_process_wait (auditord));
+ GNUNET_OS_process_destroy (auditord);
+ return result;
+}
+
+
+/**
+ * Initialize scheduler loop and curl context for the test case
+ * including starting and stopping the auditor and exchange using the
+ * given configuration file.
+ *
+ * @param main_cb main method.
+ * @param main_cb_cls main method closure.
+ * @param config_file configuration file name. Is is used
+ * by both this function and the exchange itself. In the
+ * first case it gives out the exchange port number and
+ * the exchange base URL so as to check whether the port
+ * is available and the exchange responds when requested
+ * at its base URL.
+ * @return #GNUNET_OK if no errors occurred.
+ */
+int
+TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
+ void *main_cb_cls,
+ const char *config_file)
+{
+ struct TALER_TESTING_SetupContext setup_ctx = {
+ .config_filename = config_file,
+ .main_cb = main_cb,
+ .main_cb_cls = main_cb_cls
+ };
+
+ return GNUNET_CONFIGURATION_parse_and_run (config_file,
+ &
+ TALER_TESTING_setup_with_auditor_and_exchange_cfg,
+ &setup_ctx);
+}
+
+
+/**
+ * Test port in URL string for availability.
+ *
+ * @param url URL to extract port from, 80 is default
+ * @return #GNUNET_OK if the port is free
+ */
+int
+TALER_TESTING_url_port_free (const char *url)
+{
+ const char *port;
+ long pnum;
+
+ port = strrchr (url,
+ (unsigned char) ':');
+ if (NULL == port)
+ pnum = 80;
+ else
+ pnum = strtol (port + 1, NULL, 10);
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
+ pnum))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Port %u not available.\n",
+ (unsigned int) pnum);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/* end of testing_api_helpers_exchange.c */
diff --git a/src/testing/testing_api_loop.c b/src/testing/testing_api_loop.c
@@ -0,0 +1,828 @@
+/*
+ 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 testing/testing_api_loop.c
+ * @brief main interpreter loop for testcases
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+#include "taler_fakebank_lib.h"
+
+/**
+ * Pipe used to communicate child death via signal.
+ * Must be global, as used in signal handler!
+ */
+static struct GNUNET_DISK_PipeHandle *sigpipe;
+
+/**
+ * Lookup command by label.
+ *
+ * @param is interpreter state to search
+ * @param label label to look for
+ * @return NULL if command was not found
+ */
+const struct TALER_TESTING_Command *
+TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
+ const char *label)
+{
+ if (NULL == label)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Attempt to lookup command for empty label\n");
+ return NULL;
+ }
+ /* Search backwards as we most likely reference recent commands */
+ for (int i = is->ip; i >= 0; i--)
+ {
+ const struct TALER_TESTING_Command *cmd = &is->commands[i];
+
+ /* Give precedence to top-level commands. */
+ if ( (NULL != cmd->label) &&
+ (0 == strcmp (cmd->label,
+ label)) )
+ return cmd;
+
+ if (TALER_TESTING_cmd_is_batch (cmd))
+ {
+#define BATCH_INDEX 1
+ struct TALER_TESTING_Command *batch;
+
+ GNUNET_assert (GNUNET_OK ==
+ TALER_TESTING_get_trait_cmd (cmd,
+ BATCH_INDEX,
+ &batch));
+ for (unsigned int j = 0;
+ NULL != (cmd = &batch[j])->label;
+ j++)
+ {
+ if ( (NULL != cmd->label) &&
+ (0 == strcmp (cmd->label,
+ label)) )
+ return cmd;
+ }
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Command not found: %s\n",
+ label);
+ return NULL;
+
+}
+
+
+/**
+ * Obtain main execution context for the main loop.
+ */
+struct GNUNET_CURL_Context *
+TALER_TESTING_interpreter_get_context
+ (struct TALER_TESTING_Interpreter *is)
+{
+ return is->ctx;
+}
+
+
+struct TALER_FAKEBANK_Handle *
+TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is)
+{
+ return is->fakebank;
+}
+
+
+/**
+ * Run tests starting the "fakebank" first. The "fakebank"
+ * is a C minimalist version of the human-oriented Python bank,
+ * which is also part of the Taler project.
+ *
+ * @param is pointer to the interpreter state
+ * @param commands the list of commands to execute
+ * @param bank_url the url the fakebank is supposed to run on
+ */
+void
+TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
+ struct TALER_TESTING_Command *commands,
+ const char *bank_url)
+{
+ const char *port;
+ long pnum;
+
+ port = strrchr (bank_url,
+ (unsigned char) ':');
+ if (NULL == port)
+ pnum = 80;
+ else
+ pnum = strtol (port + 1, NULL, 10);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Starting Fakebank on port %u (%s)\n",
+ (unsigned int) pnum,
+ bank_url);
+ is->fakebank = TALER_FAKEBANK_start ((uint16_t) pnum);
+ if (NULL == is->fakebank)
+ {
+ GNUNET_break (0);
+ is->result = GNUNET_SYSERR;
+ return;
+ }
+ TALER_TESTING_run (is,
+ commands);
+}
+
+
+/**
+ * Run the main interpreter loop that performs exchange operations.
+ *
+ * @param cls contains the `struct InterpreterState`
+ */
+static void
+interpreter_run (void *cls);
+
+
+/**
+ * Current command is done, run the next one.
+ */
+void
+TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
+{
+ static unsigned long long ipc;
+ static struct GNUNET_TIME_Absolute last_report;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+
+ if (GNUNET_SYSERR == is->result)
+ return; /* ignore, we already failled! */
+ if (TALER_TESTING_cmd_is_batch (cmd))
+ TALER_TESTING_cmd_batch_next (is);
+ else
+ is->ip++;
+ if (0 == (ipc % 1000))
+ {
+ if (0 != ipc)
+ GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+ "Interpreter executed 1000 instructions in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (
+ GNUNET_TIME_absolute_get_duration (last_report),
+ GNUNET_YES));
+ last_report = GNUNET_TIME_absolute_get ();
+ }
+ ipc++;
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
+ is);
+}
+
+
+/**
+ * Current command failed, clean up and fail the test case.
+ *
+ * @param is interpreter of the test
+ */
+void
+TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed at command `%s'\n",
+ cmd->label);
+ while (TALER_TESTING_cmd_is_batch (cmd))
+ {
+ cmd = TALER_TESTING_cmd_batch_get_current (cmd);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Batch is at command `%s'\n",
+ cmd->label);
+ }
+ is->result = GNUNET_SYSERR;
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Create command array terminator.
+ *
+ * @return a end-command.
+ */
+struct TALER_TESTING_Command
+TALER_TESTING_cmd_end (void)
+{
+ static struct TALER_TESTING_Command cmd;
+ cmd.label = NULL;
+
+ return cmd;
+}
+
+
+/**
+ * Obtain current label.
+ */
+const char *
+TALER_TESTING_interpreter_get_current_label (struct
+ TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+
+ return cmd->label;
+}
+
+
+/**
+ * Run the main interpreter loop that performs exchange operations.
+ *
+ * @param cls contains the `struct TALER_TESTING_Interpreter`
+ */
+static void
+interpreter_run (void *cls)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+
+ is->task = NULL;
+
+ if (NULL == cmd->label)
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Running command END\n");
+ is->result = GNUNET_OK;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Running command `%s'\n",
+ cmd->label);
+
+ cmd->run (cmd->cls,
+ cmd,
+ is);
+}
+
+
+/**
+ * Function run when the test terminates (good or bad).
+ * Cleans up our state.
+ *
+ * @param cls the interpreter state.
+ */
+static void
+do_shutdown (void *cls)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct TALER_TESTING_Command *cmd;
+ const char *label;
+
+ label = is->commands[is->ip].label;
+ if (NULL == label)
+ label = "END";
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Executing shutdown at `%s'\n",
+ label);
+
+ for (unsigned int j = 0;
+ NULL != (cmd = &is->commands[j])->label;
+ j++)
+ cmd->cleanup (cmd->cls,
+ cmd);
+
+ if (NULL != is->exchange)
+ {
+ TALER_LOG_DEBUG ("Disconnecting the exchange\n");
+ TALER_EXCHANGE_disconnect (is->exchange);
+ is->exchange = NULL;
+ }
+ if (NULL != is->task)
+ {
+ GNUNET_SCHEDULER_cancel (is->task);
+ is->task = NULL;
+ }
+ if (NULL != is->ctx)
+ {
+ GNUNET_CURL_fini (is->ctx);
+ is->ctx = NULL;
+ }
+ if (NULL != is->rc)
+ {
+ GNUNET_CURL_gnunet_rc_destroy (is->rc);
+ is->rc = NULL;
+ }
+ if (NULL != is->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (is->timeout_task);
+ is->timeout_task = NULL;
+ }
+ if (NULL != is->child_death_task)
+ {
+ GNUNET_SCHEDULER_cancel (is->child_death_task);
+ is->child_death_task = NULL;
+ }
+ if (NULL != is->fakebank)
+ {
+ TALER_FAKEBANK_stop (is->fakebank);
+ is->fakebank = NULL;
+ }
+ GNUNET_free_non_null (is->commands);
+}
+
+
+/**
+ * Function run when the test terminates (good or bad) with timeout.
+ *
+ * @param cls NULL
+ */
+static void
+do_timeout (void *cls)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+
+ is->timeout_task = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Terminating test due to timeout\n");
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * Task triggered whenever we receive a SIGCHLD (child
+ * process died).
+ *
+ * @param cls closure
+ */
+static void
+maint_child_death (void *cls)
+{
+ struct TALER_TESTING_Interpreter *is = cls;
+ struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
+ const struct GNUNET_DISK_FileHandle *pr;
+
+ struct GNUNET_OS_Process **processp;
+ char c[16];
+
+ if (TALER_TESTING_cmd_is_batch (cmd))
+ {
+ struct TALER_TESTING_Command *batch_cmd;
+
+ GNUNET_assert
+ (GNUNET_OK == TALER_TESTING_get_trait_cmd
+ (cmd, 0, &batch_cmd)); /* bad? */
+ cmd = batch_cmd;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got SIGCHLD for `%s'.\n",
+ cmd->label);
+
+ is->child_death_task = NULL;
+ pr = GNUNET_DISK_pipe_handle (sigpipe,
+ GNUNET_DISK_PIPE_END_READ);
+ GNUNET_break (0 <
+ GNUNET_DISK_file_read (pr,
+ &c,
+ sizeof (c)));
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_process (cmd,
+ 0,
+ &processp))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (is);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got the dead child process handle"
+ ", waiting for termination ...\n");
+
+ GNUNET_OS_process_wait (*processp);
+ GNUNET_OS_process_destroy (*processp);
+ *processp = NULL;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "... definitively terminated\n");
+
+ if (GNUNET_OK == is->reload_keys)
+ {
+ if (NULL == is->exchanged)
+ {
+ GNUNET_break (0);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Triggering key state reload at exchange\n");
+ GNUNET_break (0 == GNUNET_OS_process_kill
+ (is->exchanged, SIGUSR1));
+ sleep (5); /* make sure signal was received and processed */
+ }
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Dead child, go on with next command.\n");
+ TALER_TESTING_interpreter_next (is);
+}
+
+
+/**
+ * Wait until we receive SIGCHLD signal.
+ * Then obtain the process trait of the current
+ * command, wait on the the zombie and continue
+ * with the next command.
+ */
+void
+TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
+{
+ const struct GNUNET_DISK_FileHandle *pr;
+
+ GNUNET_assert (NULL == is->child_death_task);
+ pr = GNUNET_DISK_pipe_handle (sigpipe,
+ GNUNET_DISK_PIPE_END_READ);
+ is->child_death_task
+ = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ pr,
+ &maint_child_death,
+ is);
+}
+
+
+/**
+ * Run the testsuite. Note, CMDs are copied into
+ * the interpreter state because they are _usually_
+ * defined into the "run" method that returns after
+ * having scheduled the test interpreter.
+ *
+ * @param is the interpreter state
+ * @param commands the list of command to execute
+ * @param timeout how long to wait
+ */
+void
+TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
+ struct TALER_TESTING_Command *commands,
+ struct GNUNET_TIME_Relative timeout)
+{
+ unsigned int i;
+
+ if (NULL != is->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (is->timeout_task);
+ is->timeout_task = NULL;
+ }
+ /* get the number of commands */
+ for (i = 0; NULL != commands[i].label; i++)
+ ;
+ is->commands = GNUNET_new_array (i + 1,
+ struct TALER_TESTING_Command);
+ memcpy (is->commands,
+ commands,
+ sizeof (struct TALER_TESTING_Command) * i);
+ is->timeout_task = GNUNET_SCHEDULER_add_delayed
+ (timeout,
+ &do_timeout,
+ is);
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
+ is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is);
+}
+
+
+/**
+ * Run the testsuite. Note, CMDs are copied into
+ * the interpreter state because they are _usually_
+ * defined into the "run" method that returns after
+ * having scheduled the test interpreter.
+ *
+ * @param is the interpreter state
+ * @param commands the list of command to execute
+ */
+void
+TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
+ struct TALER_TESTING_Command *commands)
+{
+ TALER_TESTING_run2 (is,
+ commands,
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
+ 5));
+}
+
+
+/**
+ * Information used by the wrapper around the main
+ * "run" method.
+ */
+struct MainContext
+{
+ /**
+ * Main "run" method.
+ */
+ TALER_TESTING_Main main_cb;
+
+ /**
+ * Closure for @e main_cb.
+ */
+ void *main_cb_cls;
+
+ /**
+ * Interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Configuration filename. The wrapper uses it to fetch
+ * the exchange port number; We could have passed the port
+ * number here, but having the config filename seems more
+ * generic.
+ */
+ const char *config_filename;
+
+ /**
+ * URL of the exchange.
+ */
+ char *exchange_url;
+
+};
+
+
+/**
+ * Signal handler called for SIGCHLD. Triggers the
+ * respective handler by writing to the trigger pipe.
+ */
+static void
+sighandler_child_death ()
+{
+ static char c;
+ int old_errno = errno; /* back-up errno */
+
+ GNUNET_break (1 == GNUNET_DISK_file_write
+ (GNUNET_DISK_pipe_handle (sigpipe,
+ GNUNET_DISK_PIPE_END_WRITE),
+ &c, sizeof (c)));
+ errno = old_errno; /* restore errno */
+}
+
+
+/**
+ * "Canonical" cert_cb used when we are connecting to the
+ * Exchange.
+ *
+ * @param cls closure, typically, the "run" method containing
+ * all the commands to be run, and a closure for it.
+ * @param keys the exchange's keys.
+ * @param compat protocol compatibility information.
+ */
+void
+TALER_TESTING_cert_cb (void *cls,
+ const struct TALER_EXCHANGE_Keys *keys,
+ enum TALER_EXCHANGE_VersionCompatibility compat)
+{
+ struct MainContext *main_ctx = cls;
+ struct TALER_TESTING_Interpreter *is = main_ctx->is;
+
+ if (NULL == keys)
+ {
+ if (GNUNET_NO == is->working)
+ {
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_WARNING,
+ "Got NULL response for /keys"
+ " during startup, retrying!\n");
+ TALER_EXCHANGE_disconnect (is->exchange);
+ GNUNET_assert
+ (NULL != (is->exchange = TALER_EXCHANGE_connect
+ (is->ctx,
+ main_ctx->exchange_url,
+ &TALER_TESTING_cert_cb,
+ main_ctx,
+ TALER_EXCHANGE_OPTION_END)));
+ return;
+ }
+ else
+ GNUNET_log
+ (GNUNET_ERROR_TYPE_ERROR,
+ "Got NULL response for /keys"
+ " during execution!\n");
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got %d DK from /keys in generation %u\n",
+ keys->num_denom_keys,
+ is->key_generation + 1);
+ }
+ is->key_generation++;
+ is->keys = keys;
+
+ /* /keys has been called for some reason and
+ * the interpreter is already running. */
+ if (GNUNET_YES == is->working)
+ return;
+
+ is->working = GNUNET_YES;
+
+ /* Very first start of tests, call "run()" */
+ if (1 == is->key_generation)
+ {
+ main_ctx->main_cb (main_ctx->main_cb_cls,
+ is);
+ return;
+ }
+
+ /* Tests already started, just trigger the
+ * next command. */
+ TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
+ is->ip);
+ GNUNET_SCHEDULER_add_now (&interpreter_run,
+ 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);
+}
+
+
+/**
+ * Function run when the test is aborted before we launch the actual
+ * interpreter. Cleans up our state.
+ *
+ * @param cls the main context
+ */
+static void
+do_abort (void *cls)
+{
+ struct MainContext *main_ctx = cls;
+ struct TALER_TESTING_Interpreter *is = main_ctx->is;
+
+ is->timeout_task = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Executing abort prior to interpreter launch\n");
+ if (NULL != is->exchange)
+ {
+ TALER_EXCHANGE_disconnect (is->exchange);
+ is->exchange = NULL;
+ }
+}
+
+
+/**
+ * Initialize scheduler loop and curl context for the testcase,
+ * and responsible to run the "run" method.
+ *
+ * @param cls a `struct MainContext *`
+ * @param cfg configuration to use
+ */
+static int
+main_exchange_connect_with_cfg (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ struct MainContext *main_ctx = cls;
+ struct TALER_TESTING_Interpreter *is = main_ctx->is;
+ char *exchange_url;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "BASE_URL",
+ &exchange_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL");
+ return GNUNET_SYSERR;
+ }
+ main_ctx->exchange_url = exchange_url;
+ is->cfg = cfg;
+ is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
+ main_ctx);
+ GNUNET_break
+ (NULL != (is->exchange = TALER_EXCHANGE_connect
+ (is->ctx,
+ exchange_url,
+ &TALER_TESTING_cert_cb,
+ main_ctx,
+ TALER_EXCHANGE_OPTION_END)));
+ is->cfg = NULL;
+ return GNUNET_OK;
+}
+
+
+/**
+ * Initialize scheduler loop and curl context for the testcase,
+ * and responsible to run the "run" method.
+ *
+ * @param cls a `struct MainContext *`
+ */
+static void
+main_wrapper_exchange_connect (void *cls)
+{
+ struct MainContext *main_ctx = cls;
+
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_parse_and_run (main_ctx->config_filename,
+ &
+ main_exchange_connect_with_cfg,
+ main_ctx));
+}
+
+
+/**
+ * Install signal handlers plus schedules the main wrapper
+ * around the "run" method.
+ *
+ * @param main_cb the "run" method which contains all the
+ * commands.
+ * @param main_cb_cls a closure for "run", typically NULL.
+ * @param config_filename configuration filename.
+ * @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.. if NULL, the interpreter will run without
+ * trying to connect to the exchange first.
+ * @param exchange_connect #GNUNET_YES if the test should connect
+ * to the exchange, #GNUNET_NO otherwise
+ * @return #GNUNET_OK if all is okay, != #GNUNET_OK otherwise.
+ * non-GNUNET_OK codes are #GNUNET_SYSERR most of the
+ * times.
+ */
+int
+TALER_TESTING_setup (TALER_TESTING_Main main_cb,
+ void *main_cb_cls,
+ const char *config_filename,
+ struct GNUNET_OS_Process *exchanged,
+ int exchange_connect)
+{
+ struct TALER_TESTING_Interpreter is;
+ struct MainContext main_ctx = {
+ .main_cb = main_cb,
+ .main_cb_cls = main_cb_cls,
+ /* needed to init the curl ctx */
+ .is = &is,
+ /* needed to read values like exchange port
+ * number to construct the exchange url.*/
+ .config_filename = config_filename
+ };
+ struct GNUNET_SIGNAL_Context *shc_chld;
+
+ memset (&is,
+ 0,
+ sizeof (is));
+ is.exchanged = exchanged;
+ sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
+ GNUNET_NO, GNUNET_NO);
+ 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_CURL_enable_async_scope_header (is.ctx, "Taler-Correlation-Id");
+ GNUNET_assert (NULL != is.ctx);
+ is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
+
+ /* Blocking */
+
+ if (GNUNET_YES == exchange_connect)
+ GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
+ &main_ctx);
+ else
+ GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
+ &main_ctx);
+ if (NULL != is.final_cleanup_cb)
+ is.final_cleanup_cb (is.final_cleanup_cb_cls);
+ GNUNET_free_non_null (main_ctx.exchange_url);
+ GNUNET_SIGNAL_handler_uninstall (shc_chld);
+ GNUNET_DISK_pipe_close (sigpipe);
+ sigpipe = NULL;
+ return is.result;
+}
+
+
+/* end of testing_api_loop.c */
diff --git a/src/testing/testing_api_trait_amount.c b/src/testing/testing_api_trait_amount.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3,
+ or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_trait_amount.c
+ * @brief offer amounts as traits.
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_AMOUNT "amount"
+
+/**
+ * Obtain an amount from a @a cmd.
+ *
+ * @param cmd command to extract the amount from.
+ * @param index which amount to pick if @a cmd has multiple
+ * on offer
+ * @param[out] amount set to the amount.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_amount_obj (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_Amount **amount)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) amount,
+ TALER_TESTING_TRAIT_AMOUNT,
+ index);
+}
+
+
+/**
+ * Offer amount.
+ *
+ * @param index which amount to offer, in case there are
+ * multiple available.
+ * @param amount the amount to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_amount_obj (unsigned int index,
+ const struct TALER_Amount *amount)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_AMOUNT,
+ .ptr = (const void *) amount
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_amount.c */
diff --git a/src/testing/testing_api_trait_blinding_key.c b/src/testing/testing_api_trait_blinding_key.c
@@ -0,0 +1,77 @@
+/*
+ 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 testing/testing_api_trait_blinding_key.c
+ * @brief offer blinding keys as traits.
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_BLINDING_KEY "blinding-key"
+
+
+/**
+ * Obtain a blinding key from a @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index which coin to pick if @a cmd has multiple on offer.
+ * @param[out] blinding_key set to the offered blinding key.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_blinding_key
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_DenominationBlindingKeyP **blinding_key)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) blinding_key,
+ TALER_TESTING_TRAIT_BLINDING_KEY,
+ index);
+}
+
+
+/**
+ * Offer blinding key.
+ *
+ * @param index index number to associate to the offered key.
+ * @param blinding_key blinding key to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_blinding_key
+ (unsigned int index,
+ const struct TALER_DenominationBlindingKeyP *blinding_key)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_BLINDING_KEY,
+ .ptr = (const void *) blinding_key
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_blinding_key.c */
diff --git a/src/testing/testing_api_trait_cmd.c b/src/testing/testing_api_trait_cmd.c
@@ -0,0 +1,80 @@
+/*
+ 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 testing/testing_api_trait_cmd.c
+ * @brief offers CMDs as traits.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_CMD "cmd"
+
+
+/**
+ * Obtain a command from @a cmd.
+ *
+ * @param cmd command to extract the command from.
+ * @param index always zero. Commands offering this
+ * kind of traits do not need this index. For
+ * example, a "batch" CMD returns always the
+ * CMD currently being executed.
+ * @param[out] _cmd where to write the wire details.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_cmd (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ struct TALER_TESTING_Command **_cmd)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) _cmd,
+ TALER_TESTING_TRAIT_CMD,
+ index);
+}
+
+
+/**
+ * Offer a command in a trait.
+ *
+ * @param index always zero. Commands offering this
+ * kind of traits do not need this index. For
+ * example, a "meta" CMD returns always the
+ * CMD currently being executed.
+ * @param cmd wire details to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_cmd (unsigned int index,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_CMD,
+ .ptr = (const struct TALER_TESTING_Command *) cmd
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_cmd.c */
diff --git a/src/testing/testing_api_trait_coin_priv.c b/src/testing/testing_api_trait_coin_priv.c
@@ -0,0 +1,78 @@
+/*
+ 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 testing/testing_api_trait_coin_priv.c
+ * @brief coin priv traits.
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_COIN_PRIVATE_KEY "coin-private-key"
+
+
+/**
+ * Obtain a coin private key from a @a cmd.
+ *
+ * @param cmd command to extract trait from.
+ * @param index index of the coin priv to obtain.
+ * @param[out] coin_priv set to the private key of the coin.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_coin_priv
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_CoinSpendPrivateKeyP **coin_priv)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) coin_priv,
+ TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
+ index);
+}
+
+
+/**
+ * Offer coin private key.
+ *
+ * @param index index number to associate with offered coin priv.
+ * @param coin_priv coin private key to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_coin_priv
+ (unsigned int index,
+ const struct TALER_CoinSpendPrivateKeyP *coin_priv)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
+ .ptr = (const void *) coin_priv
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_coin_priv.c */
diff --git a/src/testing/testing_api_trait_contract.c b/src/testing/testing_api_trait_contract.c
@@ -0,0 +1,74 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_trait_contract.c
+ * @brief offers contract term trait.
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_testing_lib.h"
+
+
+/**
+ * Contains a contract terms object as a json_t.
+ */
+#define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms"
+
+
+/**
+ * Obtain contract terms from @a cmd.
+ *
+ * @param cmd command to extract the contract terms from.
+ * @param index contract terms index number.
+ * @param[out] contract_terms where to write the contract terms.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_contract_terms (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const json_t **contract_terms)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) contract_terms,
+ TALER_TESTING_TRAIT_CONTRACT_TERMS,
+ index);
+}
+
+
+/**
+ * Offer contract terms.
+ *
+ * @param index contract terms index number.
+ * @param contract_terms contract terms to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_contract_terms (unsigned int index,
+ const json_t *contract_terms)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_CONTRACT_TERMS,
+ .ptr = (const void *) contract_terms
+ };
+ return ret;
+}
diff --git a/src/testing/testing_api_trait_denom_pub.c b/src/testing/testing_api_trait_denom_pub.c
@@ -0,0 +1,77 @@
+/*
+ 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 testing/testing_api_trait_denom_pub.c
+ * @brief denom pub traits.
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_DENOM_PUB "denomination-public-key"
+
+
+/**
+ * Obtain a denomination public key from a @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index index number of the denom to obtain.
+ * @param[out] denom_pub set to the offered denom pub.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_denom_pub (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct
+ TALER_EXCHANGE_DenomPublicKey **denom_pub)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) denom_pub,
+ TALER_TESTING_TRAIT_DENOM_PUB,
+ index);
+}
+
+
+/**
+ * Make a trait for a denomination public key.
+ *
+ * @param index index number to associate to the offered denom pub.
+ * @param denom_pub denom pub to offer with this trait.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_denom_pub (unsigned int index,
+ const struct
+ TALER_EXCHANGE_DenomPublicKey *denom_pub)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_DENOM_PUB,
+ .ptr = (const void *) denom_pub
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_denom_pub.c */
diff --git a/src/testing/testing_api_trait_denom_sig.c b/src/testing/testing_api_trait_denom_sig.c
@@ -0,0 +1,79 @@
+/*
+ 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 testing/testing_api_trait_denom_sig.c
+ * @brief offer denomination signatures as traits
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_DENOM_SIG "denomination-signature"
+
+
+/**
+ * Obtain a denomination signature from a @a cmd.
+ *
+ * @param cmd command to extract the denom sig from.
+ * @param index index number associated with the denom sig.
+ * @param[out] denom_sig set to the offered signature.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_denom_sig
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_DenominationSignature **denom_sig)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) denom_sig,
+ TALER_TESTING_TRAIT_DENOM_SIG,
+ index);
+}
+
+
+/**
+ * Offer denom sig.
+ *
+ * @param index index number to associate to the signature on
+ * offer.
+ * @param denom_sig the denom sig on offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_denom_sig
+ (unsigned int index,
+ const struct TALER_DenominationSignature *denom_sig)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_DENOM_SIG,
+ .ptr = (const void *) denom_sig
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_denom_sig.c */
diff --git a/src/testing/testing_api_trait_exchange_pub.c b/src/testing/testing_api_trait_exchange_pub.c
@@ -0,0 +1,77 @@
+/*
+ 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 testing/testing_api_trait_exchange_pub.c
+ * @brief exchange pub traits.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_EXCHANGE_PUB "exchange-public-key"
+
+
+/**
+ * Obtain a exchange public key from a @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index index number of the exchange to obtain.
+ * @param[out] exchange_pub set to the offered exchange pub.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_exchange_pub
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_ExchangePublicKeyP **exchange_pub)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) exchange_pub,
+ TALER_TESTING_TRAIT_EXCHANGE_PUB,
+ index);
+}
+
+
+/**
+ * Make a trait for a exchange public key.
+ *
+ * @param index index number to associate to the offered exchange pub.
+ * @param exchange_pub exchange pub to offer with this trait.
+ *
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_exchange_pub
+ (unsigned int index,
+ const struct TALER_ExchangePublicKeyP *exchange_pub)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_EXCHANGE_PUB,
+ .ptr = (const void *) exchange_pub
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_exchange_pub.c */
diff --git a/src/testing/testing_api_trait_exchange_sig.c b/src/testing/testing_api_trait_exchange_sig.c
@@ -0,0 +1,77 @@
+/*
+ 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 testing/testing_api_trait_exchange_sig.c
+ * @brief exchange pub traits.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_EXCHANGE_SIG "exchange-online-signature"
+
+
+/**
+ * Obtain a exchange signature (online sig) from a @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index index number of the exchange to obtain.
+ * @param[out] exchange_sig set to the offered exchange signature.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_exchange_sig
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_ExchangeSignatureP **exchange_sig)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) exchange_sig,
+ TALER_TESTING_TRAIT_EXCHANGE_SIG,
+ index);
+}
+
+
+/**
+ * Make a trait for a exchange signature.
+ *
+ * @param index index number to associate to the offered exchange pub.
+ * @param exchange_sig exchange signature to offer with this trait.
+ *
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_exchange_sig
+ (unsigned int index,
+ const struct TALER_ExchangeSignatureP *exchange_sig)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_EXCHANGE_SIG,
+ .ptr = (const void *) exchange_sig
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_exchange_sig.c */
diff --git a/src/testing/testing_api_trait_fresh_coin.c b/src/testing/testing_api_trait_fresh_coin.c
@@ -0,0 +1,77 @@
+/*
+ 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 testing/testing_api_trait_fresh_coin.c
+ * @brief traits to offer fresh conins (after "melt" operations)
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_FRESH_COINS "fresh-coins"
+
+/**
+ * Get a array of fresh coins.
+ *
+ * @param cmd command to extract the fresh coin from.
+ * @param index which array to pick if @a cmd has multiple
+ * on offer.
+ * @param[out] fresh_coins will point to the offered array.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_fresh_coins
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_TESTING_FreshCoinData **fresh_coins)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) fresh_coins,
+ TALER_TESTING_TRAIT_FRESH_COINS,
+ index);
+}
+
+
+/**
+ * Offer a _array_ of fresh coins.
+ *
+ * @param index which array of fresh coins to offer,
+ * if there are multiple on offer. Typically passed as
+ * zero.
+ * @param fresh_coins the array of fresh coins to offer
+ * @return the trait,
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_fresh_coins
+ (unsigned int index,
+ const struct TALER_TESTING_FreshCoinData *fresh_coins)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_FRESH_COINS,
+ .ptr = (const void *) fresh_coins
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_fresh_coin.c */
diff --git a/src/testing/testing_api_trait_json.c b/src/testing/testing_api_trait_json.c
@@ -0,0 +1,123 @@
+/*
+ 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 testing/testing_api_trait_json.c
+ * @brief offers JSON traits.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details"
+#define TALER_TESTING_TRAIT_EXCHANGE_KEYS "exchange-keys"
+
+/**
+ * Obtain serialized exchange keys from @a cmd.
+ *
+ * @param cmd command to extract the keys from.
+ * @param index index number associate with the keys on offer.
+ * @param[out] keys where to write the serialized keys.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_exchange_keys
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const json_t **keys)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) keys,
+ TALER_TESTING_TRAIT_EXCHANGE_KEYS,
+ index);
+}
+
+
+/**
+ * Offer serialized keys in a trait.
+ *
+ * @param index index number associate with the serial keys
+ * on offer.
+ * @param keys serialized keys to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_exchange_keys
+ (unsigned int index,
+ const json_t *keys)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_EXCHANGE_KEYS,
+ .ptr = (const json_t *) keys
+ };
+ return ret;
+}
+
+
+/**
+ * Obtain wire details from @a cmd.
+ *
+ * @param cmd command to extract the wire details from.
+ * @param index index number associate with the wire details
+ * on offer; usually zero, as one command sticks to
+ * one bank account.
+ * @param[out] wire_details where to write the wire details.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_wire_details
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const json_t **wire_details)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) wire_details,
+ TALER_TESTING_TRAIT_WIRE_DETAILS,
+ index);
+}
+
+
+/**
+ * Offer wire details in a trait.
+ *
+ * @param index index number associate with the wire details
+ * on offer; usually zero, as one command sticks to
+ * one bank account.
+ * @param wire_details wire details to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_wire_details
+ (unsigned int index,
+ const json_t *wire_details)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS,
+ .ptr = (const json_t *) wire_details
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_json.c */
diff --git a/src/testing/testing_api_trait_merchant_key.c b/src/testing/testing_api_trait_merchant_key.c
@@ -0,0 +1,127 @@
+/*
+ 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 testing/testing_api_trait_merchant_key.c
+ * @brief traits to offer peer's (private) keys
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_MERCHANT_PRIV "merchant-priv"
+#define TALER_TESTING_TRAIT_MERCHANT_PUB "merchant-pub-pub"
+
+/**
+ * Obtain a private key from a "peer". Used e.g. to obtain
+ * a merchant's priv to sign a /track request.
+ *
+ * @param cmd command that is offering the key.
+ * @param index (typically zero) which key to return if there
+ * are multiple on offer.
+ * @param[out] priv set to the key coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_merchant_priv
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_MerchantPrivateKeyP **priv)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) priv,
+ TALER_TESTING_TRAIT_MERCHANT_PRIV,
+ index);
+}
+
+
+/**
+ * Offer private key, typically done when CMD_1 needs it to
+ * sign a request.
+ *
+ * @param index (typically zero) which key to return if there are
+ * multiple on offer.
+ * @param priv which object should be offered.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_merchant_priv (unsigned int index,
+ const struct
+ TALER_MerchantPrivateKeyP *priv)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_MERCHANT_PRIV,
+ .ptr = (const void *) priv
+ };
+
+ return ret;
+}
+
+
+/**
+ * Obtain a public key from a "peer". Used e.g. to obtain
+ * a merchant's public key to use backend's API.
+ *
+ * @param cmd command offering the key.
+ * @param index (typically zero) which key to return if there
+ * are multiple on offer.
+ * @param[out] pub set to the key coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_merchant_pub
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_MerchantPublicKeyP **pub)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) pub,
+ TALER_TESTING_TRAIT_MERCHANT_PUB,
+ index);
+}
+
+
+/**
+ * Offer public key.
+ *
+ * @param index (typically zero) which key to return if there
+ * are multiple on offer. NOTE: if one key is offered, it
+ * is mandatory to set this as zero.
+ * @param pub which object should be returned.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_merchant_pub (unsigned int index,
+ const struct
+ TALER_MerchantPublicKeyP *pub)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_MERCHANT_PUB,
+ .ptr = (const void *) pub
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_merchant_key.c */
diff --git a/src/testing/testing_api_trait_number.c b/src/testing/testing_api_trait_number.c
@@ -0,0 +1,149 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_trait_number.c
+ * @brief traits to offer numbers
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_UINT "uint"
+#define TALER_TESTING_TRAIT_UINT64 "uint-64"
+#define TALER_TESTING_TRAIT_BANK_ROW "bank-transaction-row"
+
+
+/**
+ * Obtain a number from @a cmd.
+ *
+ * @param cmd command to extract the number from.
+ * @param index the number's index number.
+ * @param[out] n set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_uint (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const unsigned int **n)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) n,
+ TALER_TESTING_TRAIT_UINT,
+ index);
+}
+
+
+/**
+ * Offer a number.
+ *
+ * @param index the number's index number.
+ * @param n the number to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_uint (unsigned int index,
+ const unsigned int *n)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_UINT,
+ .ptr = (const void *) n
+ };
+ return ret;
+}
+
+
+/**
+ * Obtain a "number" value from @a cmd, 64-bit version.
+ *
+ * @param cmd command to extract the number from.
+ * @param index the number's index number.
+ * @param[out] n 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,
+ (const void **) n,
+ TALER_TESTING_TRAIT_UINT64,
+ index);
+}
+
+
+/**
+ * Offer number trait, 64-bit version.
+ *
+ * @param index the number's index number.
+ * @param n number to offer.
+ */
+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;
+}
+
+
+/**
+ * Obtain a bank transaction row value from @a cmd.
+ *
+ * @param cmd command to extract the number from.
+ * @param[out] row set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_bank_row (const struct TALER_TESTING_Command *cmd,
+ const uint64_t **row)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) row,
+ TALER_TESTING_TRAIT_BANK_ROW,
+ 0);
+}
+
+
+/**
+ * Offer bank transaction row trait.
+ *
+ * @param row number to offer.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_bank_row (const uint64_t *row)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = 0,
+ .trait_name = TALER_TESTING_TRAIT_BANK_ROW,
+ .ptr = (const void *) row
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_number.c */
diff --git a/src/testing/testing_api_trait_process.c b/src/testing/testing_api_trait_process.c
@@ -0,0 +1,82 @@
+/*
+ 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 testing/testing_api_trait_process.c
+ * @brief trait offering process handles.
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_PROCESS "process"
+
+
+/**
+ * Obtain location where a command stores a pointer to a process.
+ *
+ * @param cmd command to extract trait from.
+ * @param index which process to pick if @a cmd
+ * has multiple on offer.
+ * @param[out] processp set to the address of the pointer to the
+ * process.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_process
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ struct GNUNET_OS_Process ***processp)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) processp,
+ TALER_TESTING_TRAIT_PROCESS,
+ index);
+}
+
+
+/**
+ * Offer location where a command stores a pointer to a process.
+ *
+ * @param index offered location index number, in case there are
+ * multiple on offer.
+ * @param processp process location to offer.
+ *
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_process
+ (unsigned int index,
+ struct GNUNET_OS_Process **processp)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_PROCESS,
+ .ptr = (const void *) processp
+ };
+
+ return ret;
+}
+
+
+/* end of testing_api_trait_process.c */
diff --git a/src/testing/testing_api_trait_reserve_priv.c b/src/testing/testing_api_trait_reserve_priv.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file testing/testing_api_trait_reserve_priv.c
+ * @brief implements reserve private key trait
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY \
+ "reserve-private-key"
+
+/**
+ * Obtain a reserve private key from a @a cmd.
+ *
+ * @param cmd command to extract the reserve priv from.
+ * @param index reserve priv's index number.
+ * @param[out] reserve_priv set to the reserve priv.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_reserve_priv
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_ReservePrivateKeyP **reserve_priv)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) reserve_priv,
+ TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
+ index);
+}
+
+
+/**
+ * Offer a reserve private key.
+ *
+ * @param index reserve priv's index number.
+ * @param reserve_priv reserve private key to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_reserve_priv
+ (unsigned int index,
+ const struct TALER_ReservePrivateKeyP *reserve_priv)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
+ .ptr = (const void *) reserve_priv
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_reserve_priv.c */
diff --git a/src/testing/testing_api_trait_reserve_pub.c b/src/testing/testing_api_trait_reserve_pub.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_trait_reserve_pub.c
+ * @brief implements reserve public key trait
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \
+ "reserve-public-key"
+
+/**
+ * Obtain a reserve public key from a @a cmd.
+ *
+ * @param cmd command to extract the reserve pub from.
+ * @param index reserve pub's index number.
+ * @param[out] reserve_pub set to the reserve pub.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_reserve_pub
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_ReservePublicKeyP **reserve_pub)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) reserve_pub,
+ TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
+ index);
+}
+
+
+/**
+ * Offer a reserve public key.
+ *
+ * @param index reserve pub's index number.
+ * @param reserve_pub reserve public key to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_reserve_pub
+ (unsigned int index,
+ const struct TALER_ReservePublicKeyP *reserve_pub)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY,
+ .ptr = (const void *) reserve_pub
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_reserve_pub.c */
diff --git a/src/testing/testing_api_trait_string.c b/src/testing/testing_api_trait_string.c
@@ -0,0 +1,231 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018-2020 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 testing/testing_api_trait_string.c
+ * @brief offers strings traits.
+ * @author Marcello Stanisci
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+/**
+ * Some string. Avoid, use something more precise!
+ */
+#define TALER_TESTING_TRAIT_STRING "string"
+
+/**
+ * An HTTP-URL.
+ */
+#define TALER_TESTING_TRAIT_URL "url"
+
+/**
+ * A PAYTO-URL.
+ */
+#define TALER_TESTING_TRAIT_PAYTO "payto"
+
+/**
+ * String identifying an order.
+ */
+#define TALER_TESTING_TRAIT_ORDER_ID "order-id"
+
+
+/**
+ * Obtain a string from @a cmd.
+ *
+ * @param cmd command to extract the subject from.
+ * @param index index number associated with the transfer
+ * subject to offer.
+ * @param[out] s where to write the offered
+ * string
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_string (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const char **s)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) s,
+ TALER_TESTING_TRAIT_STRING,
+ index);
+}
+
+
+/**
+ * Offer string.
+ *
+ * @param index index number associated with the transfer
+ * subject being offered.
+ * @param s transfer subject to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_string (unsigned int index,
+ const char *s)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_STRING,
+ .ptr = (const void *) s
+ };
+ return ret;
+}
+
+
+/**
+ * Obtain a HTTP url from @a cmd.
+ *
+ * @param cmd command to extract the url from.
+ * @param index which url is to be picked, in case
+ * multiple are offered.
+ * @param[out] url where to write the url.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_url (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const char **url)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) url,
+ TALER_TESTING_TRAIT_URL,
+ index);
+}
+
+
+/**
+ * Offer HTTP url in a trait.
+ *
+ * @param index which url is to be picked,
+ * in case multiple are offered.
+ * @param url the url to offer.
+ *
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_url (unsigned int index,
+ const char *url)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_URL,
+ .ptr = (const void *) url
+ };
+
+ GNUNET_assert (0 != strncasecmp (url,
+ "payto://",
+ strlen ("payto://")));
+
+ return ret;
+}
+
+
+/**
+ * Obtain a order id from @a cmd.
+ *
+ * @param cmd command to extract the order id from.
+ * @param index which order id is to be picked, in case
+ * multiple are offered.
+ * @param[out] order_id where to write the order id.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_order_id (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const char **order_id)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) order_id,
+ TALER_TESTING_TRAIT_ORDER_ID,
+ index);
+}
+
+
+/**
+ * Offer order id in a trait.
+ *
+ * @param index which order id is to be offered,
+ * in case multiple are offered.
+ * @param order_id the order id to offer.
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_order_id (unsigned int index,
+ const char *order_id)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_ORDER_ID,
+ .ptr = (const void *) order_id
+ };
+ return ret;
+}
+
+
+/**
+ * Obtain a PAYTO-url from @a cmd.
+ *
+ * @param cmd command to extract the url from.
+ * @param pt which url is to be picked, in case
+ * multiple are offered.
+ * @param[out] url where to write the url.
+ * @return #GNUNET_OK on success.
+ */
+int
+TALER_TESTING_get_trait_payto (const struct TALER_TESTING_Command *cmd,
+ enum TALER_TESTING_PaytoType pt,
+ const char **url)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) url,
+ TALER_TESTING_TRAIT_PAYTO,
+ (unsigned int) pt);
+}
+
+
+/**
+ * Offer a "payto" URL reference.
+ *
+ * @param pt which reference is to be offered,
+ * in case multiple are offered.
+ * @param payto_uri the payto URI
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_payto (enum TALER_TESTING_PaytoType pt,
+ const char *payto_uri)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = (unsigned int) pt,
+ .trait_name = TALER_TESTING_TRAIT_PAYTO,
+ .ptr = (const void *) payto_uri,
+ };
+
+ GNUNET_assert (0 == strncasecmp (payto_uri,
+ "payto://",
+ strlen ("payto://")));
+ return ret;
+}
+
+
+/* end of testing_api_trait_string.c */
diff --git a/src/testing/testing_api_trait_time.c b/src/testing/testing_api_trait_time.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_trait_time.c
+ * @brief traits to offer time stamps.
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_TIME_ABS "time-abs"
+
+/**
+ * Obtain a absolute time from @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index which time stamp to pick if
+ * @a cmd has multiple on offer.
+ * @param[out] time set to the wanted WTID.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_absolute_time
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct GNUNET_TIME_Absolute **time)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) time,
+ TALER_TESTING_TRAIT_TIME_ABS,
+ index);
+}
+
+
+/**
+ * Offer a absolute time.
+ *
+ * @param index associate the object with this index
+ * @param time which object should be returned
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_absolute_time
+ (unsigned int index,
+ const struct GNUNET_TIME_Absolute *time)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_TIME_ABS,
+ .ptr = (const void *) time
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_time.c */
diff --git a/src/testing/testing_api_trait_wtid.c b/src/testing/testing_api_trait_wtid.c
@@ -0,0 +1,76 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2018 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file testing/testing_api_trait_number.c
+ * @brief traits to offer numbers
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+#define TALER_TESTING_TRAIT_WTID "wtid"
+
+/**
+ * Obtain a WTID value from @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index which WTID to pick if @a cmd has multiple on
+ * offer
+ * @param[out] wtid set to the wanted WTID.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_wtid
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct TALER_WireTransferIdentifierRawP **wtid)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) wtid,
+ TALER_TESTING_TRAIT_WTID,
+ index);
+}
+
+
+/**
+ * Offer a WTID.
+ *
+ * @param index associate the object with this index
+ * @param wtid which object should be returned
+ * @return the trait.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_wtid
+ (unsigned int index,
+ const struct TALER_WireTransferIdentifierRawP *wtid)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_WTID,
+ .ptr = (const void *) wtid
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_number.c */
diff --git a/src/testing/testing_api_traits.c b/src/testing/testing_api_traits.c
@@ -0,0 +1,81 @@
+/*
+ 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 testing/testing_api_traits.c
+ * @brief loop for trait resolution
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+#include "platform.h"
+#include "taler_json_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_signatures.h"
+#include "taler_testing_lib.h"
+
+
+/**
+ * End a trait array. Usually, commands offer several traits,
+ * and put them in arrays.
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_trait_end ()
+{
+ struct TALER_TESTING_Trait end = {
+ .index = 0,
+ .trait_name = NULL,
+ .ptr = NULL
+ };
+
+ return end;
+}
+
+
+/**
+ * Pick the chosen trait from the traits array.
+ *
+ * @param traits the traits array.
+ * @param ret where to store the result.
+ * @param trait type of the trait to extract.
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
+ */
+int
+TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ for (unsigned int i = 0; NULL != traits[i].trait_name; i++)
+ {
+ if ( (0 == strcmp (trait, traits[i].trait_name)) &&
+ (index == traits[i].index) )
+ {
+ *ret = (void *) traits[i].ptr;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Trait %s/%u not found.\n",
+ trait, index);
+
+ return GNUNET_SYSERR;
+}
+
+
+/* end of testing_api_traits.c */