Implement new traits-based tests.

This commit is contained in:
Marcello Stanisci 2018-01-23 10:28:24 +01:00
parent b198bb3867
commit fe6960cce8
No known key found for this signature in database
GPG Key ID: 8D526861953F4C0F
38 changed files with 7425 additions and 450 deletions

2
.gitignore vendored
View File

@ -36,6 +36,7 @@ src/auditor/taler-auditor
src/auditor/taler-auditor-sign src/auditor/taler-auditor-sign
src/bank-lib/test_bank_api src/bank-lib/test_bank_api
src/bank-lib/test_bank_api_with_fakebank src/bank-lib/test_bank_api_with_fakebank
src/exchange-lib/test_exchange_api_new
src/exchange-lib/test_exchange_api src/exchange-lib/test_exchange_api
src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/live-keys/ src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/live-keys/
src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/wirefees/ src/exchange-lib/test_exchange_api_home/.local/share/taler/exchange/wirefees/
@ -86,6 +87,7 @@ doc/manual/manual.vr
contrib/taler-exchange.tag contrib/taler-exchange.tag
doxygen-doc/ doxygen-doc/
src/exchange-lib/test_exchange_api_keys_cherry_picking src/exchange-lib/test_exchange_api_keys_cherry_picking
src/exchange-lib/test_exchange_api_keys_cherry_picking_new
src/auditor/taler-wire-auditor src/auditor/taler-wire-auditor
contrib/auditor-report.aux contrib/auditor-report.aux
contrib/auditor-report.log contrib/auditor-report.log

View File

@ -34,14 +34,26 @@ libtalerexchange_la_LIBADD = \
-ljansson \ -ljansson \
$(XLIB) $(XLIB)
libtalertesting_la_LDFLAGS = \ libtalertesting_la_LDFLAGS = \
-version-info 0:0:0 \ -version-info 0:0:0 \
-no-undefined -no-undefined
libtalertesting_la_SOURCES = \ libtalertesting_la_SOURCES = \
testing_api_cmd_exec_aggregator.c \
testing_api_cmd_exec_wirewatch.c \ testing_api_cmd_exec_wirewatch.c \
testing_api_cmd_exec_keyup.c \
testing_api_cmd_exec_auditor-sign.c \
testing_api_cmd_fakebank_transfer.c \ testing_api_cmd_fakebank_transfer.c \
testing_api_cmd_withdraw.c \ testing_api_cmd_withdraw.c \
testing_api_cmd_wire.c \
testing_api_cmd_refund.c \
testing_api_cmd_status.c \
testing_api_cmd_deposit.c \
testing_api_cmd_refresh.c \
testing_api_cmd_track.c \
testing_api_cmd_bank_check.c \
testing_api_cmd_payback.c \
testing_api_cmd_signal.c \
testing_api_cmd_check_keys.c \
testing_api_helpers.c \ testing_api_helpers.c \
testing_api_loop.c \ testing_api_loop.c \
testing_api_traits.c \ testing_api_traits.c \
@ -50,7 +62,12 @@ libtalertesting_la_SOURCES = \
testing_api_trait_denom_pub.c \ testing_api_trait_denom_pub.c \
testing_api_trait_denom_sig.c \ testing_api_trait_denom_sig.c \
testing_api_trait_process.c \ testing_api_trait_process.c \
testing_api_trait_reserve_priv.c testing_api_trait_reserve_priv.c \
testing_api_trait_number.c \
testing_api_trait_fresh_coin.c \
testing_api_trait_string.c \
testing_api_trait_key_peer.c \
testing_api_trait_wtid.c
libtalertesting_la_LIBADD = \ libtalertesting_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/json/libtalerjson.la \
@ -71,13 +88,17 @@ endif
endif endif
check_PROGRAMS = \ check_PROGRAMS = \
test_exchange_api_keys_cherry_picking_new \
test_exchange_api_new \
test_exchange_api \ test_exchange_api \
test_exchange_api_keys_cherry_picking \ test_exchange_api_keys_cherry_picking
test_exchange_api_new
AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
# FIXME: uncomment those.
TESTS = \ TESTS = \
test_exchange_api_keys_cherry_picking_new \
test_exchange_api_new \
test_exchange_api \ test_exchange_api \
test_exchange_api_keys_cherry_picking test_exchange_api_keys_cherry_picking
@ -108,6 +129,19 @@ test_exchange_api_new_LDADD = \
-lgnunetutil \ -lgnunetutil \
-ljansson -ljansson
test_exchange_api_keys_cherry_picking_new_SOURCES = \
test_exchange_api_keys_cherry_picking_new.c
test_exchange_api_keys_cherry_picking_new_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_keys_cherry_picking_SOURCES = \ test_exchange_api_keys_cherry_picking_SOURCES = \
test_exchange_api_keys_cherry_picking.c test_exchange_api_keys_cherry_picking.c
test_exchange_api_keys_cherry_picking_LDADD = \ test_exchange_api_keys_cherry_picking_LDADD = \

View File

@ -1,7 +1,7 @@
# This file is in the public domain. # This file is in the public domain.
# #
[PATHS] [PATHS]
# Persistant data storage for the testcase # Persistent data storage for the testcase
TALER_TEST_HOME = test_exchange_api_home/ TALER_TEST_HOME = test_exchange_api_home/
[taler] [taler]

View File

@ -0,0 +1,135 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/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"
/**
* 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"
/**
* 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[] = {
/* Send signal to the exchange to see if it reacts */
TALER_TESTING_cmd_signal ("signal-reaction-1",
is->exchanged,
SIGUSR1),
TALER_TESTING_cmd_check_keys ("check-keys-1",
1, 4,
is->exchange),
TALER_TESTING_cmd_exec_keyup ("keyup-2", /* 1st keyup happens at start-up */
CONFIG_FILE_EXTENDED),
TALER_TESTING_cmd_exec_auditor_sign ("sign-keys-1",
CONFIG_FILE),
TALER_TESTING_cmd_signal ("trigger-keys-reload-1",
is->exchanged,
SIGUSR1),
TALER_TESTING_cmd_check_keys ("check-keys-2",
2, 8,
is->exchange),
/**
* End the suite. Fixme: better to have a label for this
* too, as it shows "(null)" in logs.
*/
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))
{
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 */

View File

@ -2,23 +2,29 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA Copyright (C) 2014-2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify
terms of the GNU General Public License as published by the Free Software it under the terms of the GNU General Public License as
Foundation; either version 3, or (at your option) any later version. published by the Free Software Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/ */
/** /**
* @file exchange/test_exchange_api_new.c * @file exchange/test_exchange_api_new.c
* @brief testcase to test exchange's HTTP API interface * @brief testcase to test exchange's HTTP API interface
* @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Sree Harsha Totakura <sreeharsha@totakura.in>
* @author Christian Grothoff * @author Christian Grothoff
* @author Marcello Stanisci
*/ */
#include "platform.h" #include "platform.h"
#include "taler_util.h" #include "taler_util.h"
#include "taler_signatures.h" #include "taler_signatures.h"
@ -37,10 +43,17 @@
#define CONFIG_FILE "test_exchange_api.conf" #define CONFIG_FILE "test_exchange_api.conf"
/** /**
* URL of the fakebank. Obtained from CONFIG_FILE's "exchange-wire-test:BANK_URL" option. * URL of the fakebank. Obtained from CONFIG_FILE's
* "exchange-wire-test:BANK_URI" option.
*/ */
static char *fakebank_url; static char *fakebank_url;
/**
* FIXME: what about putting exchange_url also global
* here? Right now, the exchange port is being "bounced"
* between functions before exchange_url is constructed
* and TALER_EXCHANGE_connect() is called with that.
*/
/** /**
* Account number of the exchange at the bank. * Account number of the exchange at the bank.
@ -71,6 +84,15 @@ static char *fakebank_url;
#define CMD_EXEC_WIREWATCH(label) \ #define CMD_EXEC_WIREWATCH(label) \
TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE) 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 * Run wire transfer of funds from some user's account to the
* exchange. * exchange.
@ -83,9 +105,22 @@ static char *fakebank_url;
fakebank_url, USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO, \ fakebank_url, USER_ACCOUNT_NO, EXCHANGE_ACCOUNT_NO, \
USER_LOGIN_NAME, USER_LOGIN_PASS) USER_LOGIN_NAME, USER_LOGIN_PASS)
/**
* 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_SUBJECT(label,amount,subject) \
TALER_TESTING_cmd_fakebank_transfer_with_subject \
(label, amount, fakebank_url, USER_ACCOUNT_NO, \
EXCHANGE_ACCOUNT_NO, USER_LOGIN_NAME, USER_LOGIN_PASS, \
subject)
/** /**
* Main function that will tell the interpreter what commands to run. * Main function that will tell the interpreter what commands to
* run.
* *
* @param cls closure * @param cls closure
*/ */
@ -94,9 +129,609 @@ run (void *cls,
struct TALER_TESTING_Interpreter *is) struct TALER_TESTING_Interpreter *is)
{ {
struct TALER_TESTING_Command commands[] = { struct TALER_TESTING_Command commands[] = {
/****** Start of "wire" testing ******/
/**
* Move money to the exchange's bank account.
*/
CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1", CMD_TRANSFER_TO_EXCHANGE ("create-reserve-1",
"EUR:5.01"), "EUR:5.01"),
CMD_EXEC_WIREWATCH ("exec-wirewatch-1"),
/**
* Make a reserve exist, according to the previous
* transfer.
*/
CMD_EXEC_WIREWATCH ("wirewatch-1"),
/**
* Check if 'test' wire method is offered by the exchange.
*/
TALER_TESTING_cmd_wire ("wire-test-1",
is->exchange,
"test",
NULL,
MHD_HTTP_OK),
/**
* Check if 'sepa' wire method is offered by the exchange.
*/
TALER_TESTING_cmd_wire ("wire-sepa-1",
is->exchange,
"sepa",
NULL,
MHD_HTTP_OK),
/****** End of "wire" testing ******/
/****** Start of withdraw and spend testing ******/
/**
* Withdraw EUR:5.
*/
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
is->exchange,
"create-reserve-1",
"EUR:5",
MHD_HTTP_OK),
/**
* Check the reserve is depleted.
*/
TALER_TESTING_cmd_status ("status-1",
is->exchange,
"create-reserve-1",
"EUR:0",
MHD_HTTP_OK),
/**
* Spend the coin.
*/
TALER_TESTING_cmd_deposit
("deposit-simple", is->exchange, "withdraw-coin-1", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":42}",
fakebank_url),
"{\"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",
is->exchange,
"create-reserve-1",
"EUR:5",
MHD_HTTP_FORBIDDEN),
/**
* Try to double spend using different wire details.
*/
TALER_TESTING_cmd_deposit
("deposit-double-1", is->exchange, "withdraw-coin-1", 0,
TALER_TESTING_make_wire_details
("{\"type\":\"test\",\"account_number\":43}",
fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
/**
* Try to double spend using a different transaction id.
* (copied verbatim from old exchange-lib tests.)
* FIXME: how can it get a different transaction id? There
* isn't such a thing actually, the exchange only knows about
* contract terms' hashes. So since the contract terms are
* exactly the same as the previous command, how can a different
* id be generated?
*/
TALER_TESTING_cmd_deposit
("deposit-double-1", is->exchange, "withdraw-coin-1", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\", \"account_number\":43}",
fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
/**
* Try to double spend with different proposal.
*/
TALER_TESTING_cmd_deposit
("deposit-double-2", is->exchange, "withdraw-coin-1", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\", \"account_number\":43}",
fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
/****** End of withdraw and spend testing ******/
/****** Start of refresh testing ******/
/**
* 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"),
/**
* Make previous command effective.
*/
CMD_EXEC_WIREWATCH ("wirewatch-2"),
/**
* Withdraw EUR:5.
*/
TALER_TESTING_cmd_withdraw_amount
("refresh-withdraw-coin-1",
is->exchange,
"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", is->exchange,
"refresh-withdraw-coin-1", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":42}",
fakebank_url),
"{\"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-1", is->exchange, "EUR:4",
"refresh-withdraw-coin-1", MHD_HTTP_OK),
/**
* Complete (successful) melt operation, and
* withdraw the coins
*/
TALER_TESTING_cmd_refresh_reveal
("refresh-reveal-1", is->exchange,
"refresh-melt-1", MHD_HTTP_OK),
/**
* Do it again to check idempotency
*/
TALER_TESTING_cmd_refresh_reveal
("refresh-reveal-1-idempotency",
is->exchange, "refresh-melt-1", MHD_HTTP_OK),
/**
* Test that /refresh/link works
*/
TALER_TESTING_cmd_refresh_link
("refresh-link-1", is->exchange,
"refresh-reveal-1", MHD_HTTP_OK),
/**
* Try to spend a refreshed EUR:1 coin
*/
TALER_TESTING_cmd_deposit
("refresh-deposit-refreshed-1a", is->exchange,
"refresh-reveal-1-idempotency", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":42}",
fakebank_url),
"{\"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", is->exchange,
"refresh-reveal-1", 4,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":43}",
fakebank_url),
"{\"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", is->exchange, "EUR:4",
"refresh-withdraw-coin-1", MHD_HTTP_FORBIDDEN),
/* FIXME: also test with coin that was already melted
* (signature differs from coin that was deposited...) */
/****** End of refresh testing ******/
/* **** Test tracking API ***** */
/**
* 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", is->exchange,
"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", is->exchange,
"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", is->exchange,
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! 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", "https://exchange.com/",
"EUR:4.98", 2, 42),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-99c1", "https://exchange.com/",
"EUR:0.98", 2, 42),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-99c2", "https://exchange.com/",
"EUR:0.98", 2, 42),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-99c", "https://exchange.com/",
"EUR:0.08", 2, 43),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-aai-1", "https://exchange.com/",
"EUR:5.01", 42, 2),
/**
* NOTE: the old test-suite had this "check bank transfer"
* command with debit account == 424.
*/
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-aai-2", "https://exchange.com/",
"EUR:5.01", 42, 2),
TALER_TESTING_cmd_check_bank_empty ("check_bank_empty"),
TALER_TESTING_cmd_track_transaction
("deposit-wtid-ok", is->exchange,
"deposit-simple", 0, MHD_HTTP_OK, "check_bank_transfer-499c"),
TALER_TESTING_cmd_track_transfer
("wire-deposit-success-bank", is->exchange,
"check_bank_transfer-99c1", 0, MHD_HTTP_OK, "EUR:0.98",
"EUR:0.01"),
TALER_TESTING_cmd_track_transfer
("wire-deposits-success-wtid", is->exchange,
"deposit-wtid-ok", 0, MHD_HTTP_OK, "EUR:4.98",
"EUR:0.01"),
/* **** End of test tracking API ***** */
/* **** test /refund API ***** */
/**
* 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",
is->exchange,
"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", is->exchange, "withdraw-coin-r1", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\", \"account_number\":42}",
fakebank_url),
"{\"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_transfer
("check_bank_transfer-pre-refund", "https://exchange.com/",
"EUR:5.01", 42, 2),
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"),
/**
* 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", is->exchange, "withdraw-coin-r1", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\", \"account_number\":42}",
fakebank_url),
"{\"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", "https://exchange.com/",
"EUR:4.97", 2, 42),
/**
* 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"),
CMD_EXEC_WIREWATCH ("wirewatch-rb"),
TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-rb",
is->exchange,
"create-reserve-rb",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-aai-3b", "https://exchange.com/",
"EUR:5.01", 42, 2),
TALER_TESTING_cmd_deposit
("deposit-refund-1b", is->exchange, "withdraw-coin-rb", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\", \"account_number\":42}",
fakebank_url),
"{\"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"),
/* ************** End of refund API testing ************* */
/* ************** Test /payback API ************* */
/**
* Fill reserve with EUR:5.01, as withdraw fee is 1 ct per
* config.
*/
CMD_TRANSFER_TO_EXCHANGE ("payback-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 ("payback-withdraw-coin-1",
is->exchange,
"payback-create-reserve-1",
"EUR:5",
MHD_HTTP_OK),
TALER_TESTING_cmd_revoke ("revoke-1", MHD_HTTP_OK,
"payback-withdraw-coin-1",
CONFIG_FILE),
TALER_TESTING_cmd_payback ("payback-1", MHD_HTTP_OK,
"payback-withdraw-coin-1", "EUR:5"),
/* Check the money is back with the reserve */
TALER_TESTING_cmd_status ("payback-reserve-status-1",
is->exchange,
"payback-create-reserve-1",
"EUR:5.0",
MHD_HTTP_OK),
/**
* 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 ("payback-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 ("payback-withdraw-coin-2a",
is->exchange,
"payback-create-reserve-2",
"EUR:1",
MHD_HTTP_OK),
/* Withdraw a 1 EUR coin, at fee of 1 ct */
TALER_TESTING_cmd_withdraw_amount ("payback-withdraw-coin-2b",
is->exchange,
"payback-create-reserve-2",
"EUR:1",
MHD_HTTP_OK),
TALER_TESTING_cmd_deposit
("payback-deposit-partial", is->exchange,
"payback-withdraw-coin-2a", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":42}",
fakebank_url),
"{\"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,
"payback-withdraw-coin-2a",
CONFIG_FILE),
TALER_TESTING_cmd_payback ("payback-2", MHD_HTTP_OK,
"payback-withdraw-coin-2a",
"EUR:0.5"),
TALER_TESTING_cmd_payback ("payback-2b", MHD_HTTP_FORBIDDEN,
"payback-withdraw-coin-2a",
"EUR:0.5"),
TALER_TESTING_cmd_deposit
("payback-deposit-revoked", is->exchange,
"payback-withdraw-coin-2b", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":42}",
fakebank_url),
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:1", MHD_HTTP_NOT_FOUND),
/* Test deposit fails after payback, with proof in payback */
/* FIXME: #3887: right now, the exchange will never return the
* coin's transaction history with payback data, as we get a
* 404 on the DK! */
TALER_TESTING_cmd_deposit
("payback-deposit-partial-after-payback", is->exchange,
"payback-withdraw-coin-2a", 0,
TALER_TESTING_make_wire_details
("{ \"type\":\"test\",\"account_number\":42}",
fakebank_url),
"{\"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 ("payback-create-reserve-3",
"EUR:1.01"),
CMD_EXEC_WIREWATCH ("wirewatch-6"),
TALER_TESTING_cmd_withdraw_amount
("payback-withdraw-coin-3-revoked",
is->exchange,
"payback-create-reserve-3",
"EUR:1",
MHD_HTTP_NOT_FOUND),
/* check that we are empty before the rejection test */
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-pr1", "https://exchange.com/",
"EUR:5.01", 42, 2),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-pr2", "https://exchange.com/",
"EUR:2.02", 42, 2),
TALER_TESTING_cmd_check_bank_transfer
("check_bank_transfer-pr3", "https://exchange.com/",
"EUR:1.01", 42, 2),
TALER_TESTING_cmd_check_bank_empty ("check-empty-again"),
/* Test rejection of bogus wire transfers */
CMD_TRANSFER_TO_EXCHANGE_SUBJECT ("bogus-subject",
"EUR:1.01",
"not a reserve public key"),
CMD_EXEC_WIREWATCH ("wirewatch-7"),
TALER_TESTING_cmd_check_bank_empty ("check-empty-from-reject"),
/* ************** End of /payback API ************* */
/**
* End the suite. Fixme: better to have a label for this
* too, as it shows a "(null)" token on logs.
*/
TALER_TESTING_cmd_end () TALER_TESTING_cmd_end ()
}; };
@ -105,7 +740,6 @@ run (void *cls,
fakebank_url); fakebank_url);
} }
int int
main (int argc, main (int argc,
char * const *argv) char * const *argv)
@ -116,9 +750,15 @@ main (int argc,
GNUNET_log_setup ("test-exchange-api-new", GNUNET_log_setup ("test-exchange-api-new",
"INFO", "INFO",
NULL); NULL);
if (NULL == (fakebank_url = TALER_TESTING_prepare_fakebank (CONFIG_FILE))) if (NULL == (fakebank_url
/* Check fakebank port is available and config cares
* about bank url. */
= TALER_TESTING_prepare_fakebank (CONFIG_FILE)))
return 77; return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE); 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)) switch (TALER_TESTING_prepare_exchange (CONFIG_FILE))
{ {
case GNUNET_SYSERR: case GNUNET_SYSERR:
@ -128,10 +768,15 @@ main (int argc,
return 77; return 77;
case GNUNET_OK: case GNUNET_OK:
if (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, TALER_TESTING_setup_with_exchange (&run,
NULL, NULL,
CONFIG_FILE)) CONFIG_FILE))
return 1; return 1;
break;
default: default:
GNUNET_break (0); GNUNET_break (0);
return 1; return 1;

View File

@ -0,0 +1,268 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
struct BankCheckState
{
/**
* Exchange base URL (Fixme: why?)
*/
const char *exchange_base_url;
/**
* Expected transferred amount.
*/
const char *amount;
/**
* Expected account number that gave money
*/
unsigned int debit_account;
/**
* Expected account number that received money
*/
unsigned int credit_account;
/**
* Wire transfer subject (set by fakebank-lib).
*/
char *subject;
/**
* Binary form of the transfer subject. Some commands expect
* it - via appropriate traits - to be in binary form.
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
void
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;
if (GNUNET_OK !=
TALER_string_to_amount (bcs->amount,
&amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %u\n",
bcs->amount,
is->ip);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_FAKEBANK_check (is->fakebank,
&amount,
bcs->debit_account,
bcs->credit_account,
bcs->exchange_base_url,
&bcs->subject))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
TALER_TESTING_interpreter_next (is);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
void
check_bank_transfer_cleanup
(void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct BankCheckState *bcs = cls;
GNUNET_free_non_null (bcs->subject);
GNUNET_free (bcs);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
check_bank_transfer_traits (void *cls,
void **ret,
const char *trait,
unsigned int index)
{
struct BankCheckState *bcs = cls;
GNUNET_assert (GNUNET_OK ==
GNUNET_STRINGS_string_to_data
(bcs->subject,
strlen (bcs->subject),
&bcs->wtid,
sizeof (struct TALER_WireTransferIdentifierRawP)));
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_transfer_subject (0, bcs->subject),
TALER_TESTING_make_trait_wtid (0, &bcs->wtid),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
}
/**
* Command to check whether a particular wire transfer has been
* made or not.
*
* @param label the command label
* @param exchange_base_url base url of the exchange (Fixme: why?)
* @param amount the amount expected to be transferred
* @param debit_account the account that gave money
* @param credit_account 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,
unsigned int debit_account,
unsigned int credit_account)
{
struct BankCheckState *bcs;
struct TALER_TESTING_Command cmd;
bcs = GNUNET_new (struct BankCheckState);
bcs->exchange_base_url = exchange_base_url;
bcs->amount = amount;
bcs->debit_account = debit_account;
bcs->credit_account = credit_account;
cmd.label = label;
cmd.cls = bcs;
cmd.run = &check_bank_transfer_run;
cmd.cleanup = &check_bank_transfer_cleanup;
// traits?
cmd.traits = &check_bank_transfer_traits;
return cmd;
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
void
check_bank_empty_cleanup
(void *cls,
const struct TALER_TESTING_Command *cmd)
{
return;
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
void
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);
}
/**
* Check bank's balance is zero.
*
* @param credit_account the account that received money
*
* @return the command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_check_bank_empty (const char *label)
{
struct TALER_TESTING_Command cmd;
cmd.label = label;
cmd.run = &check_bank_empty_run;
cmd.cleanup = &check_bank_empty_cleanup;
return cmd;
}

View File

@ -0,0 +1,153 @@
/*
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 exchange-lib/testing_api_cmd_check_keys.c
* @brief Implementation of "check keys" 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"
struct CheckKeysState
{
/**
* FIXME
*/
unsigned int generation;
/**
* FIXME
*/
unsigned int num_denom_keys;
/**
* Connection to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
};
/**
* Run the command.
*
* @param cls closure, typically a #struct SignalState.
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
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', key generation: %d\n",
cmd->label, is->key_generation);
if (is->key_generation < cks->generation)
{
/* Go back to waiting for /keys signal! */
is->working = GNUNET_NO;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Triggering /keys dl, cmd `%s'\n",
cmd->label);
GNUNET_break (0 == TALER_EXCHANGE_check_keys_current
(cks->exchange, GNUNET_YES).abs_value_us);
return;
}
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_TESTING_interpreter_fail (is);
return;
}
/* /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);
fprintf (stderr, "Got %u keys in step %s\n",
is->keys->num_denom_keys, cmd->label);
TALER_TESTING_interpreter_fail (is);
return;
}
TALER_TESTING_interpreter_next (is);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct SignalState.
* @param cmd the command which is being cleaned up.
*/
void
check_keys_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct CheckKeysState *cks = cls;
GNUNET_free (cks);
}
/**
* Make a "check keys" command.
*
* @param label command label
* @param generation FIXME
* @param num_denom_keys FIXME
*
* @return the command.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_check_keys
(const char *label,
unsigned int generation,
unsigned int num_denom_keys,
struct TALER_EXCHANGE_Handle *exchange)
{
struct CheckKeysState *cks;
struct TALER_TESTING_Command cmd;
cks = GNUNET_new (struct CheckKeysState);
cks->generation = generation;
cks->num_denom_keys = num_denom_keys;
cks->exchange = exchange;
cmd.cls = cks;
cmd.label = label;
cmd.run = &check_keys_run;
cmd.cleanup = &check_keys_cleanup;
return cmd;
}

View File

@ -0,0 +1,448 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
struct DepositState
{
/**
* Amount to deposit.
*/
const char *amount;
/**
* Reference to any command that is able to provide a coin.
*/
const char *coin_reference;
/**
* If this @e coin_ref refers to an operation that generated
* an array of coins, this value determines which coin to pick.
*/
unsigned int coin_index;
/**
* JSON string describing the merchant's "wire details".
*/
char *wire_details;
/**
* JSON string describing what a proposal is about.
*/
const char *contract_terms;
/**
* Relative time (to add to 'now') to compute the refund
* deadline. Zero for no refunds.
*/
struct GNUNET_TIME_Relative refund_deadline;
/**
* Set (by the interpreter) to a fresh private key.
*/
struct TALER_MerchantPrivateKeyP merchant_priv;
/**
* Deposit handle while operation is running.
*/
struct TALER_EXCHANGE_DepositHandle *dh;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Exchange connection.
*/
struct TALER_EXCHANGE_Handle *exchange;
};
/**
* Function called with the result of a /deposit operation.
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for
* successful deposit; 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 exchange_pub public key the exchange used for signing
* @param obj the received JSON reply, should be kept as proof
* (and, in case of errors, be forwarded to the customer)
*/
static void
deposit_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const struct TALER_ExchangePublicKeyP *exchange_pub,
const json_t *obj)
{
struct DepositState *ds = cls;
ds->dh = NULL;
if (ds->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
ds->is->commands[ds->is->ip].label);
json_dumpf (obj, stderr, 0);
TALER_TESTING_interpreter_fail (ds->is);
return;
}
TALER_TESTING_interpreter_next (ds->is);
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param i the interpreter state.
*/
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;
struct TALER_TESTING_Command *this_cmd;
struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
struct TALER_DenominationSignature *denom_pub_sig;
struct TALER_CoinSpendSignatureP coin_sig;
struct GNUNET_TIME_Absolute refund_deadline;
struct GNUNET_TIME_Absolute wire_deadline;
struct GNUNET_TIME_Absolute timestamp;
struct GNUNET_CRYPTO_EddsaPrivateKey *merchant_priv;
struct TALER_MerchantPublicKeyP merchant_pub;
struct GNUNET_HashCode h_contract_terms;
json_t *contract_terms;
json_t *wire;
struct TALER_Amount amount;
ds->is = is;
this_cmd = &is->commands[is->ip];
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;
}
/* Fixme: do prefer "interpreter fail" over assertions,
* as the former takes care of shutting down processes too */
GNUNET_assert (NULL != coin_cmd);
GNUNET_assert (GNUNET_OK
== TALER_TESTING_get_trait_coin_priv (coin_cmd,
ds->coin_index,
&coin_priv));
GNUNET_assert (GNUNET_OK
== TALER_TESTING_get_trait_denom_pub (coin_cmd,
ds->coin_index,
&denom_pub));
GNUNET_assert (GNUNET_OK
== TALER_TESTING_get_trait_denom_sig (coin_cmd,
ds->coin_index,
&denom_pub_sig));
if (GNUNET_OK !=
TALER_string_to_amount (ds->amount,
&amount))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at '%u/%s'\n",
ds->amount, is->ip, this_cmd->label);
TALER_TESTING_interpreter_fail (is);
return;
}
contract_terms = json_loads (ds->contract_terms,
JSON_REJECT_DUPLICATES,
NULL);
if (NULL == contract_terms)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse proposal data `%s' at %u/%s\n",
ds->contract_terms, is->ip, this_cmd->label);
TALER_TESTING_interpreter_fail (is);
return;
}
GNUNET_assert (GNUNET_OK ==
TALER_JSON_hash (contract_terms,
&h_contract_terms));
json_decref (contract_terms);
wire = json_loads (ds->wire_details,
JSON_REJECT_DUPLICATES,
NULL);
if (NULL == wire)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse wire details `%s' at %u/%s\n",
ds->wire_details,
is->ip,
this_cmd->label);
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.rel_value_us)
{
refund_deadline = GNUNET_TIME_relative_to_absolute
(ds->refund_deadline);
wire_deadline = GNUNET_TIME_relative_to_absolute
(GNUNET_TIME_relative_multiply
(ds->refund_deadline, 2));
}
else
{
refund_deadline = GNUNET_TIME_UNIT_ZERO_ABS;
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);
timestamp = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&timestamp);
GNUNET_TIME_round_abs (&refund_deadline);
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_hash
(wire, &dr.h_wire));
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dr.refund_deadline = GNUNET_TIME_absolute_hton
(refund_deadline);
TALER_amount_hton (&dr.amount_with_fee, &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
(ds->exchange,
&amount,
wire_deadline,
wire,
&h_contract_terms,
&coin_pub,
denom_pub_sig,
&denom_pub->key,
timestamp,
&merchant_pub,
refund_deadline,
&coin_sig,
&deposit_cb,
ds);
if (NULL == ds->dh)
{
GNUNET_break (0);
json_decref (wire);
TALER_TESTING_interpreter_fail (is);
return;
}
json_decref (wire);
return;
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
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;
}
GNUNET_free (ds->wire_details);
GNUNET_free (ds);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
deposit_traits (void *cls,
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. */
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[] = {
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_peer_key
(0, &ds->merchant_priv.eddsa_priv),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
}
/**
* Create a deposit command.
*
* @param label command label
* @param exchange exchange connection
* @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 wire_details bank details of the merchant performing the
* deposit
* @param contract_terms contract terms to be signed over by the
* coin
* @param refund_deadline refund deadline, zero means 'no refunds'
* @param amount how much is going to be deposited
* @param expected_response_code which HTTP status code we expect
* in the response
*
* @return the deposit command to be run by the interpreter
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_deposit
(const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *coin_reference,
unsigned int coin_index,
char *wire_details,
const char *contract_terms,
struct GNUNET_TIME_Relative refund_deadline,
const char *amount,
unsigned int expected_response_code)
{
struct TALER_TESTING_Command cmd;
struct DepositState *ds;
ds = GNUNET_new (struct DepositState);
ds->exchange = exchange;
ds->coin_reference = coin_reference;
ds->coin_index = coin_index;
ds->wire_details = wire_details;
ds->contract_terms = contract_terms;
ds->refund_deadline = refund_deadline;
ds->amount = amount;
ds->expected_response_code = expected_response_code;
cmd.cls = ds;
cmd.label = label;
cmd.run = &deposit_run;
cmd.cleanup = &deposit_cleanup;
cmd.traits = &deposit_traits;
return cmd;
}

View File

@ -0,0 +1,162 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not,
see <http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
struct AggregatorState
{
/**
* Process for the aggregator.
*/
struct GNUNET_OS_Process *aggregator_proc;
/**
* Which configuration file should we pass to the process?
*/
const char *config_filename;
};
/**
* Runs the command. Note that upon return, the interpreter
* will not automatically run the next command, as the command
* may continue asynchronously in other scheduler tasks. Thus,
* the command must ensure to eventually call
* #TALER_TESTING_interpreter_next() or
* #TALER_TESTING_interpreter_fail().
*
* @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);
}
/**
* Clean up after the command. Run during forced termination
* (CTRL-C) or test failure or test success.
*
* @param cls closure
*/
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);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
aggregator_traits (void *cls,
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);
}
/**
* Execute taler-exchange-wirewatch process.
*
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_exec_aggregator (const char *label,
const char *config_filename)
{
struct TALER_TESTING_Command cmd;
struct AggregatorState *as;
as = GNUNET_new (struct AggregatorState);
as->config_filename = config_filename;
cmd.cls = as;
cmd.label = label;
cmd.run = &aggregator_run;
cmd.cleanup = &aggregator_cleanup;
cmd.traits = &aggregator_traits;
return cmd;
}
/* end of testing_api_cmd_exec_aggregator.c */

View File

@ -0,0 +1,221 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not,
see <http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
struct AuditorSignState
{
/**
* Process for the "auditor sign" command.
*/
struct GNUNET_OS_Process *auditor_sign_proc;
/**
* Which configuration file should we pass to the process?
*/
const char *config_filename;
};
/**
* Runs the command. Note that upon return, the interpreter
* will not automatically run the next command, as the command
* may continue asynchronously in other scheduler tasks. Thus,
* the command must ensure to eventually call
* #TALER_TESTING_interpreter_next() or
* #TALER_TESTING_interpreter_fail().
*
* @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 *signed_keys_out;
char *exchange_master_pub;
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_string (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;
}
GNUNET_asprintf (&signed_keys_out,
"%s/.local/share/taler/auditors/auditor.out",
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", signed_keys_out,
NULL);
if (NULL == ass->auditor_sign_proc)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
TALER_TESTING_wait_for_sigchld (is);
}
/**
* Clean up after the command. Run during forced termination
* (CTRL-C) or test failure or test success.
*
* @param cls closure
*/
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 (ass);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
auditor_sign_traits (void *cls,
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);
}
/**
* Execute taler-auditor-sign process.
*
* @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 TALER_TESTING_Command cmd;
struct AuditorSignState *ass;
ass = GNUNET_new (struct AuditorSignState);
ass->config_filename = config_filename;
cmd.cls = ass;
cmd.label = label;
cmd.run = &auditor_sign_run;
cmd.cleanup = &auditor_sign_cleanup;
cmd.traits = &auditor_sign_traits;
return cmd;
}
/* end of testing_api_cmd_exec_auditor-sign.c */

View File

@ -0,0 +1,168 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not,
see <http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
struct KeyupState
{
/**
* Process for the "keyup" command.
*/
struct GNUNET_OS_Process *keyup_proc;
/**
* Which configuration file should we pass to the process?
*/
const char *config_filename;
};
/**
* Runs the command. Note that upon return, the interpreter
* will not automatically run the next command, as the command
* may continue asynchronously in other scheduler tasks. Thus,
* the command must ensure to eventually call
* #TALER_TESTING_interpreter_next() or
* #TALER_TESTING_interpreter_fail().
*
* @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;
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;
}
TALER_TESTING_wait_for_sigchld (is);
}
/**
* Clean up after the command. Run during forced termination
* (CTRL-C) or test failure or test success.
*
* @param cls closure
*/
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);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
keyup_traits (void *cls,
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);
}
/**
* Execute taler-exchange-keyup process.
*
* @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 TALER_TESTING_Command cmd;
struct KeyupState *ks;
ks = GNUNET_new (struct KeyupState);
ks->config_filename = config_filename;
cmd.cls = ks;
cmd.label = label;
cmd.run = &keyup_run;
cmd.cleanup = &keyup_cleanup;
cmd.traits = &keyup_traits;
return cmd;
}
/* end of testing_api_cmd_exec_keyup.c */

View File

@ -122,11 +122,11 @@ static int
wirewatch_traits (void *cls, wirewatch_traits (void *cls,
void **ret, void **ret,
const char *trait, const char *trait,
const char *selector) unsigned int index)
{ {
struct WirewatchState *ws = cls; struct WirewatchState *ws = cls;
struct TALER_TESTING_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_process (NULL, TALER_TESTING_make_trait_process (0,
&ws->wirewatch_proc), &ws->wirewatch_proc),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };
@ -134,7 +134,7 @@ wirewatch_traits (void *cls,
return TALER_TESTING_get_trait (traits, return TALER_TESTING_get_trait (traits,
ret, ret,
trait, trait,
selector); index);
} }

View File

@ -2,18 +2,21 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it
terms of the GNU General Public License as published by the Free Software under the terms of the GNU General Public License as published by
Foundation; either version 3, or (at your option) any later version. the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file exchange-lib/testing_api_cmd_fakebank_transfer.c * @file exchange-lib/testing_api_cmd_fakebank_transfer.c
* @brief implementation of a fakebank wire transfer command * @brief implementation of a fakebank wire transfer command
@ -104,14 +107,17 @@ struct FakebankTransferState
/** /**
* Function called upon completion of our /admin/add/incoming request. * Function called upon completion of our /admin/add/incoming
* request.
* *
* @param cls closure with the interpreter state * @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
* 0 if the exchange's reply is bogus (fails to follow the protocol) * 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 ec taler-specific error code, #TALER_EC_NONE on success
* @param serial_id unique ID of the wire transfer * @param serial_id unique ID of the wire transfer
* @param full_response full response from the exchange (for logging, in case of errors) * @param full_response full response from the exchange (for
* logging, in case of errors)
*/ */
static void static void
add_incoming_cb (void *cls, add_incoming_cb (void *cls,
@ -167,8 +173,8 @@ fakebank_transfer_run (void *cls,
const struct TALER_TESTING_Command *ref; const struct TALER_TESTING_Command *ref;
struct TALER_ReservePrivateKeyP *reserve_priv; struct TALER_ReservePrivateKeyP *reserve_priv;
ref = TALER_TESTING_interpreter_lookup_command (is, ref = TALER_TESTING_interpreter_lookup_command
fts->reserve_reference); (is, fts->reserve_reference);
if (NULL == ref) if (NULL == ref)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -177,7 +183,7 @@ fakebank_transfer_run (void *cls,
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_priv (ref, TALER_TESTING_get_trait_reserve_priv (ref,
NULL, 0,
&reserve_priv)) &reserve_priv))
{ {
GNUNET_break (0); GNUNET_break (0);
@ -193,27 +199,27 @@ fakebank_transfer_run (void *cls,
fts->reserve_priv.eddsa_priv = *priv; fts->reserve_priv.eddsa_priv = *priv;
GNUNET_free (priv); GNUNET_free (priv);
} }
GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv, GNUNET_CRYPTO_eddsa_key_get_public
&reserve_pub.eddsa_pub); (&fts->reserve_priv.eddsa_priv, &reserve_pub.eddsa_pub);
subject = GNUNET_STRINGS_data_to_string_alloc (&reserve_pub, subject = GNUNET_STRINGS_data_to_string_alloc
sizeof (reserve_pub)); (&reserve_pub, sizeof (reserve_pub));
} }
auth.method = TALER_BANK_AUTH_BASIC; auth.method = TALER_BANK_AUTH_BASIC;
auth.details.basic.username = (char *) fts->auth_username; auth.details.basic.username = (char *) fts->auth_username;
auth.details.basic.password = (char *) fts->auth_password; auth.details.basic.password = (char *) fts->auth_password;
fts->is = is; fts->is = is;
fts->aih fts->aih = TALER_BANK_admin_add_incoming
= TALER_BANK_admin_add_incoming (TALER_TESTING_interpreter_get_context (is), (TALER_TESTING_interpreter_get_context (is),
fts->bank_url, fts->bank_url,
&auth, &auth,
"https://exchange.com/", /* exchange URL: FIXME */ "https://exchange.com/", /* exchange URL: FIXME */
subject, subject,
&fts->amount, &fts->amount,
fts->debit_account_no, fts->debit_account_no,
fts->credit_account_no, fts->credit_account_no,
&add_incoming_cb, &add_incoming_cb,
fts); fts);
GNUNET_free (subject); GNUNET_free (subject);
if (NULL == fts->aih) if (NULL == fts->aih)
{ {
@ -263,11 +269,11 @@ static int
fakebank_transfer_traits (void *cls, fakebank_transfer_traits (void *cls,
void **ret, void **ret,
const char *trait, const char *trait,
const char *selector) unsigned int index)
{ {
struct FakebankTransferState *fts = cls; struct FakebankTransferState *fts = cls;
struct TALER_TESTING_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_reserve_priv (NULL, TALER_TESTING_make_trait_reserve_priv (0,
&fts->reserve_priv), &fts->reserve_priv),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };
@ -275,12 +281,13 @@ fakebank_transfer_traits (void *cls,
if (NULL != fts->subject) if (NULL != fts->subject)
{ {
GNUNET_break (0); GNUNET_break (0);
return GNUNET_SYSERR; /* we do NOT create a reserve private key */ /* we do NOT create a reserve private key */
return GNUNET_SYSERR;
} }
return TALER_TESTING_get_trait (traits, return TALER_TESTING_get_trait (traits,
ret, ret,
trait, trait,
selector); index);
} }
@ -330,14 +337,15 @@ TALER_TESTING_cmd_fakebank_transfer (const char *label,
* *
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label, TALER_TESTING_cmd_fakebank_transfer_with_subject
const char *amount, (const char *label,
const char *bank_url, const char *amount,
uint64_t debit_account_no, const char *bank_url,
uint64_t credit_account_no, uint64_t debit_account_no,
const char *auth_username, uint64_t credit_account_no,
const char *auth_password, const char *auth_username,
const char *subject) const char *auth_password,
const char *subject)
{ {
struct TALER_TESTING_Command cmd; struct TALER_TESTING_Command cmd;
struct FakebankTransferState *fts; struct FakebankTransferState *fts;
@ -373,14 +381,15 @@ TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label,
* *
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label, TALER_TESTING_cmd_fakebank_transfer_with_ref
const char *amount, (const char *label,
const char *bank_url, const char *amount,
uint64_t debit_account_no, const char *bank_url,
uint64_t credit_account_no, uint64_t debit_account_no,
const char *auth_username, uint64_t credit_account_no,
const char *auth_password, const char *auth_username,
const char *ref) const char *auth_password,
const char *ref)
{ {
struct TALER_TESTING_Command cmd; struct TALER_TESTING_Command cmd;
struct FakebankTransferState *fts; struct FakebankTransferState *fts;

View File

@ -0,0 +1,491 @@
/*
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 exchange/testing_api_cmd_payback.c
* @brief Implement the /revoke and /payback 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"
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 filename.
*/
const char *config_filename;
/**
* Encoding of the denomination (to revoke) public key hash.
*/
char *dhks;
};
struct PaybackState
{
/**
* 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;
/**
* Connection to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Handle to the ongoing operation.
*/
struct TALER_EXCHANGE_PaybackHandle *ph;
};
/**
* Check the result of the payback request.
*
* @param cls closure
* @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 amount amount the exchange will wire back for this coin
* @param timestamp what time did the exchange receive the
* /payback request
* @param reserve_pub public key of the reserve receiving the
* payback
* @param full_response full response from the exchange (for
* logging, in case of errors)
*/
static void
payback_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 json_t *full_response)
{
struct PaybackState *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;
struct TALER_ReservePrivateKeyP *reserve_priv;
struct TALER_ReservePublicKeyP rp;
struct TALER_Amount expected_amount;
ps->ph = NULL;
if (ps->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
cmd->label);
json_dumpf (full_response, stderr, 0);
fprintf (stderr, "\n");
TALER_TESTING_interpreter_fail (is);
return;
}
reserve_cmd = TALER_TESTING_interpreter_lookup_command
(is, ps->coin_reference);
if (NULL == reserve_cmd)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv
(reserve_cmd, 0, &reserve_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&rp.eddsa_pub);
switch (http_status)
{
case MHD_HTTP_OK:
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;
}
if (0 != memcmp (reserve_pub, &rp,
sizeof (struct TALER_ReservePublicKeyP)))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unmanaged HTTP status code.\n");
break;
}
TALER_TESTING_interpreter_next (is);
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
void
payback_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct PaybackState *ps = cls;
const struct TALER_TESTING_Command *coin_cmd;
struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_DenominationBlindingKeyP *blinding_key;
struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
struct TALER_DenominationSignature *coin_sig;
struct TALER_PlanchetSecretsP planchet;
ps->is = is;
ps->exchange = is->exchange;
coin_cmd = TALER_TESTING_interpreter_lookup_command
(is, ps->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, 0, &coin_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_blinding_key
(coin_cmd, 0, &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, 0, &denom_pub))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig
(coin_cmd, 0, &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_payback (ps->exchange,
denom_pub,
coin_sig,
&planchet,
payback_cb,
ps);
GNUNET_assert (NULL != ps->ph);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
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 (rs->dhks);
GNUNET_free (rs);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
void
payback_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct PaybackState *ps = cls;
if (NULL != ps->ph)
{
TALER_EXCHANGE_payback_cancel (ps->ph);
ps->ph = NULL;
}
GNUNET_free (ps);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
revoke_traits (void *cls,
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 command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
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;
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 /payback command.
*
* @param label the command label
* @param expected_response_code expected HTTP status code
* @param coin_reference reference to any command which
* offers a reserve private key
* @param amount denomination to pay back.
*
* @return a /revoke command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_payback (const char *label,
unsigned int expected_response_code,
const char *coin_reference,
const char *amount)
{
struct PaybackState *ps;
struct TALER_TESTING_Command cmd;
ps = GNUNET_new (struct PaybackState);
ps->expected_response_code = expected_response_code;
ps->coin_reference = coin_reference;
ps->amount = amount;
cmd.cls = ps;
cmd.label = label;
cmd.run = &payback_run;
cmd.cleanup = &payback_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 any command which offers
* a coin trait
* @param config_filename configuration file name.
*
* @return a /revoke 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;
struct TALER_TESTING_Command cmd;
rs = GNUNET_new (struct RevokeState);
rs->expected_response_code = expected_response_code;
rs->coin_reference = coin_reference;
rs->config_filename = config_filename;
cmd.cls = rs;
cmd.label = label;
cmd.run = &revoke_run;
cmd.cleanup = &revoke_cleanup;
cmd.traits = &revoke_traits;
return cmd;
}

View File

@ -0,0 +1,993 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
/**
* Structure specifying details about a coin to be melted.
* Used in a NULL-terminated array as part of command
* specification.
*/
struct MeltDetails
{
/**
* Amount to melt (including fee).
*/
const char *amount;
/**
* Reference to reserve_withdraw operations for coin to
* be used for the /refresh/melt operation.
*/
const char *coin_reference;
};
/**
* State for a "refresh melt" operation.
*/
struct RefreshMeltState
{
/**
* Fixme: figure out this data purpose.
*/
const char *amount;
/**
* Information about coins to be melted.
*/
struct MeltDetails melted_coin;
/**
* Data used in the refresh operation.
*/
char *refresh_data;
/**
* Number of bytes in @e refresh_data.
*/
size_t refresh_data_length;
/**
* Reference to a previous melt command.
*/
const char *melt_reference;
/**
* Melt handle while operation is running.
*/
struct TALER_EXCHANGE_RefreshMeltHandle *rmh;
/**
* Connection to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
/**
* Array of the public keys corresponding to
* the @e fresh_amounts, set by the interpreter.
*/
struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
/**
* Set by the interpreter (upon completion) to the
* noreveal index selected by the exchange.
*/
uint16_t noreveal_index;
};
/**
* State for a "refresh reveal" operation.
*/
struct RefreshRevealState
{
/**
* Link to a "refresh melt" command.
*/
const char *melt_reference;
/**
* Reveal handle while operation is running.
*/
struct TALER_EXCHANGE_RefreshRevealHandle *rrh;
/**
* Number of fresh coins withdrawn, set by the interpreter.
* Length of the @e fresh_coins array.
*/
unsigned int num_fresh_coins;
/**
* Information about coins withdrawn, set by the interpreter.
*/
struct FreshCoin *fresh_coins;
/**
* Connection to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
};
/**
* State for a "refresh link" operation.
*/
struct RefreshLinkState
{
/**
* Link to a "refresh reveal" command.
*/
const char *reveal_reference;
/**
* Link handle while operation is running.
*/
struct TALER_EXCHANGE_RefreshLinkHandle *rlh;
/**
* Connection to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
};
/**
* Function called with the result of the /refresh/reveal operation.
*
* @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 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 full response from the exchange (for
* logging, in case of errors)
*/
static void
reveal_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 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)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
rrs->is->commands[rrs->is->ip].label);
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 FreshCoin);
struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
unsigned int i;
if (GNUNET_OK != TALER_TESTING_get_trait_denom_pub
(melt_cmd, 0, &fresh_pks))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
for (i=0; i<num_coins; i++)
{
struct FreshCoin *fc = &rrs->fresh_coins[i];
fc->pk = &fresh_pks[i];
fc->coin_priv = coin_privs[i];
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, a /wire one.
* @param is the interpreter state.
*/
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
(rrs->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;
}
}
/**
* Cleanup the state.
*
* @param cls closure.
* @param cmd the command which is being cleaned up.
*/
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;
}
{ /* Not sure why block-ing this */
unsigned int j;
for (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;
}
/**
* Function called with the result of a /refresh/link operation.
*
* @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 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 full response from the exchange (for
* logging, in case of errors)
*/
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;
unsigned int *num_fresh_coins;
rls->rlh = NULL;
if (rls->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
link_cmd->label);
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\n",
num_coins, *num_fresh_coins);
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 == memcmp
(&coin_privs[i], &coin_privs[j],
sizeof (struct TALER_CoinSpendPrivateKeyP)))
GNUNET_break (0);
/* Note: coins might be legitimately permutated in here... */
found = 0;
/* Will point to the pointer inside the cmd state. */
struct FreshCoin *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 == memcmp
(&coin_privs[i], &fc[i].coin_priv,
sizeof (struct TALER_CoinSpendPrivateKeyP))) &&
(0 == GNUNET_CRYPTO_rsa_signature_cmp
(fc[i].sig.rsa_signature,
sigs[i].rsa_signature)) &&
(0 == GNUNET_CRYPTO_rsa_public_key_cmp
(fc[i].pk->key.rsa_public_key,
pubs[i].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, a /wire one.
* @param i the interpreter state.
*/
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 */
{
const struct MeltDetails *md;
rms = melt_cmd->cls;
md = &rms->melted_coin;
coin_cmd = TALER_TESTING_interpreter_lookup_command
(rls->is, md->coin_reference);
if (NULL == coin_cmd)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rls->is);
return;
}
}
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
(rls->exchange, coin_priv, &link_cb, rls);
if (NULL == rls->rlh)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rls->is);
return;
}
}
/**
* Cleanup the state.
*
* @param cls closure
* @param cmd the command which is being cleaned up.
*/
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;
}
}
/**
* Function called with the result of the /refresh/melt operation.
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, never #MHD_HTTP_OK (200)
* as for successful intermediate response this callback is
* skipped. 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 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 full response from the exchange (for
* logging, in case of errors)
*/
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)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
rms->is->commands[rms->is->ip].label);
json_dumpf (full_response, stderr, 0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
rms->noreveal_index = noreveal_index;
TALER_TESTING_interpreter_next (rms->is);
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param i the interpreter state.
*/
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 struct TALER_TESTING_Command *coin_command;
const char *melt_fresh_amounts[] = {
/* with 0.01 withdraw fees (except for 1ct coins),
this totals up to exactly EUR:3.97, and with
the 0.03 refresh fee, to EUR:4.0 */
"EUR:1", "EUR:1", "EUR:1", "EUR:0.1", "EUR:0.1", "EUR:0.1",
"EUR:0.1", "EUR:0.1", "EUR:0.1", "EUR:0.1", "EUR:0.1",
"EUR:0.01", "EUR:0.01", "EUR:0.01", "EUR:0.01", "EUR:0.01",
"EUR:0.01", NULL};
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk;
rms->is = is;
rms->noreveal_index = UINT16_MAX;
for (num_fresh_coins=0;
NULL != melt_fresh_amounts[num_fresh_coins];
num_fresh_coins++) ;
rms->fresh_pks = GNUNET_new_array
(num_fresh_coins,
struct TALER_EXCHANGE_DenomPublicKey);
{
struct TALER_CoinSpendPrivateKeyP *melt_priv;
struct TALER_Amount melt_amount;
struct TALER_Amount fresh_amount;
struct TALER_DenominationSignature *melt_sig;
struct TALER_EXCHANGE_DenomPublicKey *melt_denom_pub;
unsigned int i;
const struct MeltDetails *md = &rms->melted_coin;
if (NULL == (coin_command
= TALER_TESTING_interpreter_lookup_command
(is, md->coin_reference)))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
(coin_command, 0, &melt_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
if (GNUNET_OK !=
TALER_string_to_amount (md->amount,
&melt_amount))
{
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at %u\n",
md->amount,
is->ip);
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;
}
for (i=0;i<num_fresh_coins;i++)
{
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 (rms->exchange), &fresh_amount);
if (NULL == fresh_pk)
{
GNUNET_break (0);
/* Subroutine logs specific error */
TALER_TESTING_interpreter_fail (rms->is);
return;
}
rms->fresh_pks[i] = *fresh_pk;
}
rms->refresh_data = TALER_EXCHANGE_refresh_prepare
(melt_priv, &melt_amount, melt_sig, melt_denom_pub,
GNUNET_YES, 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
(rms->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;
}
}
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct RefreshMeltState.
* @param cmd the command which is being cleaned up.
*/
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;
}
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;
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
refresh_melt_traits (void *cls,
void **ret,
const char *trait,
unsigned int index)
{
struct RefreshMeltState *rms = cls;
struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_denom_pub (0, rms->fresh_pks),
TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
}
/**
* Create a "refresh melt" command.
*
* @param label command label
* @param exchange connection to the exchange
* @param amount Fixme
* @param coin_reference reference to a command that will provide
* a coin to refresh
* @param expected_response_code expected HTTP code
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_melt
(const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *amount,
const char *coin_reference,
unsigned int expected_response_code)
{
struct RefreshMeltState *rms;
struct MeltDetails md;
struct TALER_TESTING_Command cmd;
md.coin_reference = coin_reference;
md.amount = amount;
rms = GNUNET_new (struct RefreshMeltState);
rms->amount = amount;
rms->melted_coin = md;
rms->expected_response_code = expected_response_code;
rms->exchange = exchange;
cmd.label = label;
cmd.cls = rms;
cmd.run = &refresh_melt_run;
cmd.cleanup = &refresh_melt_cleanup;
cmd.traits = &refresh_melt_traits;
return cmd;
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
refresh_reveal_traits (void *cls,
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 * 3) + 3
struct TALER_TESTING_Trait traits[NUM_TRAITS];
unsigned int i;
/* Making coin privs traits */
for (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 (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 (i=0; i<num_coins; i++)
traits[(num_coins * 2) + i]
= TALER_TESTING_make_trait_denom_sig
(i, &rrs->fresh_coins[i].sig);
/* number of fresh coins */
traits[(num_coins * 3)] = TALER_TESTING_make_trait_uint
(0, &rrs->num_fresh_coins);
/* whole array of fresh coins */
traits[(num_coins * 3) + 1]
= TALER_TESTING_make_trait_fresh_coins (0, rrs->fresh_coins),
/* end of traits */
traits[(num_coins * 3) + 2] = TALER_TESTING_trait_end ();
return TALER_TESTING_get_trait (traits,
ret,
trait,
index);
}
/**
* Create a "refresh reveal" command.
*
* @param label command label
* @param exchange connection to the exchange
* @param melt_reference reference to a "refresh melt" command
* @param expected_response_code expected HTTP response code
*
* @return the "refresh reveal" command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_refresh_reveal
(const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *melt_reference,
unsigned int expected_response_code)
{
struct RefreshRevealState *rrs;
struct TALER_TESTING_Command cmd;
rrs = GNUNET_new (struct RefreshRevealState);
rrs->melt_reference = melt_reference;
rrs->exchange = exchange;
rrs->expected_response_code = expected_response_code;
cmd.cls = rrs;
cmd.label = label;
cmd.run = &refresh_reveal_run;
cmd.cleanup = &refresh_reveal_cleanup;
cmd.traits = &refresh_reveal_traits;
return cmd;
}
/**
* Create a "refresh link" command.
*
* @param label command label
* @param exchange connection to the exchange
* @param melt_reference reference to a "refresh melt" command
* @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,
struct TALER_EXCHANGE_Handle *exchange,
const char *reveal_reference,
unsigned int expected_response_code)
{
struct RefreshLinkState *rrs;
struct TALER_TESTING_Command cmd;
rrs = GNUNET_new (struct RefreshLinkState);
rrs->reveal_reference = reveal_reference;
rrs->exchange = exchange;
rrs->expected_response_code = expected_response_code;
cmd.cls = rrs;
cmd.label = label;
cmd.run = &refresh_link_run;
cmd.cleanup = &refresh_link_cleanup;
return cmd;
}

View File

@ -0,0 +1,295 @@
/*
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 exchange/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"
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. Left un-initialized in the
* old test-suite. What's the best way to init it?
*/
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.
*
* @param cls closure
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for
* successful deposit; 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 exchange_pub public key the exchange used for signing @a
* obj
* @param obj the received JSON reply, should be kept as proof
* (and, in particular, be forwarded to the customer)
*/
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\n",
http_status,
refund_cmd->label);
json_dumpf (obj, stderr, 0);
TALER_TESTING_interpreter_fail (rs->is);
return;
}
switch (http_status)
{
case MHD_HTTP_OK:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Good /refund status code\n");
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unmanaged HTTP status code: %u, command: %s\n",
http_status, refund_cmd->label);
}
TALER_TESTING_interpreter_next (rs->is);
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param i the interpreter state.
*/
void
refund_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
struct RefundState *rs = cls;
struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_CoinSpendPublicKeyP coin;
const char *contract_terms;
struct GNUNET_HashCode h_contract_terms;
json_t *j_contract_terms;
struct TALER_Amount refund_fee;
struct TALER_Amount refund_amount;
const struct GNUNET_CRYPTO_EddsaPrivateKey *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;
}
j_contract_terms = json_loads
(contract_terms, JSON_REJECT_DUPLICATES, NULL);
/* Very unlikely to fail */
GNUNET_assert (NULL != j_contract_terms);
GNUNET_assert (GNUNET_OK == TALER_JSON_hash
(j_contract_terms, &h_contract_terms));
json_decref (j_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_peer_key
(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,
(const struct TALER_MerchantPrivateKeyP *) merchant_priv,
&refund_cb, rs);
GNUNET_assert (NULL != rs->rh);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
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 test 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.
*/
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;
struct TALER_TESTING_Command cmd;
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;
cmd.cls = rs;
cmd.label = label;
cmd.run = &refund_run;
cmd.cleanup = &refund_cleanup;
return cmd;
}

View File

@ -0,0 +1,112 @@
/*
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 exchange-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"
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, typically a #struct SignalState.
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
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.
*
* @param cls closure, typically a #struct SignalState.
* @param cmd the command which is being cleaned up.
*/
void
signal_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
struct SignalState *ss = cls;
GNUNET_free (ss);
}
/**
* Send a signal to a process.
*
* @param process handle to the process
* @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;
struct TALER_TESTING_Command cmd;
ss = GNUNET_new (struct SignalState);
ss->process = process;
ss->signal = signal;
cmd.cls = ss;
cmd.label = label;
cmd.run = &signal_run;
cmd.cleanup = &signal_cleanup;
return cmd;
}

View File

@ -0,0 +1,240 @@
/*
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 exchange/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"
struct StatusState
{
/**
* Label to the command which created the reserve to check,
* needed to resort the reserve key.
*/
const char *reserve_reference;
/**
* Handle to a /reserve/status operation.
*/
struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
/**
* Expected reserve balance.
*/
const char *expected_balance;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
/**
* Handle to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
/**
* Check exchange returned expected values.
*
* @param cls closure
* @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[in] json original response in JSON format (useful only
* for diagnostics)
* @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
*/
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\n",
http_status);
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\n");
TALER_TESTING_interpreter_fail (ss->is);
return;
}
/**
* Fixme: need a way to check if 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).
*/
TALER_TESTING_interpreter_next (ss->is);
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param i the interpreter state.
*/
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;
struct TALER_ReservePrivateKeyP *reserve_priv;
struct TALER_ReservePublicKeyP reserve_pub;
ss->is = is;
GNUNET_assert (NULL != ss->reserve_reference);
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_priv (create_reserve,
0,
&reserve_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
&reserve_pub.eddsa_pub);
ss->rsh
= TALER_EXCHANGE_reserve_status (ss->exchange,
&reserve_pub,
&reserve_status_cb,
ss);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
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 exchange the exchange to connect to.
* @param reserve_reference reference to the reserve to check.
* @param expected_balance balance expected to be at the referenced reserve.
* @param expected_response_code expected HTTP response code.
*
* @return the command to be executed by the interpreter.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_status (const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *reserve_reference,
const char *expected_balance,
unsigned int expected_response_code)
{
struct TALER_TESTING_Command cmd;
struct StatusState *ss;
ss = GNUNET_new (struct StatusState);
ss->exchange = exchange;
ss->reserve_reference = reserve_reference;
ss->expected_balance = expected_balance;
ss->expected_response_code = expected_response_code;
cmd.cls = ss;
cmd.label = label;
cmd.run = &status_run;
cmd.cleanup = &status_cleanup;
return cmd;
}

View File

@ -0,0 +1,819 @@
/*
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 exchange/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"
struct TrackTransactionState
{
/**
* Which #OC_CHECK_BANK_TRANSFER wtid should this match? NULL
* for none.
*/
const char *bank_transfer_reference;
/**
* Wire transfer identifier, set if #MHD_HTTP_OK was the
* response code.
*/
struct TALER_WireTransferIdentifierRawP wtid;
/**
* Expected HTTP response code.
*/
unsigned int expected_response_code;
/**
* Reference to any operation that can provide a transaction.
* Tipically a /deposit operation.
*/
const char *transaction_reference;
/**
* Index of the coin involved in the transaction.
*/
unsigned int coin_index;
/**
* Handle to the deposit wtid request.
*/
struct TALER_EXCHANGE_TrackTransactionHandle *tth;
/**
* Handle to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
struct TrackTransferState
{
/**
* Expected amount for this WTID.
*/
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.
*/
const char *wtid_reference;
/**
* Reference to any operation that can provide wire details.
*/
const char *wire_details_reference;
/**
* Reference to any operation that can provide an amount.
*/
const char *total_amount_reference;
/**
* Index to the WTID to pick.
*/
unsigned int index;
/**
* Handle to the deposit wtid request.
*/
struct TALER_EXCHANGE_TrackTransferHandle *tth;
/**
* Handle to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is;
};
/**
* Function called with detailed wire transfer data.
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange
* protocol violation
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key the exchange used for signing
* @param json original json reply (may include signatures, those
* have then been validated already)
* @param wtid wire transfer identifier used by the exchange, NULL
* if exchange did not yet execute the transaction
* @param execution_time actual or planned execution time for the
* wire transfer
* @param coin_contribution contribution to the @a total_amount of
* the deposited coin (may be NULL)
* @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 #MHD_HTTP_OK)
*/
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];
tts->tth = NULL;
if (tts->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
cmd->label);
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;
char *ws;
ws = GNUNET_STRINGS_data_to_string_alloc (wtid,
sizeof (*wtid));
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;
}
char *transfer_subject;
if (GNUNET_OK != TALER_TESTING_get_trait_transfer_subject
(bank_transfer_cmd, 0, &transfer_subject))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (0 != strcmp (ws, transfer_subject))
{
GNUNET_break (0);
GNUNET_free (ws);
TALER_TESTING_interpreter_fail (tts->is);
return;
}
GNUNET_free (ws);
}
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, typically a #struct WireState.
* @param cmd the command to execute, a /track/transaction one.
* @param is the interpreter state.
*/
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;
struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_CoinSpendPublicKeyP coin_pub;
const char *wire_details;
const char *contract_terms;
json_t *j_wire_details;
json_t *j_contract_terms;
struct GNUNET_HashCode h_wire_details;
struct GNUNET_HashCode h_contract_terms;
const struct GNUNET_CRYPTO_EddsaPrivateKey *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;
}
/* Parse them.. */
j_wire_details = json_loads
(wire_details, JSON_REJECT_DUPLICATES, NULL);
j_contract_terms = json_loads
(contract_terms, JSON_REJECT_DUPLICATES, NULL);
if ((NULL == j_wire_details) || (NULL == j_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_hash (j_wire_details,
&h_wire_details)) &&
(GNUNET_OK == TALER_JSON_hash (j_contract_terms,
&h_contract_terms)) );
if (GNUNET_OK != TALER_TESTING_get_trait_peer_key
(transaction_cmd, 0, &merchant_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
return;
}
tts->tth = TALER_EXCHANGE_track_transaction
(tts->exchange,
(struct TALER_MerchantPrivateKeyP *) merchant_priv,
&h_wire_details,
&h_contract_terms,
&coin_pub,
&deposit_wtid_cb,
tts);
GNUNET_assert (NULL != tts->tth);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
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);
}
/**
* Extract information from a command that is useful for other
* commands.
*
* @param cls closure
* @param ret[out] result (could be anything)
* @param trait name of the trait
* @param selector more detailed information about which object
* to return in case there were multiple generated
* by the command
* @return #GNUNET_OK on success
*/
static int
track_transaction_traits (void *cls,
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 exchange the exchange to connect to.
* @param transaction_reference reference to a deposit operation.
* @param coin_index index of the coin involved in the transaction
* @param expected_response_code expected HTTP response code.
* @param bank_transfer_reference which #OC_CHECK_BANK_TRANSFER
* wtid should this match? NULL
* for none
*
* @return the command to be executed by the interpreter.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_track_transaction
(const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *transaction_reference,
unsigned int coin_index,
unsigned int expected_response_code,
const char *bank_transfer_reference)
{
struct TALER_TESTING_Command cmd;
struct TrackTransactionState *tts;
tts = GNUNET_new (struct TrackTransactionState);
tts->exchange = exchange;
tts->transaction_reference = transaction_reference;
tts->expected_response_code = expected_response_code;
tts->bank_transfer_reference = bank_transfer_reference;
tts->coin_index = coin_index;
cmd.cls = tts;
cmd.label = label;
cmd.run = &track_transaction_run;
cmd.cleanup = &track_transaction_cleanup;
cmd.traits = &track_transaction_traits;
return cmd;
}
/**
* Cleanup the state.
*
* @param cls closure.
* @param cmd the command which is being cleaned up.
*/
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);
}
/**
* Function called with detailed wire transfer data, including all
* of the coin transactions that were combined into the wire
* transfer.
*
* @param cls closure
* @param http_status HTTP status code we got, 0 on exchange
* protocol violation
* @param ec taler-specific error code, #TALER_EC_NONE on success
* @param exchange_pub public key the exchange used for signing
* @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 #MHD_HTTP_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];
const struct TALER_TESTING_Command *wtid_cmd;
struct TALER_Amount expected_amount;
tts->tth = NULL;
if (tts->expected_response_code != http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s\n",
http_status,
cmd->label);
json_dumpf (json, stderr, 0);
TALER_TESTING_interpreter_fail (is);
return;
}
switch (http_status)
{
if (
(NULL == tts->expected_total_amount) ||
(NULL == tts->expected_wire_fee))
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Expected amount and fee not specified, "
"likely to segfault...\n");
case MHD_HTTP_OK:
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;
}
wtid_cmd = TALER_TESTING_interpreter_lookup_command
(is, tts->wtid_reference);
if (NULL == wtid_cmd)
{
GNUNET_break (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 char *wire_details;
json_t *j_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;
}
j_wire_details = json_loads
(wire_details, JSON_REJECT_DUPLICATES, NULL);
GNUNET_assert (NULL != j_wire_details);
GNUNET_assert (GNUNET_OK == TALER_JSON_hash
(j_wire_details, &h_wire_details));
if (0 != memcmp (&h_wire_details,
h_wire,
sizeof (struct GNUNET_HashCode)))
{
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 char *total_amount_from_reference_str;
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
(total_amount_cmd, 0, &total_amount_from_reference_str))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
GNUNET_assert (GNUNET_OK == TALER_string_to_amount
(total_amount_from_reference_str,
&total_amount_from_reference));
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 to execute, a /track/transfer one.
* @param is the interpreter state.
*/
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;
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;
}
}
tts->tth = TALER_EXCHANGE_track_transfer (tts->exchange,
wtid_ptr,
&track_transfer_cb,
tts);
GNUNET_assert (NULL != tts->tth);
}
/**
* Make a /track/transfer command, expecting the transfer
* not being done (yet).
*
* @param label the command label
* @param exchange connection to the exchange
* @param wtid_reference reference to any command which can provide
* a wtid
* @param index in case there are multiple wtid offered, this
* parameter selects a particular one
* @param expected_response_code expected HTTP response code
*
* @return the command
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_track_transfer_empty
(const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *wtid_reference,
unsigned int index,
unsigned int expected_response_code)
{
struct TrackTransferState *tts;
struct TALER_TESTING_Command cmd;
tts = GNUNET_new (struct TrackTransferState);
tts->wtid_reference = wtid_reference;
tts->index = index;
tts->expected_response_code = expected_response_code;
tts->exchange = exchange;
cmd.cls = tts;
cmd.label = label;
cmd.run = &track_transfer_run;
cmd.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 exchange connection to the exchange
* @param wtid_reference reference to any command which can provide
* a wtid
* @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_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,
struct TALER_EXCHANGE_Handle *exchange,
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;
struct TALER_TESTING_Command cmd;
tts = GNUNET_new (struct TrackTransferState);
tts->wtid_reference = wtid_reference;
tts->index = index;
tts->expected_response_code = expected_response_code;
tts->exchange = exchange;
tts->expected_total_amount = expected_total_amount;
tts->expected_wire_fee = expected_wire_fee;
cmd.cls = tts;
cmd.label = label;
cmd.run = &track_transfer_run;
cmd.cleanup = &track_transfer_cleanup;
return cmd;
}

View File

@ -0,0 +1,267 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
struct WireState
{
/**
* Handle to the /wire operation.
*/
struct TALER_EXCHANGE_WireHandle *wh;
/**
* Which wire-method we expect are 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;
/**
* Connection to the exchange.
*/
struct TALER_EXCHANGE_Handle *exchange;
};
/**
* Check all the expected values have been returned by /wire.
*
* @param cls closure
* @param wire_method name of the wire method (i.e. "sepa")
* @param fees fee structure for this method
*/
static void
check_method_and_fee_cb
(void *cls,
const char *wire_method,
const struct TALER_EXCHANGE_WireAggregateFees *fees);
/**
* Callbacks called with the result(s) of a wire format inquiry
* request to the exchange.
*
* @param cls closure with the interpreter state
* @param http_status HTTP response code, #MHD_HTTP_OK (200)
* for successful 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 obj the received JSON reply, if successful this should
* be the wire format details as provided by /wire.
*/
static void
wire_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
const json_t *obj)
{
struct WireState *ws = cls;
struct TALER_TESTING_Command *cmd
= &ws->is->commands[ws->is->ip];
/**
* The handle has been free'd by GNUnet curl-lib. FIXME:
* shouldn't GNUnet nullify it once it frees it?
*/
ws->wh = NULL;
if (ws->expected_response_code != http_status)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (ws->is);
return;
}
if (GNUNET_OK != TALER_EXCHANGE_wire_get_fees
(&TALER_EXCHANGE_get_keys (ws->exchange)->master_pub,
obj,
// will check synchronously.
&check_method_and_fee_cb,
ws))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Wire fee extraction in command %s failed\n",
cmd->label);
json_dumpf (obj, stderr, 0);
TALER_TESTING_interpreter_fail (ws->is);
return;
}
if (ws->method_found != GNUNET_OK)
{
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);
}
/**
* Check all the expected values have been returned by /wire.
*
* @param cls closure
* @param wire_method name of the wire method (i.e. "sepa")
* @param fees fee structure for this method
*/
static void
check_method_and_fee_cb
(void *cls,
const char *wire_method,
const struct TALER_EXCHANGE_WireAggregateFees *fees)
{
struct WireState *ws = cls;
struct TALER_TESTING_Command *cmd
= &ws->is->commands[ws->is->ip]; // ugly?
struct TALER_Amount expected_fee;
if (0 == strcmp (ws->expected_method, wire_method))
ws->method_found = GNUNET_OK;
if ( ws->expected_fee && (ws->method_found == GNUNET_OK) )
{
GNUNET_assert (GNUNET_OK == TALER_string_to_amount
(ws->expected_fee,
&expected_fee));
while (NULL != fees)
{
if (0 != TALER_amount_cmp (&fees->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);
return;
}
fees = fees->next;
}
}
}
/**
* Run the command.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command to execute, a /wire one.
* @param i the interpreter state.
*/
void
wire_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *i)
{
struct WireState *ws = cls;
ws->is = i;
ws->wh = TALER_EXCHANGE_wire (ws->exchange,
&wire_cb,
ws);
}
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
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 exchange the exchange to connect to.
* @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 to be executed by the interpreter.
*/
struct TALER_TESTING_Command
TALER_TESTING_cmd_wire (const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *expected_method,
const char *expected_fee,
unsigned int expected_response_code)
{
struct TALER_TESTING_Command cmd;
struct WireState *ws;
ws = GNUNET_new (struct WireState);
ws->exchange = exchange;
ws->expected_method = expected_method;
ws->expected_fee = expected_fee;
ws->expected_response_code = expected_response_code;
cmd.cls = ws;
cmd.label = label;
cmd.run = &wire_run;
cmd.cleanup = &wire_cleanup;
return cmd;
}

View File

@ -2,16 +2,18 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it
terms of the GNU General Public License as published by the Free Software under the terms of the GNU General Public License as published by
Foundation; either version 3, or (at your option) any later version. the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
@ -85,14 +87,17 @@ struct WithdrawState
/** /**
* Function called upon completion of our /reserve/withdraw request. * Function called upon completion of our /reserve/withdraw
* request.
* *
* @param cls closure with the withdraw state * @param cls closure with the withdraw state
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
* 0 if the exchange's reply is bogus (fails to follow the protocol) * 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 ec taler-specific error code, #TALER_EC_NONE on success
* @param sig signature over the coin, NULL on error * @param sig signature over the coin, NULL on error
* @param full_response full response from the exchange (for logging, in case of errors) * @param full_response full response from the exchange (for
* logging, in case of errors)
*/ */
static void static void
reserve_withdraw_cb (void *cls, reserve_withdraw_cb (void *cls,
@ -164,9 +169,8 @@ withdraw_run (void *cls,
struct TALER_ReservePrivateKeyP *rp; struct TALER_ReservePrivateKeyP *rp;
const struct TALER_TESTING_Command *create_reserve; const struct TALER_TESTING_Command *create_reserve;
create_reserve create_reserve = TALER_TESTING_interpreter_lookup_command
= TALER_TESTING_interpreter_lookup_command (is, (is, ws->reserve_reference);
ws->reserve_reference);
if (NULL == create_reserve) if (NULL == create_reserve)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -175,7 +179,7 @@ withdraw_run (void *cls,
} }
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_reserve_priv (create_reserve, TALER_TESTING_get_trait_reserve_priv (create_reserve,
NULL, 0,
&rp)) &rp))
{ {
GNUNET_break (0); GNUNET_break (0);
@ -245,38 +249,72 @@ static int
withdraw_traits (void *cls, withdraw_traits (void *cls,
void **ret, void **ret,
const char *trait, const char *trait,
const char *selector) unsigned int index)
{ {
struct WithdrawState *ws = cls; struct WithdrawState *ws = cls;
const struct TALER_TESTING_Command *reserve_cmd;
struct TALER_ReservePrivateKeyP *reserve_priv;
/* 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;
}
struct TALER_TESTING_Trait traits[] = { struct TALER_TESTING_Trait traits[] = {
TALER_TESTING_make_trait_coin_priv (NULL /* only one coin */, TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
&ws->ps.coin_priv), &ws->ps.coin_priv),
TALER_TESTING_make_trait_blinding_key (NULL /* only one coin */, TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
&ws->ps.blinding_key), &ws->ps.blinding_key),
TALER_TESTING_make_trait_denom_pub (NULL /* only one coin */, TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
ws->pk), ws->pk),
TALER_TESTING_make_trait_denom_sig (NULL /* only one coin */, TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,
&ws->sig), &ws->sig),
TALER_TESTING_make_trait_reserve_priv (0,
reserve_priv),
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
}; };
return TALER_TESTING_get_trait (traits, return TALER_TESTING_get_trait (traits,
ret, ret,
trait, trait,
selector); index);
} }
/** /**
* Create withdraw command. * Create a withdraw command.
* *
* @param label command label, used by other commands to
* reference this.
* @param exchange handle to the exchange.
* @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 struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_amount (const char *label, TALER_TESTING_cmd_withdraw_amount
struct TALER_EXCHANGE_Handle *exchange, (const char *label,
const char *reserve_reference, struct TALER_EXCHANGE_Handle *exchange,
const char *amount, const char *reserve_reference,
unsigned int expected_response_code) const char *amount,
unsigned int expected_response_code)
{ {
struct TALER_TESTING_Command cmd; struct TALER_TESTING_Command cmd;
struct WithdrawState *ws; struct WithdrawState *ws;
@ -294,8 +332,9 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
label); label);
GNUNET_assert (0); GNUNET_assert (0);
} }
ws->pk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (exchange), ws->pk = TALER_TESTING_find_pk
&ws->amount); (TALER_EXCHANGE_get_keys (exchange),
&ws->amount);
if (NULL == ws->pk) if (NULL == ws->pk)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -319,11 +358,12 @@ TALER_TESTING_cmd_withdraw_amount (const char *label,
* *
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_withdraw_denomination (const char *label, TALER_TESTING_cmd_withdraw_denomination
struct TALER_EXCHANGE_Handle *exchange, (const char *label,
const char *reserve_reference, struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *dk, const char *reserve_reference,
unsigned int expected_response_code) const struct TALER_EXCHANGE_DenomPublicKey *dk,
unsigned int expected_response_code)
{ {
struct TALER_TESTING_Command cmd; struct TALER_TESTING_Command cmd;
struct WithdrawState *ws; struct WithdrawState *ws;
@ -349,7 +389,4 @@ TALER_TESTING_cmd_withdraw_denomination (const char *label,
} }
/* end of testing_api_cmd_withdraw.c */ /* end of testing_api_cmd_withdraw.c */

View File

@ -1,4 +1,3 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
@ -31,6 +30,8 @@
/** /**
* Remove files from previous runs * Remove files from previous runs
*
* @param config_name configuration filename.
*/ */
void void
TALER_TESTING_cleanup_files (const char *config_name) TALER_TESTING_cleanup_files (const char *config_name)
@ -65,7 +66,7 @@ TALER_TESTING_cleanup_files (const char *config_name)
/** /**
* Prepare launching an exchange. Checks that the configured * Prepare launching an exchange. Checks that the configured
* port is available, runs taler-exchange-keyup, * port is available, runs taler-exchange-keyup,
* taler-auditor-sign and taler-exchange-dbinit. Does not * taler-auditor-sign and taler-exchange-dbinit. Does NOT
* launch the exchange process itself. * launch the exchange process itself.
* *
* @param config_filename configuration file to use * @param config_filename configuration file to use
@ -79,42 +80,16 @@ TALER_TESTING_prepare_exchange (const char *config_filename)
enum GNUNET_OS_ProcessStatusType type; enum GNUNET_OS_ProcessStatusType type;
unsigned long code; unsigned long code;
struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfg;
unsigned long long port; char *test_home_dir;
char *signed_keys_out;
cfg = GNUNET_CONFIGURATION_create (); char *exchange_master_pub;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_load (cfg,
config_filename))
return GNUNET_NO;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg,
"exchange",
"PORT",
&port))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange",
"PORT");
GNUNET_CONFIGURATION_destroy (cfg);
return GNUNET_NO;
}
GNUNET_CONFIGURATION_destroy (cfg);
if (GNUNET_OK !=
GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
(uint16_t) port))
{
fprintf (stderr,
"Required port %llu not available, skipping.\n",
port);
return GNUNET_NO;
}
proc = GNUNET_OS_start_process (GNUNET_NO, proc = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL, GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-exchange-keyup", "taler-exchange-keyup",
"taler-exchange-keyup", "taler-exchange-keyup",
"-c", "test_exchange_api.conf", "-c", config_filename,
"-o", "auditor.in", "-o", "auditor.in",
NULL); NULL);
if (NULL == proc) if (NULL == proc)
@ -126,21 +101,58 @@ TALER_TESTING_prepare_exchange (const char *config_filename)
GNUNET_OS_process_wait (proc); GNUNET_OS_process_wait (proc);
GNUNET_OS_process_destroy (proc); GNUNET_OS_process_destroy (proc);
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK != GNUNET_CONFIGURATION_load
(cfg, config_filename))
return GNUNET_SYSERR;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"paths",
"TALER_TEST_HOME",
&test_home_dir))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"paths",
"TALER_TEST_HOME");
GNUNET_CONFIGURATION_destroy (cfg);
return GNUNET_SYSERR;
}
GNUNET_asprintf (&signed_keys_out,
"%s/.local/share/taler/auditors/auditor.out",
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);
return GNUNET_SYSERR;
}
GNUNET_CONFIGURATION_destroy (cfg);
proc = GNUNET_OS_start_process (GNUNET_NO, proc = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL, GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-auditor-sign", "taler-auditor-sign",
"taler-auditor-sign", "taler-auditor-sign",
"-c", "test_exchange_api.conf", "-c", config_filename,
"-u", "http://auditor/", "-u", "http://auditor/",
"-m", "98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG", "-m", exchange_master_pub,
"-r", "auditor.in", "-r", "auditor.in",
"-o", "test_exchange_api_home/.local/share/taler/auditors/auditor.out", "-o", signed_keys_out,
NULL); NULL);
if (NULL == proc) if (NULL == proc)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to run `taler-exchange-keyup`, is your PATH correct?\n"); "Failed to run `taler-auditor-sign`, is your PATH correct?\n");
return GNUNET_NO; return GNUNET_NO;
} }
GNUNET_OS_process_wait (proc); GNUNET_OS_process_wait (proc);
@ -151,7 +163,7 @@ TALER_TESTING_prepare_exchange (const char *config_filename)
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-exchange-dbinit", "taler-exchange-dbinit",
"taler-exchange-dbinit", "taler-exchange-dbinit",
"-c", "test_exchange_api.conf", "-c", config_filename,
"-r", "-r",
NULL); NULL);
if (NULL == proc) if (NULL == proc)
@ -245,22 +257,60 @@ TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
* Initialize scheduler loop and curl context for the testcase * Initialize scheduler loop and curl context for the testcase
* including starting and stopping the exchange using the given * including starting and stopping the exchange using the given
* configuration file. * 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 FIXME: depends on what TALER_TESTING_setup returns.
*/ */
int int
TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb, TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
void *main_cb_cls, void *main_cb_cls,
const char *config_file) const char *config_filename)
{ {
int result; int result;
unsigned int iter; unsigned int iter;
struct GNUNET_OS_Process *exchanged; struct GNUNET_OS_Process *exchanged;
struct GNUNET_CONFIGURATION_Handle *cfg;
unsigned long long port;
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK !=
GNUNET_CONFIGURATION_load (cfg,
config_filename))
return GNUNET_NO;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg,
"exchange",
"PORT",
&port))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange",
"PORT");
GNUNET_CONFIGURATION_destroy (cfg);
return GNUNET_NO;
}
GNUNET_CONFIGURATION_destroy (cfg);
if (GNUNET_OK !=
GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
(uint16_t) port))
{
fprintf (stderr,
"Required port %llu not available, skipping.\n",
port);
return GNUNET_NO;
}
exchanged = GNUNET_OS_start_process (GNUNET_NO, exchanged = GNUNET_OS_start_process (GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL, GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL, NULL, NULL, NULL,
"taler-exchange-httpd", "taler-exchange-httpd",
"taler-exchange-httpd", "taler-exchange-httpd",
"-c", config_file, "-c", config_filename,
"-i", "-i",
NULL); NULL);
/* give child time to start and bind against the socket */ /* give child time to start and bind against the socket */
@ -287,7 +337,9 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
fprintf (stderr, "\n"); fprintf (stderr, "\n");
result = TALER_TESTING_setup (main_cb, result = TALER_TESTING_setup (main_cb,
main_cb_cls); main_cb_cls,
config_filename,
exchanged);
GNUNET_break (0 == GNUNET_break (0 ==
GNUNET_OS_process_kill (exchanged, GNUNET_OS_process_kill (exchanged,
SIGTERM)); SIGTERM));
@ -325,10 +377,32 @@ TALER_TESTING_url_port_free (const char *url)
return GNUNET_OK; return GNUNET_OK;
} }
/**
* Allocate and return a piece of wire-details. Mostly, it adds
* the bank_url to the JSON.
*
* @param template the wire-details template.
* @param bank_url the bank_url
*
* @return the filled out and stringified wire-details. To
* be manually free'd.
*/
char *
TALER_TESTING_make_wire_details (const char *template,
const char *bank_url)
{
json_t *jtemplate;
GNUNET_assert (NULL != (jtemplate = json_loads
(template, JSON_REJECT_DUPLICATES, NULL)));
GNUNET_assert (0 == json_object_set
(jtemplate, "bank_url", json_string (bank_url)));
return json_dumps (jtemplate, JSON_COMPACT);
}
/** /**
* Prepare launching a fakebank. Check that the configuration * Prepare launching a fakebank. Check that the configuration
* file has the right option, and that the port is avaiable. * file has the right option, and that the port is available.
* If everything is OK, return the configured URL of the fakebank. * If everything is OK, return the configured URL of the fakebank.
* *
* @param config_filename configuration file to use * @param config_filename configuration file to use

View File

@ -2,18 +2,21 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it
terms of the GNU General Public License as published by the Free Software under the terms of the GNU General Public License as published
Foundation; either version 3, or (at your option) any later version. by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file exchange-lib/testing_api_loop.c * @file exchange-lib/testing_api_loop.c
* @brief main interpreter loop for testcases * @brief main interpreter loop for testcases
@ -28,73 +31,12 @@
#include "taler_testing_lib.h" #include "taler_testing_lib.h"
#include "taler_fakebank_lib.h" #include "taler_fakebank_lib.h"
/**
* Global state of the interpreter, used by a command
* to access information about other commands.
*/
struct TALER_TESTING_Interpreter
{
/**
* Commands the interpreter will run.
*/
struct TALER_TESTING_Command *commands;
/**
* Interpreter task (if one is scheduled).
*/
struct GNUNET_SCHEDULER_Task *task;
/**
* ID of task called whenever we get a SIGCHILD.
* Used for #TALER_TESTING_wait_for_sigchld().
*/
struct GNUNET_SCHEDULER_Task *child_death_task;
/**
* Main execution context for the main loop.
*/
struct GNUNET_CURL_Context *ctx;
/**
* Context for running the CURL event loop.
*/
struct GNUNET_CURL_RescheduleContext *rc;
/**
* Handle to our fakebank, if #TALER_TESTING_run_with_fakebank() was used.
* Otherwise NULL.
*/
struct TALER_FAKEBANK_Handle *fakebank;
/**
* Task run on timeout.
*/
struct GNUNET_SCHEDULER_Task *timeout_task;
/**
* Instruction pointer. Tells #interpreter_run() which
* instruction to run next.
*/
unsigned int ip;
/**
* Result of the testcases, #GNUNET_OK on success
*/
int result;
};
/** /**
* Pipe used to communicate child death via signal. * Pipe used to communicate child death via signal.
* Must be global, as used in signal handler! * Must be global, as used in signal handler!
*/ */
static struct GNUNET_DISK_PipeHandle *sigpipe; static struct GNUNET_DISK_PipeHandle *sigpipe;
/** /**
* Lookup command by label. * Lookup command by label.
* *
@ -103,8 +45,9 @@ static struct GNUNET_DISK_PipeHandle *sigpipe;
* @return NULL if command was not found * @return NULL if command was not found
*/ */
const struct TALER_TESTING_Command * const struct TALER_TESTING_Command *
TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is, TALER_TESTING_interpreter_lookup_command
const char *label) (struct TALER_TESTING_Interpreter *is,
const char *label)
{ {
const struct TALER_TESTING_Command *cmd; const struct TALER_TESTING_Command *cmd;
@ -131,23 +74,35 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
* Obtain main execution context for the main loop. * Obtain main execution context for the main loop.
*/ */
struct GNUNET_CURL_Context * struct GNUNET_CURL_Context *
TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is) TALER_TESTING_interpreter_get_context
(struct TALER_TESTING_Interpreter *is)
{ {
return is->ctx; return is->ctx;
} }
struct TALER_FAKEBANK_Handle * struct TALER_FAKEBANK_Handle *
TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is) TALER_TESTING_interpreter_get_fakebank
(struct TALER_TESTING_Interpreter *is)
{ {
return is->fakebank; 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 void
TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run_with_fakebank
struct TALER_TESTING_Command *commands, (struct TALER_TESTING_Interpreter *is,
const char *bank_url) struct TALER_TESTING_Command *commands,
const char *bank_url)
{ {
const char *port; const char *port;
long pnum; long pnum;
@ -159,7 +114,7 @@ TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
else else
pnum = strtol (port + 1, NULL, 10); pnum = strtol (port + 1, NULL, 10);
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Staring Fakebank on port %u (%s)\n", "Starting Fakebank on port %u (%s)\n",
(unsigned int) pnum, (unsigned int) pnum,
bank_url); bank_url);
is->fakebank = TALER_FAKEBANK_start ((uint16_t) pnum); is->fakebank = TALER_FAKEBANK_start ((uint16_t) pnum);
@ -192,8 +147,7 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *i)
if (GNUNET_SYSERR == i->result) if (GNUNET_SYSERR == i->result)
return; /* ignore, we already failed! */ return; /* ignore, we already failed! */
i->ip++; i->ip++;
i->task = GNUNET_SCHEDULER_add_now (&interpreter_run, i->task = GNUNET_SCHEDULER_add_now (&interpreter_run, i);
i);
} }
@ -201,21 +155,25 @@ TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *i)
* Current command failed, clean up and fail the test case. * Current command failed, clean up and fail the test case.
*/ */
void void
TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *i) TALER_TESTING_interpreter_fail
(struct TALER_TESTING_Interpreter *is)
{ {
i->result = GNUNET_SYSERR; // FIXME: disconnect from the exchange.
is->result = GNUNET_SYSERR;
// this cleans up too.
GNUNET_SCHEDULER_shutdown (); GNUNET_SCHEDULER_shutdown ();
} }
/** /**
* Create command array terminator. * Create command array terminator.
*
* @return a end-command.
*/ */
struct TALER_TESTING_Command struct TALER_TESTING_Command
TALER_TESTING_cmd_end (void) TALER_TESTING_cmd_end (void)
{ {
static struct TALER_TESTING_Command cmd; static struct TALER_TESTING_Command cmd;
return cmd; return cmd;
} }
@ -224,7 +182,8 @@ TALER_TESTING_cmd_end (void)
* Obtain current label. * Obtain current label.
*/ */
const char * const char *
TALER_TESTING_interpreter_get_current_label (struct TALER_TESTING_Interpreter *is) TALER_TESTING_interpreter_get_current_label
(struct TALER_TESTING_Interpreter *is)
{ {
struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
@ -278,6 +237,10 @@ do_shutdown (void *cls)
for (unsigned int j=0;NULL != (cmd = &is->commands[j])->label;j++) for (unsigned int j=0;NULL != (cmd = &is->commands[j])->label;j++)
cmd->cleanup (cmd->cls, cmd->cleanup (cmd->cls,
cmd); cmd);
if (NULL != is->exchange)
{
TALER_EXCHANGE_disconnect (is->exchange);
}
if (NULL != is->task) if (NULL != is->task)
{ {
GNUNET_SCHEDULER_cancel (is->task); GNUNET_SCHEDULER_cancel (is->task);
@ -351,7 +314,7 @@ maint_child_death (void *cls)
sizeof (c))); sizeof (c)));
if (GNUNET_OK != if (GNUNET_OK !=
TALER_TESTING_get_trait_process (cmd, TALER_TESTING_get_trait_process (cmd,
NULL, 0,
&processp)) &processp))
{ {
GNUNET_break (0); GNUNET_break (0);
@ -361,6 +324,14 @@ maint_child_death (void *cls)
GNUNET_OS_process_wait (*processp); GNUNET_OS_process_wait (*processp);
GNUNET_OS_process_destroy (*processp); GNUNET_OS_process_destroy (*processp);
*processp = NULL; *processp = NULL;
if (GNUNET_OK == is->reload_keys)
{
GNUNET_break (0 == GNUNET_OS_process_kill
(is->exchanged, SIGUSR1));
sleep (5); /* make sure signal was received and processed */
}
TALER_TESTING_interpreter_next (is); TALER_TESTING_interpreter_next (is);
} }
@ -372,7 +343,8 @@ maint_child_death (void *cls)
* with the next command. * with the next command.
*/ */
void void
TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is) TALER_TESTING_wait_for_sigchld
(struct TALER_TESTING_Interpreter *is)
{ {
const struct GNUNET_DISK_FileHandle *pr; const struct GNUNET_DISK_FileHandle *pr;
@ -384,42 +356,66 @@ TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
pr, pr,
&maint_child_death, &maint_child_death,
is); is);
} }
/**
* Run the testsuite. FIXME: explain why the commands are
* copied into the state.
*
* @param is the interpreter state
* @param commands the list of command to execute
*/
void void
TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands) struct TALER_TESTING_Command *commands)
{ {
unsigned int i; unsigned int i;
/* get the number of commands */
for (i=0;NULL != commands[i].label;i++) ; for (i=0;NULL != commands[i].label;i++) ;
is->commands = GNUNET_new_array (i + 1, is->commands = GNUNET_new_array (i + 1,
struct TALER_TESTING_Command); struct TALER_TESTING_Command);
memcpy (is->commands, memcpy (is->commands,
commands, commands,
sizeof (struct TALER_TESTING_Command) * i); sizeof (struct TALER_TESTING_Command) * i);
is->timeout_task is->timeout_task = GNUNET_SCHEDULER_add_delayed
= GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300),
(GNUNET_TIME_UNIT_SECONDS, 300), &do_timeout, is);
&do_timeout, GNUNET_SCHEDULER_add_shutdown (&do_shutdown, is);
is); is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, is);
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
is);
is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
is);
} }
/**
* Information used by the wrapper around the main
* "run" method.
*/
struct MainContext struct MainContext
{ {
/**
* Main "run" method.
*/
TALER_TESTING_Main main_cb; TALER_TESTING_Main main_cb;
/**
* Closure for "run".
*/
void *main_cb_cls; void *main_cb_cls;
/**
* Interpreter state.
*/
struct TALER_TESTING_Interpreter *is; 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;
}; };
@ -433,58 +429,170 @@ sighandler_child_death ()
static char c; static char c;
int old_errno = errno; /* back-up errno */ int old_errno = errno; /* back-up errno */
GNUNET_break (1 == GNUNET_break (1 == GNUNET_DISK_file_write
GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle (GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
(sigpipe, &c, sizeof (c)));
GNUNET_DISK_PIPE_END_WRITE),
&c, sizeof (c)));
errno = old_errno; /* restore errno */ errno = old_errno; /* restore errno */
} }
/**
* Called once a connection to the exchange has been
* established.
*
* @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
cert_cb (void *cls,
const struct TALER_EXCHANGE_Keys *keys,
enum TALER_EXCHANGE_VersionCompatibility compat)
{
struct MainContext *main_ctx = cls;
if (NULL == keys)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Got NULL response for /keys\n");
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Got %d DK from /keys\n",
keys->num_denom_keys);
main_ctx->is->key_generation++;
main_ctx->is->keys = keys;
/* /keys has been called for some reason and
* the interpreter is already running. */
if (GNUNET_YES == main_ctx->is->working)
return;
main_ctx->is->working = GNUNET_YES;
/* Very first start of tests, call "run()" */
if (1 == main_ctx->is->key_generation)
{
main_ctx->main_cb (main_ctx->main_cb_cls,
main_ctx->is);
return;
}
/* Tests already started, just trigger the
* next command. */
GNUNET_SCHEDULER_add_now (&interpreter_run,
main_ctx->is);
}
/**
* Initialize scheduler loop and curl context for the testcase,
* and responsible to run the "run" method.
*
* @param cls closure, typically the "run" method, the
* interpreter state and a closure for "run".
*/
static void static void
main_wrapper (void *cls) main_wrapper (void *cls)
{ {
struct MainContext *main_ctx = cls; struct MainContext *main_ctx = cls;
struct TALER_TESTING_Interpreter *is = main_ctx->is; struct TALER_TESTING_Interpreter *is = main_ctx->is;
struct GNUNET_CONFIGURATION_Handle *cfg;
char *exchange_url;
long long unsigned int exchange_port;
is->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, cfg = GNUNET_CONFIGURATION_create ();
&is->rc); if (GNUNET_OK != GNUNET_CONFIGURATION_load
(cfg, main_ctx->config_filename))
return;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (cfg,
"exchange",
"PORT",
&exchange_port))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchange",
"PORT");
GNUNET_CONFIGURATION_destroy (cfg);
return;
}
GNUNET_asprintf (&exchange_url,
"http://localhost:%llu/",
exchange_port);
is->ctx = GNUNET_CURL_init
(&GNUNET_CURL_gnunet_scheduler_reschedule, &is->rc);
GNUNET_assert (NULL != is->ctx); GNUNET_assert (NULL != is->ctx);
is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx); is->rc = GNUNET_CURL_gnunet_rc_create (is->ctx);
main_ctx->main_cb (main_ctx->main_cb_cls,
main_ctx->is); GNUNET_assert ( NULL !=
(is->exchange = TALER_EXCHANGE_connect (is->ctx,
exchange_url,
cert_cb,
main_ctx)) );
GNUNET_free (exchange_url);
GNUNET_CONFIGURATION_destroy (cfg);
} }
/** /**
* Initialize scheduler loop and curl context for the testcase. * Install signal handlers plus schedules the main wrapper
* around the "run" method.
*
* @param main_cb the "run" method which coontains 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..
*
* @return FIXME: not sure what 'is.result' is at this stage.
*/ */
int int
TALER_TESTING_setup (TALER_TESTING_Main main_cb, TALER_TESTING_setup (TALER_TESTING_Main main_cb,
void *main_cb_cls) void *main_cb_cls,
const char *config_filename,
struct GNUNET_OS_Process *exchanged)
{ {
struct TALER_TESTING_Interpreter is; struct TALER_TESTING_Interpreter is;
struct MainContext main_ctx = { struct MainContext main_ctx = {
.main_cb = main_cb, .main_cb = main_cb,
.main_cb_cls = main_cb_cls, .main_cb_cls = main_cb_cls,
.is = &is /* needed to init the curl ctx */
.is = &is,
/* needed to read values like exchange port
* number and construct the exchange url. The
* port number _could_ have been passed here, but
* we prefer to stay "general" as other values might
* need to be passed around in the future. */
.config_filename = config_filename
}; };
struct GNUNET_SIGNAL_Context *shc_chld; struct GNUNET_SIGNAL_Context *shc_chld;
/* zero-ing the state */
memset (&is, memset (&is,
0, 0,
sizeof (is)); sizeof (is));
is.exchanged = exchanged;
sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
GNUNET_NO, GNUNET_NO); GNUNET_NO, GNUNET_NO);
GNUNET_assert (NULL != sigpipe); GNUNET_assert (NULL != sigpipe);
shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, shc_chld = GNUNET_SIGNAL_handler_install
&sighandler_child_death); (GNUNET_SIGCHLD, &sighandler_child_death);
GNUNET_SCHEDULER_run (&main_wrapper, GNUNET_SCHEDULER_run (&main_wrapper,
&main_ctx); &main_ctx);
GNUNET_SIGNAL_handler_uninstall (shc_chld); GNUNET_SIGNAL_handler_uninstall (shc_chld);
GNUNET_DISK_pipe_close (sigpipe); GNUNET_DISK_pipe_close (sigpipe);
sigpipe = NULL; sigpipe = NULL;
/*FIXME: ?? */
return is.result; return is.result;
} }

View File

@ -40,22 +40,22 @@
*/ */
int int
TALER_TESTING_get_trait_blinding_key (const struct TALER_TESTING_Command *cmd, TALER_TESTING_get_trait_blinding_key (const struct TALER_TESTING_Command *cmd,
const char *selector, unsigned int index,
struct TALER_DenominationBlindingKeyP **blinding_key) struct TALER_DenominationBlindingKeyP **blinding_key)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) blinding_key, (void **) blinding_key,
TALER_TESTING_TRAIT_BLINDING_KEY, TALER_TESTING_TRAIT_BLINDING_KEY,
selector); index);
} }
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_make_trait_blinding_key (const char *selector, TALER_TESTING_make_trait_blinding_key (unsigned int index,
const struct TALER_DenominationBlindingKeyP *blinding_key) const struct TALER_DenominationBlindingKeyP *blinding_key)
{ {
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .index = index,
.trait_name = TALER_TESTING_TRAIT_BLINDING_KEY, .trait_name = TALER_TESTING_TRAIT_BLINDING_KEY,
.ptr = (const void *) blinding_key .ptr = (const void *) blinding_key
}; };

View File

@ -2,18 +2,21 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it
terms of the GNU General Public License as published by the Free Software under the terms of the GNU General Public License as published by
Foundation; either version 3, or (at your option) any later version. the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
* @file exchange-lib/testing_api_trait_coin_priv.c * @file exchange-lib/testing_api_trait_coin_priv.c
* @brief main interpreter loop for testcases * @brief main interpreter loop for testcases
@ -34,28 +37,31 @@
* Obtain a coin private key from a @a cmd. * Obtain a coin private key from a @a cmd.
* *
* @param cmd command to extract trait from * @param cmd command to extract trait from
* @param selector which coin to pick if @a cmd has multiple on offer * @param selector which coin to pick if @a cmd has multiple on
* offer
* @param coin_priv[out] set to the private key of the coin * @param coin_priv[out] set to the private key of the coin
* @return #GNUNET_OK on success * @return #GNUNET_OK on success
*/ */
int int
TALER_TESTING_get_trait_coin_priv (const struct TALER_TESTING_Command *cmd, TALER_TESTING_get_trait_coin_priv
const char *selector, (const struct TALER_TESTING_Command *cmd,
struct TALER_CoinSpendPrivateKeyP **coin_priv) unsigned int index,
struct TALER_CoinSpendPrivateKeyP **coin_priv)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) coin_priv, (void **) coin_priv,
TALER_TESTING_TRAIT_COIN_PRIVATE_KEY, TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
selector); index);
} }
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_make_trait_coin_priv (const char *selector, TALER_TESTING_make_trait_coin_priv
const struct TALER_CoinSpendPrivateKeyP *coin_priv) (unsigned int index,
const struct TALER_CoinSpendPrivateKeyP *coin_priv)
{ {
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .index = index,
.trait_name = TALER_TESTING_TRAIT_COIN_PRIVATE_KEY, .trait_name = TALER_TESTING_TRAIT_COIN_PRIVATE_KEY,
.ptr = (const void *) coin_priv .ptr = (const void *) coin_priv
}; };

View File

@ -2,16 +2,18 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it
terms of the GNU General Public License as published by the Free Software under the terms of the GNU General Public License as published
Foundation; either version 3, or (at your option) any later version. by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
@ -34,28 +36,39 @@
* Obtain a denomination public key from a @a cmd. * Obtain a denomination public key from a @a cmd.
* *
* @param cmd command to extract trait from * @param cmd command to extract trait from
* @param selector which coin to pick if @a cmd has multiple on offer * @param selector which coin to pick if @a cmd has multiple on
* offer
* @param denom_pub[out] set to the blinding key of the coin * @param denom_pub[out] set to the blinding key of the coin
* @return #GNUNET_OK on success * @return #GNUNET_OK on success
*/ */
int int
TALER_TESTING_get_trait_denom_pub (const struct TALER_TESTING_Command *cmd, TALER_TESTING_get_trait_denom_pub
const char *selector, (const struct TALER_TESTING_Command *cmd,
struct TALER_EXCHANGE_DenomPublicKey **denom_pub) unsigned int index,
struct TALER_EXCHANGE_DenomPublicKey **denom_pub)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) denom_pub, (void **) denom_pub,
TALER_TESTING_TRAIT_DENOM_PUB, TALER_TESTING_TRAIT_DENOM_PUB,
selector); index);
} }
/**
* Make a trait for a denomination public key.
*
* @param selector in case the trait provides multiple
* objects, this parameter extracts a particular one.
* @param denom_pub pointer to the data to be returned from
* this trait
*/
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_make_trait_denom_pub (const char *selector, TALER_TESTING_make_trait_denom_pub
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub) (unsigned int index,
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub)
{ {
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .index = index,
.trait_name = TALER_TESTING_TRAIT_DENOM_PUB, .trait_name = TALER_TESTING_TRAIT_DENOM_PUB,
.ptr = (const void *) denom_pub .ptr = (const void *) denom_pub
}; };
@ -63,5 +76,4 @@ TALER_TESTING_make_trait_denom_pub (const char *selector,
return ret; return ret;
} }
/* end of testing_api_trait_denom_pub.c */ /* end of testing_api_trait_denom_pub.c */

View File

@ -40,22 +40,22 @@
*/ */
int int
TALER_TESTING_get_trait_denom_sig (const struct TALER_TESTING_Command *cmd, TALER_TESTING_get_trait_denom_sig (const struct TALER_TESTING_Command *cmd,
const char *selector, unsigned int index,
struct TALER_DenominationSignature **denom_sig) struct TALER_DenominationSignature **denom_sig)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) denom_sig, (void **) denom_sig,
TALER_TESTING_TRAIT_DENOM_SIG, TALER_TESTING_TRAIT_DENOM_SIG,
selector); index);
} }
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_make_trait_denom_sig (const char *selector, TALER_TESTING_make_trait_denom_sig (unsigned int index,
const struct TALER_DenominationSignature *denom_sig) const struct TALER_DenominationSignature *denom_sig)
{ {
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .index = index,
.trait_name = TALER_TESTING_TRAIT_DENOM_SIG, .trait_name = TALER_TESTING_TRAIT_DENOM_SIG,
.ptr = (const void *) denom_sig .ptr = (const void *) denom_sig
}; };

View File

@ -0,0 +1,74 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_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"
/**
* Obtain a "number" value from @a cmd.
*
* @param cmd command to extract trait from
* @param selector which coin to pick if @a cmd has multiple on
* offer
* @param fresh_coins[out] will point to array of fresh coins
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_fresh_coins
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
struct FreshCoin **fresh_coins)
{
return cmd->traits (cmd->cls,
(void **) fresh_coins,
TALER_TESTING_TRAIT_FRESH_COINS,
index);
}
/**
* @param selector associate the object with this "tag"
* @param fresh_coins the array of fresh coins to offer
*
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_fresh_coins
(unsigned int index,
struct FreshCoin *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 */

View File

@ -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 exchange-lib/testing_api_trait_key_peer.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"
/**
* NOTE: calling it "peer" key to make clear it is _not a coin_
* key.
*/
#define TALER_TESTING_TRAIT_KEY_PEER "key-peer"
/**
* Obtain a private key from a "peer". Used e.g. to obtain
* a merchant's priv to sign a /track request.
*
* @param index (tipically zero) which key to return if they
* exist in an array.
* @param selector which coin to pick if @a cmd has multiple on
* offer
* @param priv[out] set to the key coming from @a cmd.
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_peer_key
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
const struct GNUNET_CRYPTO_EddsaPrivateKey **priv)
{
return cmd->traits (cmd->cls,
(void **) priv,
TALER_TESTING_TRAIT_KEY_PEER,
index);
}
/**
* @param index (tipically zero) which key to return if they
* exist in an array.
* @param priv which object should be returned
*
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_peer_key
(unsigned int index,
struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_KEY_PEER,
.ptr = (const void *) priv
};
return ret;
}
/* end of testing_api_trait_key_peer.c */

View File

@ -0,0 +1,74 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_trait_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_NUMBER "number"
/**
* Obtain a "number" value from @a cmd.
*
* @param cmd command to extract trait from
* @param selector which coin to pick if @a cmd has multiple on
* offer
* @param n[out] set to the number coming from @a cmd.
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_uint
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
unsigned int **n)
{
return cmd->traits (cmd->cls,
(void **) n,
TALER_TESTING_TRAIT_NUMBER,
index);
}
/**
* @param selector associate the object with this "tag"
* @param n which object should be returned
*
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_uint
(unsigned int index,
const unsigned int *n)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_NUMBER,
.ptr = (const void *) n
};
return ret;
}
/* end of testing_api_trait_number.c */

View File

@ -40,22 +40,22 @@
*/ */
int int
TALER_TESTING_get_trait_process (const struct TALER_TESTING_Command *cmd, TALER_TESTING_get_trait_process (const struct TALER_TESTING_Command *cmd,
const char *selector, unsigned int index,
struct GNUNET_OS_Process ***processp) struct GNUNET_OS_Process ***processp)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) processp, (void **) processp,
TALER_TESTING_TRAIT_PROCESS, TALER_TESTING_TRAIT_PROCESS,
selector); index);
} }
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_make_trait_process (const char *selector, TALER_TESTING_make_trait_process (unsigned int index,
struct GNUNET_OS_Process **processp) struct GNUNET_OS_Process **processp)
{ {
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .index = index,
.trait_name = TALER_TESTING_TRAIT_PROCESS, .trait_name = TALER_TESTING_TRAIT_PROCESS,
.ptr = (const void *) processp .ptr = (const void *) processp
}; };

View File

@ -39,22 +39,22 @@
*/ */
int int
TALER_TESTING_get_trait_reserve_priv (const struct TALER_TESTING_Command *cmd, TALER_TESTING_get_trait_reserve_priv (const struct TALER_TESTING_Command *cmd,
const char *selector, unsigned int index,
struct TALER_ReservePrivateKeyP **reserve_priv) struct TALER_ReservePrivateKeyP **reserve_priv)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) reserve_priv, (void **) reserve_priv,
TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY, TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
selector); index);
} }
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_make_trait_reserve_priv (const char *selector, TALER_TESTING_make_trait_reserve_priv (unsigned int index,
const struct TALER_ReservePrivateKeyP *reserve_priv) const struct TALER_ReservePrivateKeyP *reserve_priv)
{ {
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .index = index,
.trait_name = TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY, .trait_name = TALER_TESTING_TRAIT_RESERVE_PRIVATE_KEY,
.ptr = (const void *) reserve_priv .ptr = (const void *) reserve_priv
}; };

View File

@ -0,0 +1,209 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_trait_string.c
* @brief offers strings traits. Mostly used to offer
* stringified JSONs.
* @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_CONTRACT_TERMS "contract-terms"
#define TALER_TESTING_TRAIT_TRANSFER_SUBJECT "transfer-subject"
#define TALER_TESTING_TRAIT_AMOUNT "amount"
/**
* Obtain contract terms from @a cmd.
*
* @param cmd command to extract trait from
* @param index always (?) zero, as one command sticks
* to one bank account
* @param contract_terms[out] 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 char **contract_terms)
{
return cmd->traits (cmd->cls,
(void **) contract_terms,
TALER_TESTING_TRAIT_CONTRACT_TERMS,
index);
}
/**
* @param index always (?) zero, as one command sticks
* to one bank account
* @param contract_terms contract terms to offer
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_contract_terms
(unsigned int index,
const char *contract_terms)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_CONTRACT_TERMS,
.ptr = (const void *) contract_terms
};
return ret;
}
/**
* Obtain wire details from @a cmd.
*
* @param cmd command to extract trait from
* @param index always (?) zero, as one command sticks
* to one bank account
* @param wire_details[out] 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 char **wire_details)
{
return cmd->traits (cmd->cls,
(void **) wire_details,
TALER_TESTING_TRAIT_WIRE_DETAILS,
index);
}
/**
* Offer wire details in a trait.
*
* @param index always (?) zero, as one command sticks
* to one bank account
* @param wire_details wire details to offer
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_wire_details
(unsigned int index,
const char *wire_details)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS,
.ptr = (const void *) wire_details
};
return ret;
}
/**
* Obtain a transfer subject from @a cmd.
*
* @param cmd command to extract trait from
* @param index always (?) zero, as one command sticks
* to one bank transfer
* @param transfer_subject[out] where to write the wire details.
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_transfer_subject
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
char **transfer_subject)
{
return cmd->traits (cmd->cls,
(void **) transfer_subject,
TALER_TESTING_TRAIT_TRANSFER_SUBJECT,
index);
}
/**
* Offer wire details in a trait.
*
* @param index always (?) zero, as one command sticks
* to one bank account
* @param wire_details wire details to offer
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_transfer_subject
(unsigned int index,
char *transfer_subject)
{
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_TRANSFER_SUBJECT,
.ptr = (const void *) transfer_subject
};
return ret;
}
/**
* Obtain an amount from @a cmd.
*
* @param cmd command to extract trait from
* @param index which amount is to be picked, in case
* multiple are offered.
* @param amount[out] where to write the wire details.
* @return #GNUNET_OK on success
*/
int
TALER_TESTING_get_trait_amount
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
const char **amount)
{
return cmd->traits (cmd->cls,
(void **) amount,
TALER_TESTING_TRAIT_AMOUNT,
index);
}
/**
* Offer amount in a trait.
*
* @param index which amount is to be picked, in case
* multiple are offered.
* @param amount the amount to offer
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_amount
(unsigned int index,
const char *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_string.c */

View File

@ -0,0 +1,74 @@
/*
This file is part of TALER
Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3, or (at your
option) any later version.
TALER is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public
License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file exchange-lib/testing_api_trait_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 wtid[out] 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,
struct TALER_WireTransferIdentifierRawP **wtid)
{
return cmd->traits (cmd->cls,
(void **) wtid,
TALER_TESTING_TRAIT_WTID,
index);
}
/**
* @param index associate the object with this index
* @param wtid which object should be returned
*
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_wtid
(unsigned int index,
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 */

View File

@ -2,16 +2,18 @@
This file is part of TALER This file is part of TALER
Copyright (C) 2018 Taler Systems SA Copyright (C) 2018 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify
terms of the GNU General Public License as published by the Free Software it under the terms of the GNU General Public License as
Foundation; either version 3, or (at your option) any later version. published by the Free Software Foundation; either version 3, or
(at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY TALER is distributed in the hope that it will be useful, but
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR WITHOUT ANY WARRANTY; without even the implied warranty of
A PARTICULAR PURPOSE. See the GNU General Public License for more details. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public
TALER; see the file COPYING. If not, see License along with TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/> <http://www.gnu.org/licenses/>
*/ */
/** /**
@ -28,11 +30,15 @@
#include "taler_testing_lib.h" #include "taler_testing_lib.h"
/**
* End a trait array. Usually, commands offer several traits,
* and put them in arrays.
*/
struct TALER_TESTING_Trait struct TALER_TESTING_Trait
TALER_TESTING_trait_end () TALER_TESTING_trait_end ()
{ {
struct TALER_TESTING_Trait end = { struct TALER_TESTING_Trait end = {
.selector = NULL, .index = 0,
.trait_name = NULL, .trait_name = NULL,
.ptr = NULL .ptr = NULL
}; };
@ -40,31 +46,35 @@ TALER_TESTING_trait_end ()
return end; return end;
} }
/**
* Pick the chosen trait from the traits array.
*
* @param traits the traits array
* @param ret where to store the result
* @param selector which particular object in the trait should be
* returned
*
* @return GNUNET_OK if no error occurred, GNUNET_SYSERR otherwise
*/
int int
TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits, TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
void **ret, void **ret,
const char *trait, const char *trait,
const char *selector) unsigned int index)
{ {
for (unsigned int i=0; for (unsigned int i=0; NULL != traits[i].trait_name; i++)
NULL != traits[i].trait_name;
i++)
{ {
if ( (0 == strcmp (trait, if ( (0 == strcmp (trait, traits[i].trait_name)) &&
traits[i].trait_name)) && (index == traits[i].index) )
( (NULL == selector) ||
(0 == strcasecmp (selector,
traits[i].selector) ) ) )
{ {
*ret = (void *) traits[i].ptr; *ret = (void *) traits[i].ptr;
return GNUNET_OK; return GNUNET_OK;
} }
} }
/* FIXME: log */ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Trait %s/%u not found.\n",
trait, index);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
/* end of testing_api_traits.c */ /* end of testing_api_traits.c */

View File

@ -1124,6 +1124,9 @@ exchange_keys_revoke_by_dki (void *cls,
rc->ok = GNUNET_SYSERR; rc->ok = GNUNET_SYSERR;
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Successfully revoking denom '%s..'\n",
TALER_B2S (rc->hc));
return GNUNET_NO; return GNUNET_NO;
} }

View File

@ -1682,6 +1682,10 @@ TEH_KS_denomination_key_lookup (const struct TEH_KS_StateHandle *key_state,
GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key, GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
&hc); &hc);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Looking for denom: '%s..'\n",
TALER_B2S (&hc));
return TEH_KS_denomination_key_lookup_by_hash (key_state, return TEH_KS_denomination_key_lookup_by_hash (key_state,
&hc, &hc,
use); use);

File diff suppressed because it is too large Load Diff